openstack live migration相当复杂的流程,足以展现openstack compute project的复杂度,所以,从代码走读开始,先来一张代码走读的流程。more details to be continue. 没有rollback 部分,没地方画了。
图中没有从nova-api 的代码走读,直接就从live migration的source compute node处理live migration开始了。
从api request发起的话,基本流程
1. nova-api处理Resetful 请求,各种权限验证。
2. nova-api ===rpc:conductor:migrate_server===>> nova-conductor call
migrate_server method, 最终的调用的是conductor/tasks/live_migrate.py:class LiveMigrationTask:execute
execute处理过程:
_check_instance_is_running
_check_host_is_up(source host)
如果没有指定target host 则调用_find_destination 选取 target host. _find_destination, 其实就是通过nova-scheduler选取target host
得到target host就监测target host是否有足够的resource 用来migration instance。
_check_compatible_with_source_hypervisor #兼容性检查要求 hypervisor_type 必须一样, 且hypervisor version是兼容的
_call_livem_checks_on_host
-
def _call_livem_checks_on_host(self, destination):
-
self.migrate_data = self.compute_rpcapi.\
-
check_can_live_migrate_destination(self.context, self.instance,
-
destination, self.block_migration, self.disk_over_commit)
这个函数式需要destination host 也就是target host 做一些migration的监测。这个函数显然是通过message 发送给target host ,并有nova-compute 进程调用method. check_can_live_migrate_destination如命名用途就是监测live-migration 是否能够进行。
下面这段代码存在于compute/manager.py : 由代码可见,最终还是有virt driver 执行具体的check步骤,且需要主要的是,直接也用rpc Message通信的方式需要source host也进行监测。
c
ompute/manager.py :check_can_live_migrate_destination
-
def check_can_live_migrate_destination(self, ctxt, instance,
-
block_migration, disk_over_commit):
-
src_compute_info = self._get_compute_info(ctxt, instance.host)
-
dst_compute_info = self._get_compute_info(ctxt, CONF.host)
-
dest_check_data = self.driver.check_can_live_migrate_destination(ctxt,
-
instance, src_compute_info, dst_compute_info,
-
block_migration, disk_over_commit)
-
migrate_data = {}
-
try:
-
migrate_data = self.compute_rpcapi.\
-
check_can_live_migrate_source(ctxt, instance,
-
dest_check_data)
-
finally:
-
self.driver.check_can_live_migrate_destination_cleanup(ctxt,
-
dest_check_data)
-
if 'migrate_data' in dest_check_data:
-
migrate_data.update(dest_check_data['migrate_data'])
-
return migrate_data
kvm中的处理方法virt/libvirt/driver.py:check_can_live_migrate_
destination
-
def check_can_live_migrate_destination(self, context, instance,
-
src_compute_info, dst_compute_info,
-
block_migration=False,
-
disk_over_commit=False):
-
-
disk_available_mb = None
-
if block_migration:
-
disk_available_gb = dst_compute_info['disk_available_least']
-
disk_available_mb = \
-
(disk_available_gb * units.Ki) - CONF.reserved_host_disk_mb
-
-
# Compare CPU
-
source_cpu_info = src_compute_info['cpu_info']
-
self._compare_cpu(source_cpu_info)
-
-
# Create file on storage, to be checked on source host
-
filename = self._create_shared_storage_test_file()
-
-
return {"filename": filename,
-
"block_migration": block_migration,
-
"disk_over_commit": disk_over_commit,
-
"disk_available_mb": disk_available_mb}
source host compute/manager.py
-
def check_can_live_migrate_source(self, ctxt, instance, dest_check_data):
-
is_volume_backed = self.compute_api.is_volume_backed_instance(ctxt,
-
instance)
-
dest_check_data['is_volume_backed'] = is_volume_backed
-
return self.driver.check_can_live_migrate_source(ctxt, instance,
-
dest_check_data)
source host virt/libvirt/driver.py
-
def check_can_live_migrate_source(self, context, instance,
-
dest_check_data):
-
source = CONF.host
-
filename = dest_check_data["filename"]
-
block_migration = dest_check_data["block_migration"]
-
is_volume_backed = dest_check_data.get('is_volume_backed', False)
-
has_local_disks = bool(
-
jsonutils.loads(self.get_instance_disk_info(instance['name'])))
-
-
shared = self._check_shared_storage_test_file(filename)
-
-
if block_migration:
-
if shared:
-
reason = _("Block migration can not be used "
-
"with shared storage.")
-
raise exception.InvalidLocalStorage(reason=reason, path=source)
-
self._assert_dest_node_has_enough_disk(context, instance,
-
dest_check_data['disk_available_mb'],
-
dest_check_data['disk_over_commit'])
-
-
elif not shared and (not is_volume_backed or has_local_disks):
-
reason = _("Live migration can not be used "
-
"without shared storage.")
-
raise exception.InvalidSharedStorage(reason=reason, path=source)
-
dest_check_data.update({"is_shared_storage": shared})
-
-
# NOTE(mikal): include the instance directory name here because it
-
# doesn't yet exist on the destination but we want to force that
-
# same name to be used
-
instance_path = libvirt_utils.get_instance_path(instance,
-
relative=True)
-
dest_check_data['instance_relative_path] = instance_path
return dest_check_data
其实简言之,就是判断是否有足够的空间用于migration instance,并通过创建一个test文件判断source 和target host之间是否是共享存储。
如果是共享存储,那么live migration,就不要拷贝instance disk file,也就是不需要block migration的方式。
如果不是共享存储那么就必须采用 block migration的方式进行live migration。
最后一步就是发送 rpc message 给source host 通知开始live migrate instance. 然后就是下图的处理了。
阅读(3873) | 评论(1) | 转发(0) |