Chinaunix首页 | 论坛 | 博客
  • 博客访问: 104077
  • 博文数量: 25
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 251
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-29 14:18
个人简介

不以物喜,勿以己悲;乐观向上,持之以恒。

文章分类

全部博文(25)

文章存档

2015年(25)

我的朋友

分类: 云计算

2015-08-17 18:14:20


本文主要讲解通过libvirt命令virsh migrate做虚拟机在线迁移所涉及到的代码流程。
libvirt版本为1.1.1。

基本知识

1. peer to peer的在线迁移(Managed peer to peer migration):client只负责触发迁移,源host负责控制迁移流程。
    libvirt层的控制流图如下:
    

2. 虚拟机本地数据传输(hypervisor native tranport):虚拟机之间直接传输数据,可能需要开多个端口(hypervisor native tranport)
    其数据流图如下:
    

命令发起端

以增量迁移为例,迁移命令如下:
virsh migrate --live virtual01 --copy-storage-inc  qemu+tcp://192.168.136.96/system tcp://192.168.136.96  --verbose --persistent  --p2p

注:迁移前,需要保证源端和目的端虚拟机启动时需要的文件存在。
      virsh qemu-monitor-command instance-000045ec --hmp info version : 可以检查虚拟机instance-000045ec当前运行的版本


上述命令在libvirt代码中对应的处理函数为cmdMigrate(tools/virsh-domain.c)
> cmdMigrate: 
     |--> virThreadCreate(启动线程) --> doMigrate(线程的执行函数)
     |--> vshWatchJob(等待迁移结束,并获取迁移进度)
                   |--> virDomainGetJobInfo(获取进度)
                   |--> print_job_progress(打印进度)
                   |--> vshMigrationTimeout(超时suspend虚拟机)
                   |--> virDomainAbortJob(迁移结束:成功/失败)
     |--> virThreadJoin(结束线程)

> doMigrate:
     |--> virDomainMigrateToURI3(src/libvirt.c)
                  |--> virDomainMigratePeer2PeerParams
                              |--> virDomainMigratePeer2PeerFull
                                        |--> domain->conn->driver->domainMigratePerform3Params(注册为remoteDomainMigratePerform3Params:src/remote/remote_driver.c)
                                                 |--> call: REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS:305

从上述流程可以看到,最终virsh migrate命令触发了一个call函数(同步处理),这个需要和libvirtd服务通信,由libvirtd来处理该请求。

命令处理端 -- libvirtd线程

再来介绍libvirtd启动流程中与在线迁移相关的部分:
> main(daemon/libvirtd.c)
     |--> virNetServerNew(src/rpc/virnetserver.c)
               |--> virThreadPoolNew(src/util/virthreadpool.c):jobFunc函数指针被赋值为virNetServerHandleJob
                           |--> virThreadCreate:创建线程,执行函数为virThreadPoolWorker
    
> virThreadPoolWorker
     |--> virCondWait:等待job 
     ?--> virNetServerHandleJob:线程被唤醒后,调用jobFunc执行要做的操作

