Openstack liberty 云主机迁移源码分析之在线迁移1

来源:互联网 发布:java安装教程win10 编辑:程序博客网 时间:2024/05/22 02:16

这是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记录,然后启动一个线程来执行热迁移操作,所以整个迁移操作都是在一个新的线程内完成的;详细的迁移过程,在一篇博文中分析,敬请期待!

0 0
原创粉丝点击