Add new configuration option to turn auto converge on/off
Since QEMU 1.6 and Libvirt 1.2.3 it is possible to use auto converge during live migrations. This option helps to live migrate instances with memory-intensive workload by throttling down CPU on guest machine. Partially-implements: blueprint auto-live-migration-completion Change-Id: I967bad47b67586ea2838e219eed1c6dce91ce153
This commit is contained in:
parent
3d83c462bc
commit
0c0f60031a
@ -171,6 +171,24 @@ to ensure the live-migration operation will complete.
|
||||
When using post-copy mode, if the source and destination hosts loose network
|
||||
connectivity, the VM being live-migrated will need to be rebooted. For more
|
||||
details, please see the Administration guide.
|
||||
|
||||
Related options:
|
||||
|
||||
* live_migration_permit_auto_converge
|
||||
"""),
|
||||
cfg.BoolOpt('live_migration_permit_auto_converge',
|
||||
default=False,
|
||||
help="""
|
||||
This option allows nova to start live migration with auto converge on.
|
||||
Auto converge throttles down CPU if a progress of on-going live migration
|
||||
is slow. Auto converge will only be used if this flag is set to True and
|
||||
post copy is not permitted or post copy is unavailable due to the version
|
||||
of libvirt and QEMU in use. Auto converge requires libvirt>=1.2.3 and
|
||||
QEMU>=1.6.0.
|
||||
|
||||
Related options:
|
||||
|
||||
* live_migration_permit_post_copy
|
||||
"""),
|
||||
cfg.StrOpt('snapshot_image_format',
|
||||
choices=('raw', 'qcow2', 'vmdk', 'vdi'),
|
||||
|
@ -94,6 +94,7 @@ VIR_MIGRATE_TUNNELLED = 4
|
||||
VIR_MIGRATE_PERSIST_DEST = 8
|
||||
VIR_MIGRATE_UNDEFINE_SOURCE = 16
|
||||
VIR_MIGRATE_NON_SHARED_INC = 128
|
||||
VIR_MIGRATE_AUTO_CONVERGE = 8192
|
||||
VIR_MIGRATE_POSTCOPY = 32768
|
||||
|
||||
VIR_NODE_CPU_STATS_ALL_CPUS = -1
|
||||
|
@ -1206,9 +1206,120 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_POSTCOPY))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
|
||||
def test_live_migration_permit_auto_converge_true(self, host):
|
||||
self.flags(live_migration_permit_auto_converge=True, group='libvirt')
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_AUTO_CONVERGE),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_AUTO_CONVERGE))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
|
||||
def test_live_migration_permit_auto_converge_and_post_copy_true(self,
|
||||
host):
|
||||
self.flags(live_migration_permit_auto_converge=True, group='libvirt')
|
||||
self.flags(live_migration_permit_post_copy=True, group='libvirt')
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_POSTCOPY),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_POSTCOPY))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version')
|
||||
def test_live_migration_auto_converge_and_post_copy_true_old_libvirt(
|
||||
self, mock_host):
|
||||
self.flags(live_migration_permit_auto_converge=True, group='libvirt')
|
||||
self.flags(live_migration_permit_post_copy=True, group='libvirt')
|
||||
|
||||
def fake_has_min_version(lv_ver=None, hv_ver=None, hv_type=None):
|
||||
if (lv_ver == libvirt_driver.MIN_LIBVIRT_POSTCOPY_VERSION and
|
||||
hv_ver == libvirt_driver.MIN_QEMU_POSTCOPY_VERSION):
|
||||
return False
|
||||
return True
|
||||
mock_host.side_effect = fake_has_min_version
|
||||
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_AUTO_CONVERGE),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_AUTO_CONVERGE))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=False)
|
||||
def test_live_migration_permit_postcopy_true_old_libvirt(self, host):
|
||||
self.flags(live_migration_permit_post_copy=True, group='libvirt')
|
||||
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=False)
|
||||
def test_live_migration_permit_auto_converge_true_old_libvirt(self, host):
|
||||
self.flags(live_migration_permit_auto_converge=True, group='libvirt')
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
@ -1250,6 +1361,27 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC))
|
||||
|
||||
def test_live_migration_permit_autoconverge_false(self):
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC))
|
||||
|
||||
@mock.patch('nova.utils.get_image_from_system_metadata')
|
||||
@mock.patch.object(host.Host,
|
||||
'has_min_version', return_value=True)
|
||||
|
@ -272,6 +272,10 @@ MIN_LIBVIRT_PF_WITH_NO_VFS_CAP_VERSION = (1, 3, 0)
|
||||
MIN_LIBVIRT_KVM_PPC64_VERSION = (1, 2, 12)
|
||||
MIN_QEMU_PPC64_VERSION = (2, 1, 0)
|
||||
|
||||
# Auto converge support
|
||||
MIN_LIBVIRT_AUTO_CONVERGE_VERSION = (1, 2, 3)
|
||||
MIN_QEMU_AUTO_CONVERGE = (1, 6, 0)
|
||||
|
||||
# Names of the types that do not get compressed during migration
|
||||
NO_COMPRESSION_TYPES = ('qcow2',)
|
||||
|
||||
@ -611,6 +615,25 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
migration_flags &= ~libvirt.VIR_MIGRATE_POSTCOPY
|
||||
return migration_flags
|
||||
|
||||
def _handle_live_migration_auto_converge(self, migration_flags,
|
||||
config_name):
|
||||
if self._host.has_min_version(lv_ver=MIN_LIBVIRT_AUTO_CONVERGE_VERSION,
|
||||
hv_ver=MIN_QEMU_AUTO_CONVERGE):
|
||||
if (self._is_post_copy_available() and
|
||||
(migration_flags & libvirt.VIR_MIGRATE_POSTCOPY) != 0):
|
||||
migration_flags &= ~libvirt.VIR_MIGRATE_AUTO_CONVERGE
|
||||
LOG.info(_LI('The live_migration_permit_post_copy is set to '
|
||||
'True and post copy live migration is available '
|
||||
'so auto-converge will not be in use.'))
|
||||
elif not CONF.libvirt.live_migration_permit_auto_converge:
|
||||
migration_flags &= ~libvirt.VIR_MIGRATE_AUTO_CONVERGE
|
||||
else:
|
||||
migration_flags |= libvirt.VIR_MIGRATE_AUTO_CONVERGE
|
||||
elif CONF.libvirt.live_migration_permit_auto_converge:
|
||||
LOG.info(_LI('The live_migration_permit_auto_converge is set '
|
||||
'to True, but it is not supported.'))
|
||||
return migration_flags
|
||||
|
||||
def _parse_migration_flags(self):
|
||||
def str2sum(str_val):
|
||||
logical_sum = 0
|
||||
@ -647,6 +670,11 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
block_migration_flags = self._handle_live_migration_post_copy(
|
||||
block_migration_flags, block_config_name)
|
||||
|
||||
live_migration_flags = self._handle_live_migration_auto_converge(
|
||||
live_migration_flags, live_config_name)
|
||||
block_migration_flags = self._handle_live_migration_auto_converge(
|
||||
block_migration_flags, block_config_name)
|
||||
|
||||
self._live_migration_flags = live_migration_flags
|
||||
self._block_migration_flags = block_migration_flags
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- New configuration option live_migration_permit_auto_converge
|
||||
has been added to allow hypervisor to throttle down CPU of an
|
||||
instance during live migration in case of a slow progress due
|
||||
to high ratio of dirty pages. Requires libvirt>=1.2.3 and
|
||||
QEMU>=1.6.0.
|
Loading…
Reference in New Issue
Block a user