Add a new NumInstancesWeigher

Despite having a NumInstancesFilter, we miss a weigher that would classify hosts
based on their instance usage.

Change-Id: Id232c2caf29d3443c61c0329d573a34a7481fd57
Implements-Blueprint: bp/num-instances-weigher
This commit is contained in:
Sylvain Bauza 2023-06-15 16:48:12 -07:00
parent 308633f93a
commit ca3fbb4d15
5 changed files with 185 additions and 0 deletions

View File

@ -1081,6 +1081,21 @@ If you prefer to invert the behavior set the
:oslo.config:option:`filter_scheduler.hypervisor_version_weight_multiplier` option
to a negative number and the weighing has the opposite effect of the default.
``NumInstancesWeigher``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 28.0.0 (Bobcat)
This weigher compares hosts and orders them based on their number of instances
respectively. By default the weigher is doing nothing but you
can change its behaviour by modifiying the value of
:oslo.config:option:`filter_scheduler.num_instances_weight_multiplier`.
A positive value will favor hosts with a larger number of instances (packing
strategy) while a negative value will follow a spread strategy that will
favor hosts with the lesser number of instances.
Utilization-aware scheduling
----------------------------

View File

@ -505,6 +505,51 @@ Example:
Related options:
* ``[filter_scheduler] weight_classes``
"""),
cfg.FloatOpt("num_instances_weight_multiplier",
default=0.0,
help="""
Number of instances weight multiplier ratio.
The multiplier is used for weighting hosts based on the reported
number of instances they have.
Negative numbers indicate preferring hosts with fewer instances (i.e. choosing
to spread instances), while positive numbers mean preferring hosts with more
hosts (ie. choosing to pack).
The default is 0.0 which means that you have to choose a strategy if you want
to use it.
Possible values:
* An integer or float value, where the value corresponds to the multiplier
ratio for this weigher.
Example:
* Strongly prefer to pack instances to hosts.
.. code-block:: ini
[filter_scheduler]
num_instances_weight_multiplier=1000
* Softly prefer to spread instances between hosts.
.. code-block:: ini
[filter_scheduler]
num_instances_weight_multiplier=1.0
* Disable weigher influence
.. code-block:: ini
[filter_scheduler]
num_instances_weight_multiplier=0
Related options:
* ``[filter_scheduler] weight_classes``
"""),
cfg.FloatOpt("io_ops_weight_multiplier",

View File

@ -0,0 +1,41 @@
# 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.
"""
Num instances Weigher. Weigh hosts by their number of instances.
The default is to select hosts with less instances for a spreading strategy.
If you prefer to invert this behavior set the 'num_instances_weight_multiplier'
option to a positive number and the weighing has the opposite effect of the
default.
"""
import nova.conf
from nova.scheduler import utils
from nova.scheduler import weights
CONF = nova.conf.CONF
class NumInstancesWeigher(weights.BaseHostWeigher):
def weight_multiplier(self, host_state):
"""Override the weight multiplier."""
return utils.get_weight_multiplier(
host_state, 'num_instances_weight_multiplier',
CONF.filter_scheduler.num_instances_weight_multiplier)
def _weigh_object(self, host_state, weight_properties):
"""Higher weights win. We want to chooose hosts with fewer instances
as the default, hence the negative value of the multiplier.
"""
return host_state.num_instances

View File

@ -0,0 +1,71 @@
# 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.
"""
Tests For Scheduler hypervisor version weights.
"""
from nova.scheduler import weights
from nova.scheduler.weights import num_instances
from nova import test
from nova.tests.unit.scheduler import fakes
class NumInstancesWeigherTestCase(test.NoDBTestCase):
def setUp(self):
super().setUp()
self.weight_handler = weights.HostWeightHandler()
self.weighers = [num_instances.NumInstancesWeigher()]
def _get_weighed_host(self, hosts, weight_properties=None):
if weight_properties is None:
weight_properties = {}
return self.weight_handler.get_weighed_objects(self.weighers,
hosts, weight_properties)[0]
def _get_all_hosts(self):
host_values = [
('host1', 'node1', {'num_instances': 2}),
('host2', 'node2', {'num_instances': 5}),
('host3', 'node3', {'num_instances': 4}),
('host4', 'node4', {'num_instances': 10}),
]
return [fakes.FakeHostState(host, node, values)
for host, node, values in host_values]
def test_multiplier_default(self):
hostinfo_list = self._get_all_hosts()
weighed_host = self._get_weighed_host(hostinfo_list)
self.assertEqual(0.0, weighed_host.weight)
# Nothing changes, we just returns the first in the list
self.assertEqual('host1', weighed_host.obj.host)
def test_multiplier_positive(self):
self.flags(
num_instances_weight_multiplier=2.0,
group='filter_scheduler'
)
hostinfo_list = self._get_all_hosts()
weighed_host = self._get_weighed_host(hostinfo_list)
self.assertEqual(2.0, weighed_host.weight)
# Host4 wins because it has the most instances
self.assertEqual('host4', weighed_host.obj.host)
def test_multiplier_negative(self):
self.flags(
num_instances_weight_multiplier=-2.0,
group='filter_scheduler'
)
hostinfo_list = self._get_all_hosts()
weighed_host = self._get_weighed_host(hostinfo_list)
self.assertEqual(0.0, weighed_host.weight)
# Host1 wins because it has the less instances
self.assertEqual('host1', weighed_host.obj.host)

View File

@ -0,0 +1,13 @@
---
features:
- |
A new `num_instances_weigher` weigher has been added. This weigher will
compare the number of instances between each node and order the list of
filtered results by its number, By default, this weigher is enabled but with
a default of 0.0 which doesn't change the current behavior.
In order to use it, please change the value of
``[filter_scheduler]/num_instances_weight_multiplier`` config option where
a positive value will favor the host with the higher number of instances
(ie. packing strategy) vs. a negative value that will spread instances
between hosts. As a side note, this weigher will count *all* of the existing
instances on the host, even the stopped or shelved ones.