> virNetServerHandleJob(src/rpc/virnetserver.c)
     |--> virNetServerProcessMsg
                 |--> virNetServerProgramDispatch
                             |--> virNetServerProgramDispatchCall(virNetServerProgramDispatchCall):主要处理从client端发过来的请求
                                        |--> virNetServerProgramGetProc:根据client端virsh migrate最终发过来的请求,获得要处理的函数等内容(返回prog->procs[305]
                                        |--> dispatcher->func:执行函数根据client端发过来的请求而定(此处为命令virsh migrate)
                                        |--> virNetServerClientSendMessage:请求处理完毕,给client端发送信息

注:remoteProcs数组在文件daemon/remote_dispatch.h中定义,主要描述各个Method处理的函数与参数等。
如:REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS:305对应的函数为remoteDispatchDomainMigratePerform3ParamsHelper
       即,prog->procs[305] = remoteDispatchDomainMigratePerform3ParamsHelper

remoteProcs的赋值流程如下:
> libvirtd:main
     |--> virNetServerProgramNew(src/rpc/virnetserverprogram.c)
               |--> prog->procs = remoteProcs


到这里,可以看到virsh migrate命令的最终处理函数为remoteDispatchDomainMigratePerform3ParamsHelper!
> remoteDispatchDomainMigratePerform3ParamsHelper(daemon/remote_dispatch.h:编译后出现此文件,被daemon/remote.c引用)
      |--> remoteDispatchDomainMigratePerform3Params(daemon/remote.c)
                |--> virDomainMigratePerform3Params(src/libvirt.c)
                           |--> conn->driver->domainMigratePerform3Params(注册为qemuDomainMigratePerform3Params:src/qemu/qemu_driver.c)

> qemuDomainMigratePerform3Params(src/qemu/qemu_driver.c)
      |--> qemuMigrationPerform(src/qemu/qemu_migration.c)       <-- 分叉口

注:qemuMigrationPerform(src/qemu/qemu_migration.c)
1. 传入的参数包括p2p或者tunnelled,则进入qemuMigrationPerformJob
2. 传入的参数不包括p2p,也不包括tunnelled,则进入qemuMigrationPerformPhase


路线1:参数中包括p2p或者tunnelled(p2p迁移要走的代码路径)
> qemuMigrationPerformJob
     |--> qemuMigrationJobStart
     |--> doPeer2PeerMigrate因为传入的参数包括p2p,所以走进此函数
               |--> virConnectOpen,连接目的端虚拟机(处于paused状态)
               |--> doPeer2PeerMigrate3(v3协议)

> doPeer2PeerMigrate3(src/qemu/qemu_migration.c)
     |--> qemuMigrationBeginPhase:获取虚拟机xml信息,迁移状态为QEMU_MIGRATION_PHASE_BEGIN3
     |--> dconn->driver->domainMigratePrepare3Params,注册为qemuDomainMigratePrepare3Params,迁移状态为QEMU_MIGRATION_PHASE_PREPARE
     |--> doNativeMigrate --> qemuMigrationRun,调用之前迁移状态为QEMU_MIGRATION_PHASE_PERFORM3,成功则迁移状态为QEMU_MIGRATION_PHASE_PERFORM3_DONE
     |--> dconn->driver->domainMigrateFinish3Params,注册为qemuDomainMigrateFinish3Params,迁移状态为QEMU_MIGRATION_PHASE_FINISH3
     |--> qemuMigrationConfirmPhase,迁移状态为QEMU_MIGRATION_PHASE_CONFIRM3

以上可以看到,整个p2p迁移过程中,迁移状态图如下:
PHASE_BEGIN3 --> PHASE_PREPARE --> PHASE_PERFORM3 --> PHASE_FINISH3 --> PHASE_CONFIRM3
                                      |--> PHASE_PERFORM3_DONE(迁移成功)
                                      |--> PHASE_CONFIRM3_CANCELLED(迁移失败)

注:doPeer2PeerMigrate3(src/qemu/qemu_migration.c),共经历以下几个阶段:
1. Begin阶段,发起端调用函数qemuDomainDefFormatXML完成xml的生成时,解析运行态虚拟机xml使用了标记MIGRATABLE、SECURE、UPDATE_CPU;
2. Prepare阶段,目的端调用函数qemuMigrationPrepareDirect --> qemuMigrationPrepareAny
                         |--> qemuProcessStart,在目的端启动一个带-incoming参数的kvm虚拟机
                         |--> qemuMigrationStartNBDServer,启动NBD Server
3. Perform阶段,发起端调用函数qemuMigrationRun,用于虚拟机的内存、数据、状态的迁移,在结尾部分会专门讲解此函数
4. Finish阶段,目的端调用函数qemuMigrationFinish完成迁移后的处理工作:
                         |--> qemuMigrationStopNBDServer,停止NBD Server
                         |--> qemuProcessStartCPUs,恢复目的端虚拟机为running状态
5. Confirm阶段,发起端调用函数qemuProcessStop,停止源端虚拟机


路线2:如果参数中没有p2p,也没有tunnelled,则走下面这个逻辑
> qemuMigrationPerformPhase(src/qemu/qemu_migration.c)
     |--> qemuMigrationJobStartPhase,迁移状态QEMU_MIGRATION_PHASE_PERFORM3 --> qemuMigrationCleanup
     |--> doNativeMigrate --> qemuMigrationRun
     |--> qemuMigrationJobStartPhase,迁移状态QEMU_MIGRATION_PHASE_PERFORM3_DONE 
               ?--> qemuMigrationCleanup:异步处理job
                         |--> qemuDomainObjDiscardAsyncJob
以上可以看到迁移状态只有PHASE_PERFORM3,可以确定,迁移走入此路径之前,必然已经完成了PHASE_BEGIN3 和 PHASE_PREPARE,此处不作讲解。

下面再介绍下Perform阶段调用的迁移核心函数qemuMigrationRun
> qemuMigrationRun(src/qemu/qemu_migration.c)
     |--> qemuMigrationDriveMirror:通过driver-mirror方式同步源端和目的端的数据盘数据,有几个数据盘,就调几次此函数,底层使用了NBD实现(调用qmp_dirve_mirror命令)
     |--> qemuMonitorMigrateToFd:通过此命令同步内存数据和虚拟机状态(调用qmp_migrate命令)
     |--> qemuMigrationWaitForCompletion:等待内存数据和虚拟机状态迁移完成,然后退出migrate(调用qmp_migrate_cancel命令)
     |--> qemuMigrationCancelDriveMirror:数据盘数据迁移完成,然后退出dirve-mirror调用qmp_block_job_cancel命令)
  
drive_mirror依赖nbd,所以可以看到:
在Prepare阶段还调用了函数qemuMigrationStartNBDServer
> qemuMigrationStartNBDServer(src/qemu/qemu_migration.c)
     |--> qemuMonitorNBDServerStart:在目的端启动nbd server(调用qmp_nbd_server_start命令)
     |--> qemuMonitorNBDServerAdd:将目的端的disk通过nbd导出(调用qmp_nbd_server_add命令)
在Finish阶段还调用了函数qemuMigrationStopNBDServer
> qemuMigrationStopNBDServer(src/qemu/qemu_migration.c)
     |--> qemuMonitorNBDServerStop:在目的端停止nbd server(调用qmp_nbd_server_stop命令)

至此,可以看到,libvirt的在线迁移最终调用了至少四个qemu-kvm接口(NBD相关命令这里不做讲解)
1. qmp_drive_mirror:同步数据盘数据;
2. qmp_migrate:同步内存数据与虚拟机状态;
3. qmp_migrate_cancel:停止内存数据与虚拟机状态的迁移,一般完成时调用
4. qmp_block_job_cancel:停止drive-mirror数据盘同步job,一般完成时调用

后续会再介绍qemu-kvm中虚拟机迁移的实现。

参考:
 
 
阅读(4644) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~