虚拟机快照技术是指,在虚拟机运行过程中将虚拟机的完整运行状态,包括内存、磁盘、 CPU、网络等,保存到持久化的外部设备中,从而当虚拟机发生故障时可以通过备份的数据恢复虚拟机的运行。快照里面内存的快照又是非常重要非常关键的一部分。
内存快照主要实现机制主要有三种:停机拷贝机制(stop-and-copy),预拷贝机制(pre-copy),后拷贝机制(post-copy)。
停机拷贝机制(stop-and-copy)
在进行虚拟机快照的时刻要先将虚拟机挂起,然后在保存完虚拟机的完整状态后再恢复虚拟机的运行。
这种方式简单,但使得整个快照过程的虚拟机停机时间完全取决于虚拟机的内存大小,而且该时间可以达到几十秒,严重影响虚拟机的性能。
主流kvm、xen、vmware等都是基于停机拷贝方式实现快照功能。
预拷贝机制(pre-copy)
通过多轮迭代的方式对内存页面进行保存。每一轮保存自上一轮以来变脏的内存页面,当需要保存的内 存页面数量收敛到可以在一个较短的停机时间内完成保存的时刻,虚拟机停机。
写密集时,收敛时间较长,多轮拷贝影响性能。“状态漂移”现象。
Vnsnap等基于预拷贝机制实现快照。
后拷贝机制(post-copy)
首先停机,将cpu、设备等状态信息以及少量内存页面保存,然后开机,并在发生缺页中断时将相应内存页面保存。
个人认为在分布式快照时优势比较明显。
研究了一下xen快照部分的代码,其实xen-4.1.2的内存快照实现函数是跟迁移共用的,迁移已经是采用预拷贝机制来实现内存的迁移,所以说内存快照部分的代码其实是实现了预拷贝快照的。只是有一个参数live进行控制,live为1那么就是预拷贝,live为0就是停机拷贝。
快照部分函数入口及调用关系如下:
注意,xen-4.4.1版本及以上使用xl命令,不再是之前版本的xm命令,也就是不再用xend,而是成了toolstack,所以上层入口有所变化,但是最底层的xc_domain_save()函数是不变的。
预拷贝过程中关键数据
预拷贝主流程:
页判定代码:
代码分析
页判定主要是判定该轮迭代要传送哪些页面。
last_iter=1表示最后一轮迭代,置1后下一轮就进行停机拷贝。
superpages=1表示全虚拟化,iter=1表示第一轮迭代,test_bit(n,xx)表示xx位图第n位的值,为1或0。
判定规则
(1)to_send为1且to_skip为0的页
(2)全虚拟化形式下第一轮迭代to_send为1的页面
(3)最后一轮迭代to_send为1的页面
(4)最后一轮迭代to_fix为1的页面
以上四种页面是本轮迭代需要传送的页面。
to_send、to_skip、to_fix置位时机
to_fix是每一轮迭代页判断,当该页还没有被映射时就置为1。
页判定规则原理
to_send在第i-1轮迭代结束时候获取,收集的是第i-1轮迭代过程中变脏的页面,即第i轮可能拷贝页面的全集。 to_skip是第i轮迭代开始时获取,收集的是第i-1轮迭代结束到第i轮迭代开始这一短暂时间间隔内再次变脏的页面。 当to_skip为1表示这很短时间内某页面又再次被修改,也就可以认为该页频繁访问,为避免该页被重复拷贝,可以暂缓拷贝。
第一轮迭代时候,to_send被初始化为全1,to_skip实际上是没有获取的,所以可以不必考虑to_skip。
最后一轮迭代时候,to_fix、to_skip都需要一并拷贝,以保证内存拷贝的完整。
后处理代码:
代码分析
后处理主要是判定是否进行最后一轮迭代,如果是最后一轮置标记并申请停机。
判定规则:
如果 迭代次数iter大于等于预设最大迭代次数max_iters
或者 本轮拷贝页面数与跳过页面数之和小于50
或者 整个迭代过程拷贝总页面数大于迭代因子倍的P2M表对应页面数量
则 进入停机拷贝。
设备状态的拷贝是在XendCheckpoint.py中的save()函数中实现的。