Introduction to QEMU-KVM Live Migration
Introduction to QEMU-KVM Live Migration.
本文只介绍Pre-copy memory migration,大部分内容转载自:qemu热迁移简介.
文中的代码解析基于QEMU 5.1.0。
1. Usage
The usage of QEMU&&KVM live migration
2. 基本原理
推荐读下NSDI‘05 Live Migration of Virtual Machines。
首先看看热迁移过程中qemu的哪些部分会包含进来。上图中间的灰色部分是虚拟机的内存,它对于qemu来说是黑盒,qemu不会做任何假设,而只是一股脑儿的发送到dst(destination host)。左边的区域是表示设备的状态,这部分是虚拟机可见的,qemu使用自己的协议来发送这部分。右边的是不会迁移的部分,但是还是需要dst和src(source host)保持一致,一般来说,src和dst的虚拟机使用相同的qemu command line能够保证这部分一致。
需要满足很多条件才能进行热迁:
- 使用共享存储,如NFS
- host的时间要一致
- 网络配置要一致,不能说src能访问某个网络,dst不能
- host CPU类型要一致,毕竟host导出指令集给guest
- 虚拟机的机器类型,QEMU版本,rom版本等
热迁移主要包括三个步骤:
- 将虚拟机所有RAM pages设置成dirty,主要函数:
ram_save_setup
- 持续迭代将虚拟机的dirty pages发送到dst,直到达到一定条件,比如dirty pages数量比较少, 主要函数:
ram_save_iterate
- 停止src上面的guest,把剩下的dirty pages发送到dst,之后发送设备状态,主要函数:
qemu_savevm_state_complete_precopy
其中步骤1和步骤2是上图中的灰色区域,步骤3是灰色和左边的区域。
之后就可以在dst上面继续运行qemu程序了。
3. Algorithm
- Setup
- Start guest on destination, connect, enable dirty page logging and more
- Transfer Memory
- Guest continues to run
- Bandwidth limitation (controlled by the user)
- First transfer the whole memory
- Iteratively transfer all dirty pages (pages that were written to by the guest).
- Stop the guest
- And sync VM image(s) (guest’s hard drives).
- Transfer State
- As fast as possible (no bandwidth limitation)
- All VM devices’ state and dirty pages yet to be transferred
- Continue the guest
- On destination upon success
- Broadcast “I’m over here” Ethernet packet to announce new location of NIC(s).
- On source upon failure (with one exception).
4. 发送端源码分析
在qemu的monitor输入migrate命令后,经过的一些函数:
1 | hmp_migrate |
1 | void migrate_fd_connect(MigrationState *s, Error *error_in) |
migrate_fd_connect
函数创建了一个迁移线程,线程函数为migration_thread
。
1 | migration_thread |
migration_thread
主要就是用来完成之前提到的热迁移的三个步骤。
首先来看第一个步骤,qemu_savevm_state_setup
标记所有RAM pages为dirty。
接着看第二个步骤,由while循环中的两个函数完成: qemu_savevm_state_pending
和qemu_savevm_state_iterate
。
第一个函数通过调用回调函数ram_save_pending
确定还要传输的字节数,比较简单。 第二个函数通过调用回调函数ram_save_iterate
用来把dirty pages传到dst上面。
ram_find_and_save_block
–>find_dirty_block
–>ram_save_host_page
–>migration_bitmap_clear_dirty
–>ram_save_target_page
–>ram_save_page
–>save_normal_page
->qemu_put_buffer_async
–>…->qemu_fflush
–>…->send
在while循环中反复调用ram_save_pending
和ram_save_iterate
不停向dst发送虚拟机脏页,直到达到一定的条件,然后进入第三个步骤。
第三个步骤就是调用migration_completion
,在这一步中会停止src虚拟机,然后把最后剩的一点脏页拷贝到dst去。
5. 接收端源码分析
接收端的qemu运行参数跟发送端的一样,但是多了一个参数-incoming tcp:0:6666
, qemu在解析到-incoming
后,就会等待src迁移过来,我们来看看这个流程。
main
–>qemu_init
–>qemu_start_incoming_migration
–>tcp_start_incoming_migration
–>socket_start_incoming_migration
–>socket_accept_incoming_migration
–>migration_channel_process_incoming
->migration_ioc_process_incoming
->migration_incoming_process
->process_incoming_migration_co
->qemu_loadvm_state
->qemu_loadvm_state_main
process_incoming_migration_co
函数用来完成数据接收,恢复虚拟机的运行。最重要的是qemu_loadvm_state
,用于接收数据,在dst重构虚拟机。
1 | int qemu_loadvm_state(QEMUFile *f) |
显然,qemu_loadvm_state_main
是构建虚拟机的主要函数。
1 | int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis) |
qemu_loadvm_state_main
分别处理各个section, src会把QEMU_VM_SECTION_START
等标志放到流中。1
2
3
4
5
6
7qemu_loadvm_section_start_full
find_se
vmstate_load
ram_load[load_state]
ram_load_precopy
qemu_get_buffer
...
ram_load
负责把接收到的数据拷贝到dst这端虚拟机的内存上。
6. MISC
1 | typedef struct SaveVMHandlers { |
1 | static SaveVMHandlers savevm_ram_handlers = { |
以这些callback函数为接口来研究Live Migration,也是学习源码的一个极佳途径,能掌握全局。
参考资料: