Create Nova Scheduler IO Ops Weighter
Add a new nova scheduler weighter, sort the filter hosts according to host io ops number, aims to booting instances on light workload hosts. DocImpact: Adds io_ops_weight_multiplier to [DEFAULT] group of nova.conf and an new default schedule weigher. Change-Id: Ib3c9184f10b2ebe6b1230365a51b5542dffd447c Implements: blueprint io-ops-weight
This commit is contained in:
parent
ad84585d75
commit
fb559a34f9
|
@ -364,6 +364,11 @@ The Filter Scheduler weighs hosts based on the config option
|
|||
|
||||
metrics_weight_setting = name1=1.0, name2=-1.0
|
||||
|
||||
* |IoOpsWeigher| The weigher can compute the weight based on the compute node
|
||||
host's workload. The default is to preferably choose light workload compute
|
||||
hosts. If the multiplier is positive, the weigher prefer choosing heavy
|
||||
workload compute hosts, the weighing has the opposite effect of the default.
|
||||
|
||||
Filter Scheduler finds local list of acceptable hosts by repeated filtering and
|
||||
weighing. Each time it chooses a host, it virtually consumes resources on it,
|
||||
so subsequent selections can adjust accordingly. It is useful if the customer
|
||||
|
@ -415,3 +420,4 @@ in :mod:``nova.tests.scheduler``.
|
|||
.. |AggregateImagePropertiesIsolation| replace:: :class:`AggregateImagePropertiesIsolation <nova.scheduler.filters.aggregate_image_properties_isolation.AggregateImagePropertiesIsolation>`
|
||||
.. |MetricsFilter| replace:: :class:`MetricsFilter <nova.scheduler.filters.metrics_filter.MetricsFilter>`
|
||||
.. |MetricsWeigher| replace:: :class:`MetricsWeigher <nova.scheduler.weights.metrics.MetricsWeigher>`
|
||||
.. |IoOpsWeigher| replace:: :class:`IoOpsWeigher <nova.scheduler.weights.io_ops.IoOpsWeigher>`
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) 2014 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Io Ops Weigher. Weigh hosts by their io ops number.
|
||||
|
||||
The default is to preferably choose light workload compute hosts. If you prefer
|
||||
choosing heavy workload compute hosts, you can set 'io_ops_weight_multiplier'
|
||||
option to a positive number and the weighing has the opposite effect of the
|
||||
default.
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.scheduler import weights
|
||||
|
||||
io_ops_weight_opts = [
|
||||
cfg.FloatOpt('io_ops_weight_multiplier',
|
||||
default=-1.0,
|
||||
help='Multiplier used for weighing host io ops. Negative '
|
||||
'numbers mean a preference to choose light workload '
|
||||
'compute hosts.'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(io_ops_weight_opts)
|
||||
|
||||
|
||||
class IoOpsWeigher(weights.BaseHostWeigher):
|
||||
minval = 0
|
||||
|
||||
def weight_multiplier(self):
|
||||
"""Override the weight multiplier."""
|
||||
return CONF.io_ops_weight_multiplier
|
||||
|
||||
def _weigh_object(self, host_state, weight_properties):
|
||||
"""Higher weights win. We want to choose light workload host
|
||||
to be the default.
|
||||
"""
|
||||
return host_state.num_io_ops
|
|
@ -16,6 +16,8 @@
|
|||
Tests For Scheduler weights.
|
||||
"""
|
||||
|
||||
from oslo.serialization import jsonutils
|
||||
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova.openstack.common.fixture import mockpatch
|
||||
|
@ -36,9 +38,10 @@ class TestWeighedHost(test.NoDBTestCase):
|
|||
def test_all_weighers(self):
|
||||
classes = weights.all_weighers()
|
||||
class_names = [cls.__name__ for cls in classes]
|
||||
self.assertEqual(len(classes), 2)
|
||||
self.assertEqual(len(classes), 3)
|
||||
self.assertIn('RAMWeigher', class_names)
|
||||
self.assertIn('MetricsWeigher', class_names)
|
||||
self.assertIn('IoOpsWeigher', class_names)
|
||||
|
||||
|
||||
class RamWeigherTestCase(test.NoDBTestCase):
|
||||
|
@ -246,3 +249,91 @@ class MetricsWeigherTestCase(test.NoDBTestCase):
|
|||
self.flags(required=False, group='metrics')
|
||||
setting = ['foo=0.0001', 'zot=-1']
|
||||
self._do_test(setting, 1.0, 'host5')
|
||||
|
||||
|
||||
COMPUTE_NODES_IO_OPS = [
|
||||
# host1: num_io_ops=1
|
||||
dict(id=1, local_gb=1024, memory_mb=1024, vcpus=1,
|
||||
disk_available_least=None, free_ram_mb=512, vcpus_used=1,
|
||||
free_disk_gb=512, local_gb_used=0, updated_at=None,
|
||||
service=dict(host='host1', disabled=False),
|
||||
hypervisor_hostname='node1', host_ip='127.0.0.1',
|
||||
hypervisor_version=0, numa_topology=None,
|
||||
stats=jsonutils.dumps({'io_workload': '1'})),
|
||||
# host2: num_io_ops=2
|
||||
dict(id=2, local_gb=2048, memory_mb=2048, vcpus=2,
|
||||
disk_available_least=1024, free_ram_mb=1024, vcpus_used=2,
|
||||
free_disk_gb=1024, local_gb_used=0, updated_at=None,
|
||||
service=dict(host='host2', disabled=True),
|
||||
hypervisor_hostname='node2', host_ip='127.0.0.1',
|
||||
hypervisor_version=0, numa_topology=None,
|
||||
stats=jsonutils.dumps({'io_workload': '2'})),
|
||||
# host3: num_io_ops=0, so host3 should win in the case of default
|
||||
# io_ops_weight_multiplier configure.
|
||||
dict(id=3, local_gb=4096, memory_mb=4096, vcpus=4,
|
||||
disk_available_least=3333, free_ram_mb=3072, vcpus_used=1,
|
||||
free_disk_gb=3072, local_gb_used=0, updated_at=None,
|
||||
service=dict(host='host3', disabled=False),
|
||||
hypervisor_hostname='node3', host_ip='127.0.0.1',
|
||||
hypervisor_version=0, numa_topology=None,
|
||||
stats=jsonutils.dumps({'io_workload': '0'})),
|
||||
# host4: num_io_ops=4, so host4 should win in the case of positive
|
||||
# io_ops_weight_multiplier configure.
|
||||
dict(id=4, local_gb=8192, memory_mb=8192, vcpus=8,
|
||||
disk_available_least=8192, free_ram_mb=8192, vcpus_used=0,
|
||||
free_disk_gb=8888, local_gb_used=0, updated_at=None,
|
||||
service=dict(host='host4', disabled=False),
|
||||
hypervisor_hostname='node4', host_ip='127.0.0.1',
|
||||
hypervisor_version=0, numa_topology=None,
|
||||
stats=jsonutils.dumps({'io_workload': '4'})),
|
||||
# Broken entry
|
||||
dict(id=5, local_gb=1024, memory_mb=1024, vcpus=1, service=None),
|
||||
]
|
||||
|
||||
|
||||
class IoOpsWeigherTestCase(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(IoOpsWeigherTestCase, self).setUp()
|
||||
self.useFixture(mockpatch.Patch(
|
||||
'nova.db.compute_node_get_all',
|
||||
return_value=COMPUTE_NODES_IO_OPS))
|
||||
self.host_manager = fakes.FakeHostManager()
|
||||
self.weight_handler = weights.HostWeightHandler()
|
||||
self.weight_classes = self.weight_handler.get_matching_classes(
|
||||
['nova.scheduler.weights.io_ops.IoOpsWeigher'])
|
||||
|
||||
def _get_weighed_host(self, hosts, io_ops_weight_multiplier):
|
||||
if io_ops_weight_multiplier is not None:
|
||||
self.flags(io_ops_weight_multiplier=io_ops_weight_multiplier)
|
||||
return self.weight_handler.get_weighed_objects(self.weight_classes,
|
||||
hosts, {})[0]
|
||||
|
||||
def _get_all_hosts(self):
|
||||
ctxt = context.get_admin_context()
|
||||
return self.host_manager.get_all_host_states(ctxt)
|
||||
|
||||
def _do_test(self, io_ops_weight_multiplier, expected_weight,
|
||||
expected_host):
|
||||
hostinfo_list = self._get_all_hosts()
|
||||
weighed_host = self._get_weighed_host(hostinfo_list,
|
||||
io_ops_weight_multiplier)
|
||||
self.assertEqual(weighed_host.weight, expected_weight)
|
||||
if expected_host:
|
||||
self.assertEqual(weighed_host.obj.host, expected_host)
|
||||
|
||||
def test_io_ops_weight_multiplier_by_default(self):
|
||||
self._do_test(io_ops_weight_multiplier=None,
|
||||
expected_weight=0.0,
|
||||
expected_host='host3')
|
||||
|
||||
def test_io_ops_weight_multiplier_zero_value(self):
|
||||
# We do not know the host, all have same weight.
|
||||
self._do_test(io_ops_weight_multiplier=0.0,
|
||||
expected_weight=0.0,
|
||||
expected_host=None)
|
||||
|
||||
def test_io_ops_weight_multiplier_positive_value(self):
|
||||
self._do_test(io_ops_weight_multiplier=2.0,
|
||||
expected_weight=2.0,
|
||||
expected_host='host4')
|
||||
|
|
Loading…
Reference in New Issue