Openstack liberty 云主机迁移源码分析之在线迁移1
2016-07-29 10:19
651 查看
这是Openstack liberty云主机迁移源码分析的第二部分 - 在线迁移(热迁移/动态迁移)源码分析;和之前的静态迁移(离线迁移)源码分析一样,也用两篇博文详细阐述liberty中热迁移的过程,两篇博文的内容划分如下:
第一篇:分析
第二篇:分析
下面来看第一篇,在线迁移过程中
可以通过
从上面的日志以及
小结:
接上文,由
小结:
从消息队列拿到
小结:
第一篇:分析
nova-api,
nova-conductor的处理过程
第二篇:分析
nova-compute的处理过程
下面来看第一篇,在线迁移过程中
nova-api,
nova-conductor的处理过程:
发起在线迁移
用户可以通过nova live-migration发起在线迁移操作,如:
#nova --debug live-migration 57fe59d1-2566-42c1-8b17-b2a1e50c889e
可以通过
nova help live-migration帮助命令查看使用规则
--debug选项用来打印客户端调试日志:
POST http://10.240.xxx.xxx:8774/v2.1/25520b29dce346d38bc4b055c5ffbfcb/servers/57fe59d1-2566-42c1-8b17-b2a1e50c889e/action -H "User-Agent: python-novaclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-OpenStack-Nova-API-Version: 2.6" -H "X-Auth-Token: {SHA1}6b48595f60d527e2c55a182c65c32c6f9cc76e67" -d '{"os-migrateLive": {"disk_over_commit": false, "block_migration": false, "host": null}}'
从上面的日志以及
nova-api启动时建立的路由映射,我们很容易的知道消息的入口是:
nova/api/openstack/compute/migrate_server.py/MigrateServerController._migrate_live,下面一起来看看具体的处理过程:
nova-api
处理阶段
#这里省略装饰器定义(知道:装饰器在函数之前执行,并且各个装饰器的执行顺序与#声明顺序相反即可) def _migrate_live(self, req, id, body): """Permit admins to (live) migrate a server to a new host. 参数如下: req Request对象,包含请求的详细信息 id 待迁移的云主机的uuid 57fe59d1-2566-42c1-8b17-b2a1e50c889e body 请求体,包含本次请求的参数 {"os-migrateLive": {"disk_over_commit": false, "block_migration": false, "host": null}} """ #得到请求上下文 context = req.environ["nova.context"] """根据CONF.policy_file=`/etc/nova/policy.json`文件及 CONF.policy_dirs目录下策略文件中定义的策略认证该action在context上 下文中是否合法,适用的规则是: "os_compute_api:os-migrate-server:migrate_live": "rule:admin_api",如果没有定义相应的规则,则尝试执行默认规则 (CONF.policy_default_rule, 适用的规则 是:"default":"rule:admin_or_owner"),认证失败,抛异常 """ authorize(context, action='migrate_live') #根据请求体body获取配置参数 block_migration = body["os-migrateLive"]["block_migration"] disk_over_commit = body["os-migrateLive"]["disk_over_commit"] host = body["os-migrateLive"]["host"] #参数类型转换 block_migration = strutils.bool_from_string(block_migration, strict=True) disk_over_commit = strutils.bool_from_string(disk_over_commit, strict=True) """此处省略异常处理 常见的异常有:找不到合适的目标主机,目标主机上`compute`服务不可用, hypervisor不兼容,hypervisor版本太旧,CPU不兼容,云主机处于锁定状 态,云主机状态不对等,可以在`nova-api`的日志文件中看到具体的异常类型 及信息 先从nova.instance数据表获取id指定的实例信息(返回InstanceV2对 象),然后调用`nova/compute/api.py/API.live_migrate`执行后续的 操作,下文具体分析 """ instance = common.get_instance(self.compute_api, context, id) self.compute_api.live_migrate(context, instance, block_migration, disk_over_commit, host) -------------------------------------------------------------- #接上文:`nova/compute/api.py/API.live_migrate` #省略装饰器:判断云主机是否锁定,状态是否正常(Active或者Paused)等 def live_migrate(self, context, instance, block_migration, disk_over_commit, host_name): """Migrate a server lively to a new host. 输入参数如下: context 请求上下文 instance 实例对象 block_migration 块迁移标志,False disk_over_commit False host_name 迁移的目标主机,NULL """ #修改云主机任务状态:正在迁移 instance.task_state = task_states.MIGRATING instance.save(expected_task_state=[None]) #在`nova.instance_actions`数据表添加`live-migration`操作记录 self._record_action_start(context, instance, instance_actions.LIVE_MIGRATION) #将请求转交给 #`nova/conductor/api.py/ComputeTaskAPI.live_migrate_instance` #处理,下文分析 self.compute_task_api.live_migrate_instance(context, instance, host_name, block_migration=block_migration, disk_over_commit=disk_over_commit) -------------------------------------------------------------- #接上文:`nova/conductor/api.py/ComputeTaskAPI.live_migrate_instance` def live_migrate_instance(self, context, instance, host_name, block_migration, disk_over_commit): """输入参数如下: context 请求上下文 instance 实例对象 block_migration 块迁移标志,False disk_over_commit False host_name 迁移的目标主机,NULL """ #过滤属性,`nova-scheduler`选择目标主机的时候会用到 scheduler_hint = {'host': host_name} """参数: True,表示在线迁移; False 表示非resize操作 第一个None 表示不指定配置模板flavor 第二个None 表示不停机 发送同步`migrate_server`消息到消息队列,消费者`nova-conductor` 会处理该消息 """ self.conductor_compute_rpcapi.migrate_server( context, instance, scheduler_hint, True, False, None, block_migration, disk_over_commit, None)
小结:
nova-api的处理比较简单,先认证权限及转换输入参数,之后更新实例任务状态(
migrating)及
nova.instance_actions数据库,最后发起同步rpc请求
migrate_server,由
nova-conductor执行后续的处理
nova-conductor
处理阶段
接上文,由nova-conductor服务启动时建立的路由映射我们知道
migrate_server消息的,处理入口如下:
#`nova/conductor/manager.py/ComputeTaskManager.migrate_server #省略装饰器定义,添加了try {} except 异常处理,相关的异常信息会返回给`nova-api` def migrate_server(self, context, instance, scheduler_hint, live, rebuild, flavor, block_migration, disk_over_commit, reservations=None, clean_shutdown=True): """参数说明: scheduler_hint 过滤属性 {'host': host_name} live True 在线迁移 rebuild False 非resize flavor None block_migration False,块迁移 disk_over_commit False,块迁移时,计算磁盘空间时使用实际大小还是虚 拟大小(=True表示使用实际大小,=False表示使用虚拟大小) reservations None clean_shutdown False 在线迁移,不需要停机 """ #省略instance及flavor参数的异常处理 ...... #热迁移,下文具体分析 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, 'cold_migrate', instance_uuid): self._cold_migrate(context, instance, flavor, scheduler_hint['filter_properties'], reservations, clean_shutdown) else: raise NotImplementedError() --------------------------------------------------------------- #接上文:`nova/conductor/manager.py/ComputeTaskManager._live_migrate` def _live_migrate(self, context, instance, scheduler_hint, block_migration, disk_over_commit): #得到热迁移的目标主机 destination = scheduler_hint.get("host") """定义一个辅助函数: 1. 更新实例状态, 2. 更新`nova.instance_faults`记录异常堆栈 3. 发送通知给ceilometer """ def _set_vm_state(context, instance, ex, vm_state=None, task_state=None): request_spec = {'instance_properties': { 'uuid': instance.uuid, }, } scheduler_utils.set_vm_state_and_notify(context, instance.uuid, 'compute_task', 'migrate_server', dict(vm_state=vm_state, task_state=task_state, expected_task_state=task_states.MIGRATING,), ex, request_spec, self.db) #创建一个迁移对象Migration,包含:源端主机,目的主机,实例id,迁移类 #型,迁移状态,配置模板id migration = objects.Migration(context=context.elevated()) migration.dest_compute = destination migration.status = 'pre-migrating' migration.instance_uuid = instance.uuid migration.source_compute = instance.host migration.migration_type = 'live-migration' if instance.obj_attr_is_set('flavor'): migration.old_instance_type_id = instance.flavor.id migration.new_instance_type_id = instance.flavor.id else: migration.old_instance_type_id = instance.instance_type_id migration.new_instance_type_id = instance.instance_type_id #在`nova.migrations`数据表添加一条迁移记录,初始状态为:pre- #migrating migration.create() #生成迁移任务对象LiveMigrationTask task = self._build_live_migrate_task(context, instance, destination, block_migration, disk_over_commit, migration) """此处省略异常处理 常见的异常有:找不到合适的目标主机,目标主机上`compute`服务不可用, hypervisor不兼容,hypervisor版本太旧,CPU不兼容,云主机处于锁定状 态,云主机状态不对等 - 对于上述异常,会调用上文定义的_set_vm_state辅 助方法:还原实例状态,更新`nova.instance_faults`及发送错误类型通知 给ceilometer,同时更新`nova.migrations`迁移状态为`error` 对于其他的未指明异常,会调用上文定义的_set_vm_state辅助方法:设置实 例状态为Error,实例任务状态为(`migrating`),更新 `nova.instance_faults`及发送错误类型通知给ceilometer, 同时更新 `nova.migrations`迁移状态为`failed` 最后会将异常上抛给`nova-api` 启动迁移任务,TaskBase.execute -> LiveMigrationTask._execute, 下文具体分析 """ task.execute() ------------------------------------------------------------- #接上文:`nova/conductor/tasks/live_migrate.py/LiveMigrationTask._execute` def _execute(self): #判断实例的状态是否为运行或者暂停状态, #否则抛InstanceInvalidState异常 self._check_instance_is_active() #从数据表`nova.services`获取源端主机上`nova-compute`服务的信息, #出错,抛ComputeServiceUnavailable异常,如果`nova-compute`服务 #未启动,也抛ComputeServiceUnavailable异常 self._check_host_is_up(self.source) """如果没有指定目标主机,则循环通过`nova-scheduler`选择目标主机 选定一个主机后需要检查: 1.该主机上的hypervisor是否与源主机上的兼容,过程如下: 1.从`nova.compute_nodes`数据表获取源端和目的端节点信息,出错抛 ComputeHostNotFound异常 2.比较源端和目的端节点上hypervisor类型,如果不同则抛 InvalidHypervisorType异常 3.比较源端和目的端节点上hypervisor的版本,如果源端的比目的端的 新,则抛DestinationHypervisorTooOld异常 2.检测选择的目标主机是否支持在线迁移,过程如下: 1. 发送同步`check_can_live_migrate_destination`消息到消息 队列,消费者`nova-compute`会处理该消息 2. 从`nova.compute_nodes`数据表获取源端和目的端节点信息 3. 判断实例所使用的vcpu类型与目标主机的cpu类型是否兼容,如果不兼 容抛InvalidCPUInfo异常 4.发送同步`check_can_live_migrate_source`消息到消息队列,消 费者`nova-compute`会处理该消息,以便判断实例的磁盘配置是否支持 在线迁移,包括两种情况: 1. 块迁移(block_migration=True),满足下述所有条件: 1.不能有共享磁盘,不符合抛InvalidLocalStorage异常 2.目标主机上有足够的磁盘空间,不足抛 MigrationPreCheckError异常 3.不能有卷设备,不符合抛MigrationPreCheckError异常 2. 非块迁移(block_migration=False),满足下述条件之一: 1.从卷启动并且没有本地磁盘, 2.从镜像启动并且使用的是共享磁盘 不符合上述条件,抛InvalidSharedStorage异常 上述动作如果超时,则抛MigrationPreCheckError异常 选择目标主机时,会排除源主机以及前一次选择的主机,如果超过最大重试次 数(配置了migrate_max_retries > 0),还没有得到合适的目标主机,抛 MaxRetriesExceeded异常,如果所有的主机节点都试过了,还是没有找到合适 的目标主机,抛NoInvalidHost异常 """ if not self.destination: self.destination = self._find_destination() #设置迁移模板主机,更新`nova.migrations`数据表 self.migration.dest_compute = self.destination self.migration.save() else: """指定了目标主机,需要执行如下判断: 1.源端主机与目标主机不同,不符合抛UnableToMigrateToSelf异常 2.目标主机上的`nova-compute`存在且以启动,不符合抛 ComputeServiceUnavailable异常 3.从`nova.compute_nodes`数据表获取目标主机信息,并判断是否内存 足够完成该次迁移,不符合抛MigrationPreCheckError异常 4.与上述没有指定目标主机情况一样,判断目标主机上的hypervisor是否与 源主机上的兼容,具体分析如上文 5.与上述没有指定目标主机情况一样,判断目标主机是否支持在线迁移,具体分 析如上文 """ self._check_requested_destination() #发送异步`live_migration`到消息队列,消费者`nova-compute`会处理该 #消息 return self.compute_rpcapi.live_migration( self.context, host=self.source, instance=self.instance, dest=self.destination, block_migration=self.block_migration, migration=self.migration, migrate_data=self.migrate_data)
小结:
nova-conductor的处理过程略显复杂,与
nova-compute的交互比较多,主要是判断通过
nova-scheduler选择的候选目标主机是否满足执行在线迁移的条件,另外会在数据表
nova.migrations创建一条迁移记录;在迁移发生异常是也会更新
nova.instance_faults数据表,最后发起异步rpc请求,由
nova-compute完成后续的迁移操作
nova-compute
处理阶段
从消息队列拿到live_migration消息后,
nova-compute通过如下方法继续处理迁移请求:
#`nova/compute/manager.py/ComputeManager.live_migration` #省略装饰器定义 def live_migration(self, context, dest, instance, block_migration, migration, migrate_data): """Executing live migration. :param context: security context :param dest: destination host param instance: a nova.objects.instance.Instance object :param block_migration: if true, prepare for block migration :param migration: an nova.objects.Migration object :param migrate_data: implementation specific params """ # NOTE(danms): Remove these guards in v5.0 of the RPC API #更新`nova.migrations`记录,更新迁移状态为:queued if migration: migration.status = 'queued' migration.save() """线程函数,使用信号量临界保护,根据配置的 CONF.max_concurrent_live_migrations(默认1)参数使能节点上并发的 迁移操作,如果信号量饱和了,就会等待 """ def dispatch_live_migration(*args, **kwargs): with self._live_migration_semaphore: self._do_live_migration(*args, **kwargs) """ NOTE(danms): We spawn here to return the RPC worker thread back to the pool. Since what follows could take a really long time, we don't want to tie up RPC workers. """ #创建一个线程执行迁移操作,线程函数为上文定义的 #`dispatch_live_migration`,如果成功拿到了信号量,就调用 `_do_live_migration`继续执行迁移,否则等待 utils.spawn_n(dispatch_live_migration, context, dest, instance, block_migration, migration, migrate_data)
小结:
nova-compute收到
live_migration消息后,更新
nova.migrations记录,然后启动一个线程来执行热迁移操作,所以整个迁移操作都是在一个新的线程内完成的;详细的迁移过程,在一篇博文中分析,敬请期待!
相关文章推荐
- Openstack liberty 云主机迁移源码分析之在线迁移3
- 【OpenStack源码分析之八】openstack中虚拟机在线迁移
- Openstack liberty 云主机迁移源码分析之在线迁移2
- Openstack liberty 云主机迁移源码分析之在线迁移4
- OpenStack基于Libvirt的虚拟化平台调度实现----Nova虚拟机动态迁移源码分析
- Openstack liberty Glance上传镜像源码分析
- Openstack liberty 云主机迁移源码分析之静态迁移2
- OpenStack基于Libvirt的虚拟化平台调度实现----Nova虚拟机动态迁移源码分析
- Openstack liberty 云主机迁移源码分析之静态迁移1
- OpenStack基于Libvirt的虚拟化平台调度实现----Nova虚拟机动态迁移源码分析
- OpenStack基于Libvirt的虚拟化平台调度实现----Nova虚拟机动态迁移源码分析
- 【OpenStack】由浅入深(源码)分析nova的资源刷新机制
- openstack在线迁移资料
- PIC在线升级源码分析
- mongodb源码分析(二十三)mongos chunk的迁移
- OpenStack中实例的在线迁移
- OpenStack中实例的在线迁移
- openstack在线迁移配置live-migration
- OpenStack之Swift:容器服务器(Container Server)源码分析
- OpenNebula 虚拟机迁移源码分析