不做第二个别人,永远做第一个自己。
分类: 虚拟化
2014-04-10 11:09:38
1. snapshot 概念
当要做snapshot时,可以通过qemu的monitor terminal 或是QMP(Qemu Monitor Protocol)向QEMU发送命令,命令执行的结果是将原始的镜像(original image)变成备份镜像(bacup image),同时,生成一个snapshot(又称为活动镜像, active image),与原始镜像相比,所有新的变化都将记录在活动镜像里,另外,还将原始镜像(即备份镜像)以只读的权限挂载。
任何格式的原始镜像(也可以是raw格式)都可以做snapshot,但生成的snapshot必须是qcow2或QED格式的。
内置快照(Internal Snapshots):单个qcow2镜像文件存储了包括数据以及快照的状态信息,
内置快照又可以细分一下:
(1)内置磁盘快照(Internal disk snapshot),也可以成为内置磁盘快照
快照点的磁盘状态,数据和快照保存在单个qcow2文件中,虚拟机运行状态和关闭状态都可以创建.
(2)内置系统还原点(Internal system checkpoint),也可能成为内置内存快照
内存状态,处理器状态,设备状态和磁盘状态,可以为运行中的虚拟机创建,所有信息都存储在同一个qcow2文件中,只有在运行状态才能创建内置系统还原点.
外置快照(External Snapshots):当一个快照被创建时,创建时当前的状态保存在当前使用的磁盘文件中,即成为一个backing file
外置快照也可以分细分为:
(1)外置磁盘快照(External disk snapshot),也可以成为外置磁盘快照:
磁盘的快照被保存在一个文件中,创建时间点以后的数据被记录到一个新的qcow2或QED文件中,同样可以在运行和关闭状态创建.
(2)外置系统还原点(External system checkpoint),也可以成为外置内存快照:
内存状态,处理器状态,设备状态和磁盘状态将被保存到一个文件中,内存和设备的状态将被保存到另外一个新的文件qcow2或QED中.
2.生成snapshot的命令流
在了解了snapshot的基本概念后,来详细介绍下从触发snapshot的命令发出到snapshot完成过程中,QEMU具体经历的哪些步骤以及执行了哪些命令。
其实,在QEMU内部有一个GuestAgent Daemon(qemu-guest-agent),用来接收QEMU monitor发来的命令,并执行对应的处理函数,关于GuestAgent会在后续详细分析,这里不做具体介绍,只需要知道它是是一个处理QEMU Monitor发来的命令的模块就可以了。
(1)如果Guest处于非running状态,首先通过如下命令来使其运行
(qemu) cont
(2)为了Guest数据的一致性,通过如下命令来冻结Guest的filesystem
(agent) guest-fsfreeze-freeze
(3) 对每一个block device做snapshot,
(qemu) snapshot_blkdev
During snapshot creation the guest will momentarily be halted by QEMU. Pending I/Os will be flushed to disk
在这个过程中,Guest被QEMU置于halted的状态,之前pending的io将会被刷新到disk中,qemu将会自动将对原来设备(original file/devices)的io路径替换为新生成的snapshot。
该命令是个同步命令,当该命令执行完成完成后,QEMU将会恢复Guest。
(4) 在第(2)中冻结了Guest的filesystem,所以需要将其恢复
(agent) guest-fsfreeze-thaw
总结一下上述过程如下图所示:
3. 多设备的原子快照(atomic snapshot)
在qemu-1.0版本(新版本可能有变化)中snapshot_blkdev/blockdev-snapshot-sync每次只能作用于一个设备, 因此,如果Guest有多个设备的话,需要多次循环调用此命令才能完成多个设备的快照。这就可能在做某个设备snapshot时候失败了,在qemu退出 之前,它仅仅能回滚失败的设备的操作,但是此时,有些设备的snapshot已经完成了,所以就造成了当前Guest的状态与做快照之前的状态不一致性了
基于事务的块设备命令能够帮助解决这个问题。qemu-1.1中实现基于事务的QMP命令,它能够原子性的操作Guest的所有的设备,具体参见如下解释(对于原子性的QMP命令将在后续文章中详细分析):
QEMU 1.1 implements a "transaction" QMP command that operates on multiple block devices atomically. The transaction command receives one or more "transactionable" QMP commands and their arguments; the only transactionable command for now is blockdev-snapshot-sync. Execution of the commands is then split into two phases, a prepare phase and a commit/rollback phase. Should any command fail the prepare phase, the transaction immediately proceeds to roll back the completed prepare phases. If all commands are prepared successfully they are committed; the commit phase cannot fail, so that atomicity is achieved.