Add a disk space weight-based scheduler.

By default this is turned on and has equal weight to the
ram weigher.

DocImpact: Added the disk_weight_multiplier config option
Closes-Bug: 1513654
Change-Id: I29ce73122ad1860081b64b75646a297dfbb8d292
This commit is contained in:
andrewbogott 2015-12-21 22:04:40 -06:00 committed by John Garbutt
parent 440f2a834f
commit 13c1301f41
5 changed files with 169 additions and 0 deletions

View File

@ -379,6 +379,9 @@ The Filter Scheduler weighs hosts based on the config option
Sort with the largest weight winning. If the multiplier is negative, the
host with least RAM available will win (useful for stacking hosts, instead
of spreading).
* |DiskWeigher| Hosts are weighted and sorted by free disk space with the largest
weight winning. If the multiplier is negative, the host with less disk space available
will win (useful for stacking hosts, instead of spreading).
* |MetricsWeigher| This weigher can compute the weight based on the compute node
host's various metrics. The to-be weighed metrics and their weighing ratio
are specified in the configuration file as the followings::
@ -455,3 +458,4 @@ in :mod:`nova.tests.scheduler`.
.. |IoOpsWeigher| replace:: :class:`IoOpsWeigher <nova.scheduler.weights.io_ops.IoOpsWeigher>`
.. |ServerGroupSoftAffinityWeigher| replace:: :class:`ServerGroupSoftAffinityWeigher <nova.scheduler.weights.affinity.ServerGroupSoftAffinityWeigher>`
.. |ServerGroupSoftAntiAffinityWeigher| replace:: :class:`ServerGroupSoftAntiAffinityWeigher <nova.scheduler.weights.affinity.ServerGroupSoftAntiAffinityWeigher>`
.. |DiskWeigher| replace:: :class:`DiskWeigher <nova.scheduler.weights.disk.DiskWeigher>`

View File

@ -327,6 +327,11 @@ ram_weight_mult_opt = cfg.FloatOpt("ram_weight_multiplier",
help="Multiplier used for weighing ram. Negative numbers mean to "
"stack vs spread.")
disk_weight_mult_opt = cfg.FloatOpt("disk_weight_multiplier",
default=1.0,
help="Multiplier used for weighing free disk space. Negative "
"numbers mean to stack vs spread.")
io_ops_weight_mult_opt = cfg.FloatOpt("io_ops_weight_multiplier",
default=-1.0,
help="Multiplier used for weighing host io ops. Negative numbers mean "
@ -406,6 +411,7 @@ default_opts = [host_subset_size_opt,
agg_img_prop_iso_separator_opt,
max_instances_per_host_opt,
ram_weight_mult_opt,
disk_weight_mult_opt,
io_ops_weight_mult_opt,
scheduler_max_att_opt,
soft_affinity_weight_opt,

View File

@ -0,0 +1,38 @@
# Copyright (c) 2015 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.
"""
Disk Weigher. Weigh hosts by their disk usage.
The default is to spread instances across all hosts evenly. If you prefer
stacking, you can set the 'disk_weight_multiplier' option to a negative
number and the weighing has the opposite effect of the default.
"""
import nova.conf
from nova.scheduler import weights
CONF = nova.conf.CONF
class DiskWeigher(weights.BaseHostWeigher):
minval = 0
def weight_multiplier(self):
"""Override the weight multiplier."""
return CONF.disk_weight_multiplier
def _weigh_object(self, host_state, weight_properties):
"""Higher weights win. We want spreading to be the default."""
return host_state.free_disk_mb

View File

@ -0,0 +1,111 @@
# Copyright 2011-2016 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.
"""
Tests For Scheduler disk weights.
"""
from nova.scheduler import weights
from nova.scheduler.weights import disk
from nova import test
from nova.tests.unit.scheduler import fakes
class DiskWeigherTestCase(test.NoDBTestCase):
def setUp(self):
super(DiskWeigherTestCase, self).setUp()
self.weight_handler = weights.HostWeightHandler()
self.weighers = [disk.DiskWeigher()]
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', {'free_disk_mb': 5120}),
('host2', 'node2', {'free_disk_mb': 10240}),
('host3', 'node3', {'free_disk_mb': 30720}),
('host4', 'node4', {'free_disk_mb': 81920})
]
return [fakes.FakeHostState(host, node, values)
for host, node, values in host_values]
def test_default_of_spreading_first(self):
hostinfo_list = self._get_all_hosts()
# host1: free_disk_mb=5120
# host2: free_disk_mb=10240
# host3: free_disk_mb=30720
# host4: free_disk_mb=81920
# so, host4 should win:
weighed_host = self._get_weighed_host(hostinfo_list)
self.assertEqual(1.0, weighed_host.weight)
self.assertEqual('host4', weighed_host.obj.host)
def test_disk_filter_multiplier1(self):
self.flags(disk_weight_multiplier=0.0)
hostinfo_list = self._get_all_hosts()
# host1: free_disk_mb=5120
# host2: free_disk_mb=10240
# host3: free_disk_mb=30720
# host4: free_disk_mb=81920
# We do not know the host, all have same weight.
weighed_host = self._get_weighed_host(hostinfo_list)
self.assertEqual(0.0, weighed_host.weight)
def test_disk_filter_multiplier2(self):
self.flags(disk_weight_multiplier=2.0)
hostinfo_list = self._get_all_hosts()
# host1: free_disk_mb=5120
# host2: free_disk_mb=10240
# host3: free_disk_mb=30720
# host4: free_disk_mb=81920
# so, host4 should win:
weighed_host = self._get_weighed_host(hostinfo_list)
self.assertEqual(1.0 * 2, weighed_host.weight)
self.assertEqual('host4', weighed_host.obj.host)
def test_disk_filter_negative(self):
self.flags(disk_weight_multiplier=1.0)
hostinfo_list = self._get_all_hosts()
host_attr = {'id': 100, 'disk_mb': 81920, 'free_disk_mb': -5120}
host_state = fakes.FakeHostState('negative', 'negative', host_attr)
hostinfo_list = list(hostinfo_list) + [host_state]
# host1: free_disk_mb=5120
# host2: free_disk_mb=10240
# host3: free_disk_mb=30720
# host4: free_disk_mb=81920
# negativehost: free_disk_mb=-5120
# so, host4 should win
weights = self.weight_handler.get_weighed_objects(self.weighers,
hostinfo_list, {})
weighed_host = weights[0]
self.assertEqual(1, weighed_host.weight)
self.assertEqual('host4', weighed_host.obj.host)
# and negativehost should lose
weighed_host = weights[-1]
self.assertEqual(0, weighed_host.weight)
self.assertEqual('negative', weighed_host.obj.host)

View File

@ -0,0 +1,10 @@
---
prelude: >
The disk_weight_multiplier option is now available.
features:
- A disk space scheduling filter is now available,
which prefers compute nodes with the most available
disk space. By default, free disk space is given equal
importance to available RAM. To increase the priority
of free disk space in scheduling, increase the
disk_weight_multiplier option.