18.3 SnowFlock的实现方法
SnowFlock实现虚拟机克隆被称为“虚拟机fork”,这就像标准的Unix系统调用fork一样,但有几个重要的差异。第一,系统调用fork是复制一个单一的进程,虚拟机fork重复整个虚拟机,包括所有的内存,所有的进程和虚拟设备,以及本地文件系统。第二,系统调用fork是产生在同一物理主机上运行的单个副本,虚拟机fork可以同时产生多个并行备份。最后,虚拟机可以被复制到不同的物理服务器,让你迅速提高云服务的需要。
以下是SnowFlock中的核心概念:
· 虚拟化:虚拟机封装了计算环境,使机器复制和云服务成为可能。
· 延迟传播:直到需要的时候才复制虚拟机的状态,虚拟机克隆在几秒钟内生成。
· 组播:诸多的虚拟机克隆有着类似的状态需求。通过多播,几十个虚拟机克隆可以尽快执行。
· 页故障:当一个克隆使用了无效的内存空间,这一故障将触发一个请求到父节点,直到所需的内存页可用了,才继续执行克隆操作。
· 写复制(COW):在虚拟机克隆生成前,父虚拟机先保留一个当前内存和磁盘页的副本,在保留虚拟机克隆所需的状态同时可以继续运行。
我们使用Xen虚拟化系统来实现的SnowFlock,所以弄清一些Xen的专用术语是非常有用的。在Xen环境中,VMM被称为虚拟机管理程序,虚拟机被称为域。在每台物理机(主机)说,是一个特权域,称为“域0(dom0),每个特权域能够完整地访问主机及其物理设备。如果虚拟机被用来控制额外的“访问者”或“用户”,则被称为“域U”(domU)。
广义而言,SnowFlock包括一套修改了的Xen虚拟机管理程序(使其在无效资源被访问时能够顺利恢复),一组运行在dom0上的支持进程和系统服务包括无效虚拟机状态的合作迁移,以及一些虚拟机克隆中OS修改,由六个主要组成部分。
· 虚拟机描述器:这个小对象是虚拟机克隆的抽象描述,描述了需要开始执行的虚拟机基本框架。它没有需要执行任何实际工作血肉。
· 组播分发系统(mcdist):这是父节点系统,能够同时向所有克隆有效地发布虚拟机的状态信息。
· 内存服务器进程:父节点服务器进程中维护了父节点状态的多个副本,并使其根据需求通过多播mcdist发布给所有克隆。
· Memtap进程:一个虚拟机克隆端的进程,与内存服务器通信请求那些克隆所需要但又缺失的内存页。
· 克隆提示器:运行在克隆内的guest内核,通过为VMM提供线索来按需减少虚拟机状态的迁移。尽管是可选的,却是高效的。
· 控制栈:运行在每个物理主机上得守护进程,协调其他组件以及管理SnowFlock的父节点和虚拟机克隆。
图18.1:SnowFlock 虚拟机复制架构
如图所示,图18.1描绘克隆一个虚拟机的过程,主要有四个主要步骤:(1)暂停父虚拟机并产生一个虚拟机描述器;(2)将虚拟机描述器分发到所有目标主机(3)克隆初始化;(4)按需加载状态。该图还描述了使用mcdist 进行组播分发的方法,并取通过访问启示避免相关问题 。
如果你有兴趣尝试SnowFlock,这里有两种方法。多伦多大学SnowFlock研究项目组提供了文文档和开放的源代码1, . 如果您愿意采用一个工业化的版本,可以从GridCentric公司2 获得一个免费的非商业许可证.由于SnowFlock包括hypervisor的修改和dom0的访问的,所以安装SnowFlock需要对主机的访问权限。出于这个原因,你需要使用自己的硬件,将不能使用如亚马逊的EC2云环境等商业云服务。
在接下来的几节中,我们将描述瞬时实现和高效克隆的协同工作。我们将所以地内容结合在一起,如图18.2所示 。
图18.2:SnowFlock的的软件组件
18.4 构建虚拟机描述器
SnowFlock的设计关键是决定推迟虚拟机的状态复制到一个延迟运行操作。换句话说,复制虚拟机的内存是后期绑定操作,从而为优化的许多机会。
第一步的设计决定是生成虚拟机状态的架构描述器。这是将用于创建克隆虚拟机的种子。它包含了创建一个虚拟机的最低必要条件,使其可以被调度。顾名思义,这一必要条件是由架构规范所需要的数据结构组成。在SnowFlock中,该架构是Intel x86处理器和Xen的结合。因此,架构的描述包含数据结构,如页表,虚拟寄存器,设备元数据,wallclock时间戳等.我们推荐有兴趣的读者可以参考[LCWB +11 ]架构描述器的内容来深入理解。
一个架构描述器有三个重要的属性:首先,它可以在短时间内创建200毫秒的情况并不少见。其次,它是小的,通常是小于原虚拟机的内存分配三个数量级(1 MB为1 GB的虚拟机)。第三,从一个描述符创建克隆虚拟机可以在一秒钟之内(通常为800毫秒)。
当然,主要的时间开销是从描述他们的记忆状态创建克隆虚拟机全部的时间。以下各节我们说明如何解决这个问题,如何利用优势,并提出优化的机会。
18.5父节点组件
一旦被克隆的虚拟机成为一个父节点, 就和所有其他父节点一样,它需要为子节点提供克隆服务。父节点是通过维护一套内存和磁盘状态,克隆的集会,为克隆虚拟机提供按需服务。
18.5.1 memserver进程
b当创建架构描述器的时候,虚拟机将在进程中停止。这保证了虚拟机的内存状态稳定;在暂停虚拟机并执行调度或取消调度前,内部OS驱动程序处于停顿状态,从克隆可以重新连接到外部网络。我们采取这种静止状态的优势来创建一个“内存服务器”即memserver。
内存服务器将提供克隆虚拟机所需的所有父节点内存数据。内存转移是以x86的内存页(4字节)为粒度单位的。最简单的形式是内存服务器等待来自克隆的内存页请求,在一个时间上为一个克隆提供一个内存页的转移。
然而,这些需要转移的内存在父虚拟机中需要继续使用并执行。如果我们允许父节点去修改这个内存,那将会以损坏的内存内容克隆虚拟机:内存供应将是从不同的克隆点完成的,使克隆容易混淆。以破解内核的词汇来说,这是一个堆栈信息跟踪的问题。
为了克服这个问题,采用经典的操作系统概念来救援:Copy-on-Write, 即CoW memory.。通过辅助的Xen hypervisor,我们可以移除父虚拟机的所有内存页写入权限。当父节点试图修改一个内存页,将触发硬件内存页错误。Xen通过页面的副本知道这种情况发生的原因。父虚拟机允许写入到原来的页面,并继续执行,而被告知使用原来的副本,这就是保持只读的内存服务器。在这种方式下,被克隆的内存状态仍然冻结,且不混淆,而父节点能够继续执行。CoW的开销是最小的:Linux使用了类似的机制,如创建一个新的进程。
18.5.2 Multicast与Mcdist
克隆通常存在被称为“命运的决定”的问题。 我们希望创建克隆是为了一个单一的目的:例如,相对于Y调整一个数据库的DNA中X链。此外,我们期望要创建一套克隆,使所有的兄弟姐妹做的一样,也许对数据库的不同部分对准相同的X链,或调整不同的链对准Y链,从而明确地表现为大量内存访问的时间局部性:他们将使用相同的代码和大部分常见的数据。
我们利用时间局部性,为SnowFlock量身定制了自己的组播分发系统—— mcdist。mcdist使用IP组播,同时为接收器集合分发相同的数据包。它利用网络硬件并行处理的优势减少了内存的服务器上的负载。因为所有克隆具有类似的内存访问模式,通过对所有克隆的第一个要求发送一个应答,每个克隆的要求被作为它的兄弟姐妹预处理。
不像其他的组播系统,mcdist并不一定是可靠的,没有以一个有序的方式提供数据包,也没有以原子方式提供所有拟接收的应答。组播是严格意义上的优化,并确保克隆明确请求内存页的需要。因此,该设计优雅简单:简单的服务器多播的响应,而因为客户端超时,当克隆没有收到一个请求的答复时重新请求。
SnowFlock的三个优化都体现在mcdist上:
· 一致性检测:当时间局部性发生时,多个无差别请求都非常密切的继承在同一页。mcdist服务器忽略所有除第一个以外的请求。
· 流量控制:接收器的获取率与请求相关。服务器的发送率取决于客户端接受率的加权平均。否则,接收器将会淹没在服务器发送过多的内存页中。
· 游戏结束:当服务器已经发送了大多数页面时,将回到单播响应。在这一时间点上的大多数请求是重试,从而通过网络的内存页轰炸所有克隆是不必要的。
18.5.3虚拟磁盘
SnowFlock的克隆,由于其短寿命和命运决定,很少使用的磁盘。SnowFlock 虚拟机的虚拟磁盘包括了二进制文件,库和配置文件的根分区。通过合适的文件系统如HDFS 或PVFS 是完成大量的数据处理。因此,当SnowFlock克隆决定从他们的根磁盘读取数据时,它们通常由内核的文件系统页面缓存来满足这样要求。
尽管如此,我们仍需提供克隆的虚拟磁盘访问,在一些罕见的实例中这种访问需求是需要的。我们在这里采用了最小阻力路径,依据内存复制的设计来实现虚拟磁盘访问。首先,在克隆的时间里磁盘的状态被冻结。父虚拟机保持以CoW的方式使用其磁盘:对存储备份的写操作被发送到单独的位置,在磁盘克隆时也是不可改变的。二,磁盘的状态将使用 mcdist组播到所有克隆,且具有相同的4 KB页的粒度,并根据时间局部性完成相同的期望。第三,严格复制克隆虚拟机的磁盘状态是短暂的:它存储在一个文件中,当克隆被摧毁后被删除。