OpenStack之虛機(jī)熱遷移的代碼詳細(xì)解析
話(huà)說(shuō)虛機(jī)遷移分為冷遷移以及熱遷移,所謂熱遷移用度娘的話(huà)說(shuō)即是:熱遷移(Live Migration,又叫動(dòng)態(tài)遷移、實(shí)時(shí)遷移),即虛機(jī)保存/恢復(fù)(Save/Restore):將整個(gè)虛擬機(jī)的運(yùn)行狀態(tài)完整保存下來(lái),同時(shí)可以快速的恢復(fù)到原有硬件平臺(tái)甚至是不同硬件平臺(tái)上。恢復(fù)以后,虛機(jī)仍舊平滑運(yùn)行,用戶(hù)不會(huì)察覺(jué)到任何差異。OpenStack的虛機(jī)遷移是基于Libvirt實(shí)現(xiàn)的,下面來(lái)看看Openstack虛機(jī)熱遷移的具體代碼實(shí)現(xiàn)。
首先,由API入口進(jìn)入到nova/api/openstack/compute/contrib/admin_actions.py
@wsgi.action('os-migrateLive')
def _migrate_live(self, req, id, body):
"""Permit admins to (live) migrate a server to a new host."""
context = req.environ["nova.context"]
authorize(context, 'migrateLive')
try:
block_migration = body["os-migrateLive"]["block_migration"]
disk_over_commit = body["os-migrateLive"]["disk_over_commit"]
host = body["os-migrateLive"]["host"]
except (TypeError, KeyError):
msg = _("host, block_migration and disk_over_commit must "
"be specified for live migration.")
raise exc.HTTPBadRequest(explanation=msg)
try:
block_migration = strutils.bool_from_string(block_migration,
strict=True)
disk_over_commit = strutils.bool_from_string(disk_over_commit,
strict=True)
except ValueError as err:
raise exc.HTTPBadRequest(explanation=str(err))
try:
instance = self.compute_api.get(context, id, want_objects=True)
self.compute_api.live_migrate(context, instance, block_migration,
disk_over_commit, host)
except (exception.ComputeServiceUnavailable,
exception.InvalidHypervisorType,
exception.UnableToMigrateToSelf,
exception.DestinationHypervisorTooOld,
exception.NoValidHost,
exception.InvalidLocalStorage,
exception.InvalidSharedStorage,
exception.MigrationPreCheckError) as ex:
raise exc.HTTPBadRequest(explanation=ex.format_message())
except exception.InstanceNotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message())
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'os-migrateLive')
except Exception:
if host is None:
msg = _("Live migration of instance %s to another host "
"failed") % id
else:
msg = _("Live migration of instance %(id)s to host %(host)s "
"failed") % {'id': id, 'host': host}
LOG.exception(msg)
# Return messages from scheduler
raise exc.HTTPBadRequest(explanation=msg)
return webob.Response(status_int=202)
這里第一行可以看到是與API文檔的第二行照應(yīng)的:
{
"os-migrateLive": {
"host": "0443e9a1254044d8b99f35eace132080",
"block_migration": false,
"disk_over_commit": false
}
}
好了,源碼中其實(shí)執(zhí)行遷移工作的就是第26、27行的一條語(yǔ)句:
self.compute_api.live_migrate(context, instance, block_migration,
disk_over_commit, host)
由這句進(jìn)入到nova/compute/api.py中,源碼如下:
@check_instance_cell
@check_instance_state(vm_state=[vm_states.ACTIVE])
def live_migrate(self, context, instance, block_migration,
disk_over_commit, host_name):
"""Migrate a server lively to a new host."""
LOG.debug(_("Going to try to live migrate instance to %s"),
host_name or "another host", instance=instance)
instance.task_state = task_states.MIGRATING
instance.save(expected_task_state=[None])
self.compute_task_api.live_migrate_instance(context, instance,
host_name, block_migration=block_migration,
disk_over_commit=disk_over_commit)
第2行是一個(gè)裝飾器,用于在進(jìn)入API方法之前,檢測(cè)虛擬機(jī)和/或任務(wù)的狀態(tài), 如果實(shí)例處于錯(cuò)誤的狀態(tài),將會(huì)引發(fā)異常;接下來(lái)實(shí)時(shí)遷移虛機(jī)到新的主機(jī),并將虛機(jī)狀態(tài)置于“migrating”,然后由12行進(jìn)入nova/conductor/api.py
def live_migrate_instance(self, context, instance, host_name,
block_migration, disk_over_commit):
scheduler_hint = {'host': host_name}
self._manager.migrate_server(
context, instance, scheduler_hint, True, False, None,
block_migration, disk_over_commit, None)
將主機(jī)名存入字典scheduler_hint中,然后調(diào)用nova/conductor/manager.py方法migrate_server,
def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
flavor, block_migration, disk_over_commit, reservations=None):
if instance and not isinstance(instance, instance_obj.Instance):
# NOTE(danms): Until v2 of the RPC API, we need to tolerate
# old-world instance objects here
attrs = ['metadata', 'system_metadata', 'info_cache',
'security_groups']
instance = instance_obj.Instance._from_db_object(
context, instance_obj.Instance(), instance,
expected_attrs=attrs)
if live and not rebuild and not flavor:
self._live_migrate(context, instance, scheduler_hint,
block_migration, disk_over_commit)
elif not live and not rebuild and flavor:
instance_uuid = instance['uuid']
with compute_utils.EventReporter(context, self.db,
'cold_migrate', instance_uuid):
self._cold_migrate(context, instance, flavor,
scheduler_hint['filter_properties'],
reservations)
else:
raise NotImplementedError()
由于在nova/conductor/api.py中傳過(guò)來(lái)的參數(shù)是
self._manager.migrate_server(
context, instance, scheduler_hint, True, False, None,
block_migration, disk_over_commit, None)
因此live是True,rebuild是Flase,flavor是None,執(zhí)行第12、13行代碼:
if live and not rebuild and not flavor:
self._live_migrate(context, instance, scheduler_hint,
block_migration, disk_over_commit)
_live_migrate代碼如下:
def _live_migrate(self, context, instance, scheduler_hint,
block_migration, disk_over_commit):
destination = scheduler_hint.get("host")
try:
live_migrate.execute(context, instance, destination,
block_migration, disk_over_commit)
except (exception.NoValidHost,
exception.ComputeServiceUnavailable,
exception.InvalidHypervisorType,
exception.InvalidCPUInfo,
exception.UnableToMigrateToSelf,
exception.DestinationHypervisorTooOld,
exception.InvalidLocalStorage,
exception.InvalidSharedStorage,
exception.HypervisorUnavailable,
exception.MigrationPreCheckError) as ex:
with excutils.save_and_reraise_exception():
#TODO(johngarbutt) - eventually need instance actions here
request_spec = {'instance_properties': {
'uuid': instance['uuid'], },
}
scheduler_utils.set_vm_state_and_notify(context,
'compute_task', 'migrate_server',
dict(vm_state=instance['vm_state'],
task_state=None,
expected_task_state=task_states.MIGRATING,),
ex, request_spec, self.db)
except Exception as ex:
LOG.error(_('Migration of instance %(instance_id)s to host'
' %(dest)s unexpectedly failed.'),
{'instance_id': instance['uuid'], 'dest': destination},
exc_info=True)
raise exception.MigrationError(reason=ex)
首先,第三行中將主機(jī)名賦給destination,然后執(zhí)行遷移,后面的都是異常的捕捉,執(zhí)行遷移的代碼分為兩部分,先看第一部分,在nova/conductor/tasks/live_migrate.py的184行左右:
def execute(context, instance, destination,
block_migration, disk_over_commit):
task = LiveMigrationTask(context, instance,
destination,
block_migration,
disk_over_commit)
#TODO(johngarbutt) create a superclass that contains a safe_execute call
return task.execute()
先創(chuàng)建包含安全執(zhí)行回調(diào)的超類(lèi),然后返回如下函數(shù)也即執(zhí)行遷移的第二部分代碼,在54行左右:
def execute(self):
self._check_instance_is_running()
self._check_host_is_up(self.source)
if not self.destination:
self.destination = self._find_destination()
else:
self._check_requested_destination()
#TODO(johngarbutt) need to move complexity out of compute manager
return self.compute_rpcapi.live_migration(self.context,
host=self.source,
instance=self.instance,
dest=self.destination,
block_migration=self.block_migration,
migrate_data=self.migrate_data)
#TODO(johngarbutt) disk_over_commit?
這里有三部分內(nèi)容:
如果目前主機(jī)不存在,則由調(diào)度算法選取一個(gè)目標(biāo)主機(jī),并且進(jìn)行相關(guān)的檢測(cè),確保能夠進(jìn)行實(shí)時(shí)遷移操作;
如果目標(biāo)主機(jī)存在,則直接進(jìn)行相關(guān)的檢測(cè)操作,確保能夠進(jìn)行實(shí)時(shí)遷移操作;
執(zhí)行遷移操作。
前兩部分不再贅述,直接看第三部分代碼,在nova/compute/rpcapi.py中:
def live_migration(self, ctxt, instance, dest, block_migration, host,
migrate_data=None):
# NOTE(russellb) Havana compat
version = self._get_compat_version('3.0', '2.0')
instance_p = jsonutils.to_primitive(instance)
cctxt = self.client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'live_migration', instance=instance_p,
dest=dest, block_migration=block_migration,
migrate_data=migrate_data)
熱遷移開(kāi)始執(zhí)行:
def live_migration(self, context, instance, dest,
post_method, recover_method, block_migration=False,
migrate_data=None):
"""Spawning live_migration operation for distributing high-load.
:param context: security context
:param instance:
nova.db.sqlalchemy.models.Instance object
instance object that is migrated.
:param dest: destination host
:param post_method:
post operation method.
expected nova.compute.manager.post_live_migration.
:param recover_method:
recovery method when any exception occurs.
expected nova.compute.manager.recover_live_migration.
:param block_migration: if true, do block migration.
:param migrate_data: implementation specific params
"""
greenthread.spawn(self._live_migration, context, instance, dest,
post_method, recover_method, block_migration,
migrate_data)
這個(gè)方法中建立一個(gè)綠色線(xiàn)程來(lái)運(yùn)行方法_live_migration,來(lái)執(zhí)行實(shí)時(shí)遷移; 主要是調(diào)用libvirt python接口方法virDomainMigrateToURI,來(lái)實(shí)現(xiàn)從當(dāng)前主機(jī)遷移domain對(duì)象到給定的目標(biāo)主機(jī);
spawn:建立一個(gè)綠色線(xiàn)程來(lái)運(yùn)行方法“func(*args, **kwargs)”,這里就是來(lái)運(yùn)行方法_live_migration;
_live_migration:執(zhí)行實(shí)時(shí)遷移; 主要是調(diào)用libvirt python接口方法virDomainMigrateToURI,來(lái)實(shí)現(xiàn)從當(dāng)前主機(jī)遷移domain對(duì)象到給定的目標(biāo)主機(jī);
接著在綠色線(xiàn)程中調(diào)用_live_migration方法:
def _live_migration(self, context, instance, dest, post_method,
recover_method, block_migration=False,
migrate_data=None):
"""Do live migration.
:param context: security context
:param instance:
nova.db.sqlalchemy.models.Instance object
instance object that is migrated.
:param dest: destination host
:param post_method:
post operation method.
expected nova.compute.manager.post_live_migration.
:param recover_method:
recovery method when any exception occurs.
expected nova.compute.manager.recover_live_migration.
:param block_migration: if true, do block migration.
:param migrate_data: implementation specific params
"""
# Do live migration.
try:
if block_migration:
flaglist = CONF.libvirt.block_migration_flag.split(',')
else:
flaglist = CONF.libvirt.live_migration_flag.split(',')
flagvals = [getattr(libvirt, x.strip()) for x in flaglist]
logical_sum = reduce(lambda x, y: x | y, flagvals)
dom = self._lookup_by_name(instance["name"])
dom.migrateToURI(CONF.libvirt.live_migration_uri % dest,
logical_sum,
None,
CONF.libvirt.live_migration_bandwidth)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_("Live Migration failure: %s"), e,
instance=instance)
recover_method(context, instance, dest, block_migration)
# Waiting for completion of live_migration.
timer = loopingcall.FixedIntervalLoopingCall(f=None)
if block_migration:
flaglist = CONF.libvirt.block_migration_flag.split(',')
這個(gè)獲取塊遷移標(biāo)志列表,block_migration_flag:這個(gè)參數(shù)定義了為塊遷移設(shè)置遷移標(biāo)志。
else:
flaglist = CONF.libvirt.live_migration_flag.split(',')
flagvals = [getattr(libvirt, x.strip()) for x in flaglist]
logical_sum = reduce(lambda x, y: x | y, flagvals)
這部分獲取實(shí)時(shí)遷移標(biāo)志列表,live_migration_flag這個(gè)參數(shù)定義了實(shí)時(shí)遷移的遷移標(biāo)志。
dom = self._lookup_by_name(instance["name"])
根據(jù)給定的實(shí)例名稱(chēng)檢索libvirt域?qū)ο蟆?/p>
timer = loopingcall.FixedIntervalLoopingCall(f=None)
獲取等待完成實(shí)時(shí)遷移的時(shí)間。
熱遷移代碼部分至此結(jié)束。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Openstack組件部署 — Overview和前期環(huán)境準(zhǔn)備
本篇文章主要介紹了詳解Openstack組件部署 — Overview和前期環(huán)境準(zhǔn)備,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03
Openstack各組件邏輯關(guān)系及運(yùn)行流程解析
這篇文章主要為大家介紹了Openstack各組件邏輯關(guān)系及運(yùn)行流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
OpenStack虛擬機(jī)快照和增量備份實(shí)現(xiàn)方法
快照針對(duì)要保存的數(shù)據(jù)分為內(nèi)存快照和磁盤(pán)快照,內(nèi)存快照就是保存當(dāng)前內(nèi)存的數(shù)據(jù),磁盤(pán)快照就是保存硬盤(pán)的數(shù)據(jù),這篇文章主要介紹了OpenStack虛擬機(jī)快照和增量備份實(shí)現(xiàn),需要的朋友可以參考下2022-04-04
cURL操作Openstack對(duì)象存儲(chǔ)的ReST API詳解
這篇文章主要介紹了cURL操作Openstack對(duì)象存儲(chǔ)的ReST API詳解的相關(guān)資料,需要的朋友可以參考下2016-11-11
OpenStack之虛機(jī)熱遷移的代碼詳細(xì)解析
本篇文章主要介紹了OpenStack之虛機(jī)熱遷移,有需要的朋友可以了解下。2016-11-11
OpenStack Ceilometer用MongoDB解決占用磁盤(pán)空間過(guò)大問(wèn)題
這篇文章主要介紹了OpenStack Ceilometer用MongoDB解決占用磁盤(pán)空間過(guò)大問(wèn)題的相關(guān)資料,Ceilometer使用MongoDB作為數(shù)據(jù)庫(kù),不斷進(jìn)行采樣,導(dǎo)致數(shù)據(jù)量膨脹,占用過(guò)多的磁盤(pán)空間,這里提供解決辦法,需要的朋友可以參考下2016-12-12
圖文講解OpenStack手動(dòng)分布式部署環(huán)境準(zhǔn)備(Queens版)
這篇文章主要介紹了圖文講解OpenStack手動(dòng)分布式部署環(huán)境準(zhǔn)備(Queens版),OpenStack用于部署公有云、私有云,并實(shí)現(xiàn)對(duì)云項(xiàng)目管理,需要的朋友可以參考下2023-03-03
OpenStack Keystone的基本概念詳細(xì)介紹
這篇文章主要介紹了OpenStack Keystone的基本概念詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2016-11-11

