|
摘要
我们已经实现了一个支持容错虚拟机的商用企业级系统,基于通过在另一个服务器上的备份虚拟机复制执行主虚拟机的方法。我们已经在VMware vSphere 4.0上实现了一个易于使用的完整的系统,这个系统运行在商用服务器上,并且通常会降低实际应用的性能少于10%.我们复制VM执行的方法和Bressoud描述的是相似的,但是我们做了很多重要的设计选择来极大的提高了性能。另外,一个在故障后能自动恢复冗余的易于使用的商用系统需要许多在复制的虚拟机上的额外组件。我们已经设计并实现了这些额外的组件,并且也遇到了一些实际的问题在支持虚拟机运行企业应用的时候。在这篇文章,我们会描述我们的基础设计,并讨论替代的选择和许多实现的细节,也提供了在micro-benchmarks和实际应用上的性能评估。
1. 介绍
一个常用的实现容错服务的方法是主/备份,即主服务上的运行在备份服务上复制运行。如果主服务故障了,备份服务能够接管客户端的请求,而没有任何中断或状态的丢失。复制服务的方法也称为状态机方法。思想是将服务器建模为确定性状态机,通过按照相同初始化状态启动和以相同的顺序接受相同的输入请求来保持同步。因为大多数的服务器或者服务都有一些不确定性的操作,必须通过额外的协作来保证主备之间的同步。
实现协作来保证物理服务器的完全确定性执行是困难的,特别是随着处理器频率增加和时钟同步变的困难。作为对比,运行在虚拟机监视器顶层的虚拟机是实现主/备份方法的极好的平台。VM可以被认为是良好定义的状态机,其操作是虚拟化(包括所有设备)的机器的操作。和物理服务器一样,VM也有一些不确定的操作(例如读取一个时钟时间或者中断传递),并且这些额外信息必须发送给备份机来保证主从同步。因为虚拟机监视器对于虚拟机执行有完全的控制权,包括输入数据的传递,所以虚拟机监视器能够捕获所有主虚拟机上涉及的非确定性操作的有效信息,然后在备份虚拟机上正确的重放这些操作。
基于虚拟机的备份系统可以备份单个VM,这允许在一些Vm不被备份的时候,还有部分Vm会被备份和容错。另外,基于的Vm的即使不需要修改硬件,这让系统能够驾驭新的微处理器来改进硬件性能。运行在物理服务器上的备份系统需要修改硬件,因此经常滞后于性能曲线。虚拟机对于应用的另一个优点是能够物理分离主机和备机:比如,备份的虚拟机可以运行在园区内分离的物理机上,这提供了比运行在同一建筑下的主备机更好的可靠性。
我们已经在VMware vSphere4.0平台上使用主/备份的方法实现了容错虚拟机,可以高效运行在完全虚拟化的x86平台的虚拟机上。因为Vmware vSphere实现了可以运行所有基于X86平台的操作系统和应用的x86虚拟机,所以我们能够提供对于所有x86的操作系统,应用的容错能力。基础的技术让我们能够记录主机的执行并确保备机相同的执行,这称之为确定性重放。Vmware vSphere的容错是基于确定性重放的,但是为了建立一个完整的容错系统增加了必要的额外的协议和功能。另外为了提供硬件容错,我们的系统能够通过在本地集群的任何可用服务器上开启一个新的虚拟机来自动的回复冗余。现在,确定性重放和VMware FT的版本仅支持单处理器的虚拟机。记录并重放多处理器的虚拟机的执行仍在开发中,一个很重要的性能问题是几乎每一个对于共享内存的访问都会是一个不确定性的操作。
Bressoud描述了对于HP PARISC平台的容错虚拟机的原型实现。这和我们的方法是相似的,但出于性能原因我们做出了一些根本改变并调查了一系列的可替代方案。另外,为了建立一个能够由顾客运行在企业应用上的高效可以用的完整系统,我们设计并实现了许多额外的系统组件,并且处理了一系列的实际问题。和讨论的大多数其他的实际系统相似,我们只尝试解决fail-stop故障,fail-stop故障是服务器故障可以在故障的服务器引起不正确的外部不可见行为之前被检测到。
这篇论文的其余部分安排如下。首先,我们描述了我们的基础设计并详细介绍我们的基础协议,基础协议确保主机故障后由备机接管的时候没有数据丢失。然后,我们详细描述为建立一个正确的,健壮的,完整功能的,自动的系统必然会遇到的问题。我们还会描述一些为实现容错虚拟机会遇到的一些设计选择,讨论对这些选择的权衡。接着,我们提供我们的实现在一些benchmarks和一些实际企业应用上的性能表现。最后,我们会介绍相关的工作和结论。

图 1 基本 FT 配置
2. 基本 FT 设计
图1展示了我们容错虚拟机系统的基础设置。给定一个我们想要用来提供容错的虚拟机(成为主机),我们会在不同的物理服务器上运行一个备机,备机通过和主机一样的执行来保持同步,不过会有一点延迟。我们称主机和备机是帧同步的。虚拟机的虚拟磁盘在共享存储上(比如光纤通道或者iSCSI磁盘阵列),因此主机和备机访问共享存储用于输入和输出。(我们将在4.1节讨论,主机和备机在不同的非共享的虚拟磁盘上的设计)。只有主机参与网络交互,所以所有通过网络的输入都发给了主机。类似的,所有其他的输入(比如键盘或者鼠标)也只发给了主机。
所有主机接收的输入会被传输给备机,通过称为日志通道的网络连接。对于服务器工作负载,主要的输入流量来自网络和磁盘。我们在2.1节的下面部分将要讨论的额外信息必要时也会被传输给备机,来确保备机以和主机相同的方式运行不确定性操作。所以最后备机总是和主机以相同的方式运行。然而,备机的输出总是会被虚拟机管理程序丢弃,所以只有主机会产生实际的返回给客户端的输出。如2.2节描述的,主机和备机必须遵从特定的协议,包括备机的显式确认,为了保证主机故障的时候没有数据丢失。
一个前面没有过多讨论的关键问题是快速判断哪个主机,备机故障的处理过程。我们的系统使用相关服务器和日志通道上流量监控程序的心跳包的关联。另外,我们必须确保只有一个主机或备机接管执行,即使在主机和备机失联导致脑裂的情况。
在下面的章节中,我们提供对于几个重要领域更多的细节。在2.1节,我们描述对于确定性重放技术的更多细节,确定性重放即使保证主机和备机通过日志通道发送信息来保持同步。在2.2节,我们描述我们容错协议的基础规则,容错协议保证主机故障的时候没有数据丢失。在2.3节,我们描述我们以正确方式来检测和响应故障的方法。
2.1 记录重放实现
如前所述,备份服务器(或备份虚拟机)可以被建模为确定性状态机的备份。如果两个确定性状态机以相同的初始状态启动并提供相同次序的完全相同的输入,则它们将经过相同的状态顺序并产生相同的输出。在最简单的情况,一个状态机是主,另一个是备。如果所有的输入都到达主,则输出可通过日志通道从主分发给备机。一个有用的物理计算机,作为状态机的时候,有广泛的输入范围,从键盘设备到来自客户端的网络输入。另外,不确定的事件比如虚拟中断,和不确定性操作像是从处理器读取时钟周期计数器,会影响状态机。这给实际的虚拟机管理程序在物理机上运行任何操作系统的能力带来了3个挑战:
(1) 正确的捕获所有输入和必要的不确定性来保证备机的确定性执行
(2) 正确的应用输入和不确定性给备机
(3) 以不降低性能的方式进行
Vmware确定性重放正是为VMware vSphere平台上的x86虚拟机提供了此功能。确定性重放允许虚拟的输入和所有与虚拟机执行相关联的可能的不确定性能够通过写到日志文件的日志项的流记录下来。通过读取日志文件的日志项,可以在稍后准确的回访虚拟机的执行。不确定性状态转换可能是由有不确定性结果(比如读取time-of-day的时钟)的虚拟机的显式操作导致,也可能由异步的事件(比如中断)导致。这两种会导致不确定状态是因为它们打断动态指令流的时候会影响虚拟机的执行。
对于不确定性操作,充足的信息必须被日记记录下来,来让重放的时候操作可以按照相同的状态改变和输出被重置。对于不确定性的事件比如时钟中断或者IO完成中断,还必须记录事件发生的确切指令。在重放期间,必须在指令流的同一时间点传递事件。VMware确定性重放实现了一个有效的事件记录和事件传递机制,该机制使用了多种技术,包括由amd和intel联合开发的硬件性能计数器。
Bressoud提到了将虚拟机的执行分为epochs(阶段?时期?),不确定性事件比如中断只在最后的epoch传递。epoch被用于批处理机制,因为在中断发生的时候分别传递每一个中断在对应的指令是代价很高的。然而,我们的事件传递机制是足够有效的,所以VMware确定性重放不需要使用epochs.每一个中断的发生都可以被记录并写到日志,并有效的传递给适当的指令,在重放的时候。
2.2 FT Protocol
对于VMware容错,我们使用确定性重放来产生必要的日志项纪录主机的执行,但是不是将日志项写入磁盘,而是通过日志通道将日志项发送给备机。备机实时回放日志项,因此备机可以和主机有相同的执行。但是,为了容错,我们必须通过在日志通道上的严格的容错协议。基础协议有下面这些要求:
输出要求: 如果备机在主机故障后接管,备机将以和主机已经发送发送给外部世界输出完全一致性的继续运行。 注意,在故障转移发生(备机在主机故障后接管)之后,备机可能以和主机继续执行的方式完全不同的方式启动执行,因为许多不确定性事件在执行期间发生。然而,只要备机满足输出要求,就不会有任何状态和数据在故障转移给备机的时候丢失,并且客户端不会看到服务端有中断和不一致性的现象。
输出要求可以通过延迟所有外部输出(通常是网络包)直到备机已经接受了所有信息(允许备机重放到至少输出操作的时刻)的时候。一个必要的条件是备机必须已经接收了所有的输出操作事先生成的日志项。这些日志项能够让备机执行到最后的日志项的时刻。然而,如果一个故障在主机执行输出操作的时候立刻发生。备机必须知道它必须一直重放到输出操作的时刻然后在那个时刻仅仅上线(停止重放并接管主机,像2.3节描述的那样)。如果备机在输出操作之前的最后的日志项的时刻上线,一些不确定性事件(比如传递给虚拟机的时钟中断)可能改变执行路径,在执行输出操作之前。
鉴于上面的约束,执行输出要求的最简单方式是对每一个输出操作创建一个特殊的日志项。然后,输出要求可以通过这些特殊的规则被执行:
输出规则:主机直到备机接收被确认了和产生输出相关联的日志项的时候,才发送输出给外部世界。 如果备机已经接收了所有的日志项,包括输出产生操作的日志项,那么备机将能够准确的重现在该输出点上的主机的状态,即使主机宕了,备机仍能够正确的达到和该输出一致的状态。相反,如果备机在没有接收到所有必要的日志项的时候就接管了主机,则备机的状态可能很快偏离到和主机输出不一致的状态。输出规则在某些方面和[11]提到的方法是类似的,其中外部同步IO可以被缓冲,只要在下一次外部通信前写入磁盘。
注意输出规则没有说任何要通知主机执行的事情。我们只需要延迟发送输出,但是虚拟机可以继续执行。因为操作系统通过异步中断来非阻塞的表示网络和磁盘输出的完成,所以虚拟机只需要继续执行,并且不一定会立即受到输出延迟的影响。相反,先前的工作[3,9]通常表明在完成输出之前主机必须完全停止,直到备机已经确认了所有来自主机的必要信息。

图 2 FT 协议
作为例子,我们在图2中展示了一个图表说明容错协议的要求。该图展示了主机和备机上事件的时间线。主机线到备机线的箭头表示日志项的传输,备机线到主机线的箭头表示确认。异步事件的信息,输入,和输出操作都必须被发送给备机,以日志项的方式,然后由备机确认。如图中说明的那样,对于外部世界的输出会被延迟到主机已经接收到来自备机的确认信息,在备机收到和输出操作相关联的日志项的时候会进行确认。如果输出规则得以遵守,备机将能够以和主机最后输出一致性的状态进行接管。
如[3,9]所表示的,我们不能保证所有的输出都只被生成一次在故障转移的情况下。在主机尝试发送输出的时候不适用两阶段提交事务的话,就没有办法让备机判断主机是在崩溃之前还是之后发送了最后的输出。幸运的是,网络基础设施(包括常用的tcp)被设计为能够处理丢包和重包。
注意,传给主机的数据包在主机故障的时候也可能丢失因而不能被传递给备机。然而,传入的数据包可能出于一系列和服务器故障不相关的原因被丢弃,所以网络基础设施,操作系统和应用都被写入(意思应该是都要适配这个情况? )来确保可以对丢失的包进行补偿。
2.3 检测和响应失败
如前面提到的那样,主机和备机必须在另一方故障的时候快速响应。如果备机故障,主机将会上线-指的是离开记录模式(因此停止在日志通道上发送日志项)并开始正常运行。如果主机故障,备机也会上线,但是处理会更加复杂一点。因为备机是延迟执行的,备机可能有一系列它已经接受和确认的的日志项,但是还没被消费完因为备机还没达到运行的合适时间点。备机必须继续重放来自日志项的运行知道消费完最后的日志项。然后备机将会停止重放模式然后开始正常运行,像普通虚拟机那样。本质上,备机已经被晋升为了主机(现在没有备机了)。因为已经不是备机了,新的主机将在guest os(运行在虚拟机上的操作系统)有输出操作的时候产生输出给外部世界。在过渡为正常模式的期间,可能会需要一些特定设备的操作来让输出正确发生。特别的,出于联网的目的,VMware容错会自动将新的主机的mac地址在网络进行通告,所以物理网络交换机将能够得知新的主机服务器的位置。另外,新的晋升的主机可能需要重发一些磁盘IO(像3.4节描述的那样)
对于尝试检测主机和备机故障有许多可能的方式。VMware容错使用运行在容错虚拟机上的服务器间的udp心跳包来检测哪台服务器已经宕掉了。另外,VMware容错监控从主机发给备机的日志和从备机发送给主机的确认信息的流量。因为经常的时钟中断,日志流量应该是规律的并且永远不会在guest os上停止。因此,日志项和确认信息流的暂停可能表明虚拟机或者网络问题引起的故障。如果心跳包或者日志通道流量停止了超过指定的超时时间(大约几秒钟)则表明这是故障。
然而,任何这类故障检测方法都容易收到脑裂问题的影响。如果备机停止从主机接收心跳包,可能意味着主机故障了,也可能只是因为仍在运行的服务器间的所有网络连接都丢失了。如果备机接着在主机仍旧运行的情况下上线,这可能引起数据损坏或者客户端与虚拟机通信的问题。因此,我们必须确保只有一台主机或备机上线,在故障被检测到的时候。为了避免脑裂的问题,我们使用用来存储虚拟机虚拟磁盘的共享存储。在主机或备机想上线的时候,在共享存储上执行一个原子的test-and-set锁指令。如果操作指令成功,则虚拟机可以上线。如果指令失败,则另外的虚拟机肯定仍在运行,所以当前的虚拟机实际上会结束运行(提交suicide).如果虚拟机无法访问共享存储,在尝试做原子操作指令的时候,只需要一直等到可以访问的时候。记住如果共享存储因为一些存储网络故障导致不能访问,那么虚拟机可能无论如何都不能正常工作,因为虚拟机磁盘也在共享存储上面。因此,使用共享存储来解决脑裂问题不会带来任何额外的不可用
该设计的最后一个方面是一旦故障已经发生了并且其中一个虚拟机已经上线了,VMware容错会自动通过在另外主机上启动新的备机来恢复冗余。即使前面大部分没有提及这个过程,但是这一点对于实现有用的容错系统是基础的,并且需要仔细设计。更多的细节见3.1节。
2.4 Go-live Points[未出现在原论文]
为了容错使用的确定性重放驱使我们在我们的重放实现中增加了一种有趣的机制。因为会有网络问题以及主机故障可能发生在任何时刻,由备机正在读取或者重放的日志项流也可能在任何时刻终止。日志项在任何时刻终止的可能性会扩散到确定性重放的实现,因为每一个日志项(比如一个虚拟的设备实现)的潜在消费者都需要检查和处理所需日志不可用的问题。比如,给定一个之前的日志项和它现在的状态,虚拟设备实现可能需要一系列有关IO实现的额外的日志项。需要编写重放部分的代码来检查日志流的结束,退出一些可能复杂的重放代码,回复设备到合理的状态,使之可以在虚拟机上go live.
为了减轻系统上多数组件的负担,我们已经实现了go-live points.任何单个日志项都可以被标记为go-live points.思想是一个被标记为go-live point的日志项可以用来表示对于重放一个指令或者特别的设备操作必要的一系列日志项中的最后一个日志项。如果一个特别的操作或者指令需要一部分被记录的日志项,那么仅最后的日志项会被标记为go-live point.实际上,虚拟机管理程序会自动标记最后的一个新的日志项为go-live point,在它完成给定指令的所有事件和设备处理的时候。
go-live points在重放期间的使用如下。当所有从日志通道读取的日志项都被虚拟机管理程序缓存在正在重放的虚拟机上。只有最后的go-live point之前的日志项可以被重放的备机消费。也就是说,正在重放的虚拟机在消费最后一个被标记为go-live point的日志项之后会停止运行直到一系列包含go-live point的日志项已经被虚拟机管理程序拉取。结果是如果有一系列和设备操作关联的日志项,如果虚拟设备实现遇到了第一个日志项,就可以假定所有需要的日志项都是可用的。因此,虚拟设备实现不需要做所有额外的检查和恢复代码,如果日志项可以在任何时刻终止。类似的,任何代表虚拟机执行的单个指令生成多个日志项的时候,重放虚拟机的虚拟机管理程序仅在所有的对于完成指令仿真有必要的日志项都是可用的时候,才开始指令的模拟。标记方案不会对正在重放的虚拟机带来任何明显的延迟,因此记录(primary)虚拟机的虚拟机管理程序保证每一个模拟指令或者设备操作的最后的日志项被标记为go-live point.因此备机不会有明显的延迟,主机也不会受到go-live point的影响。
3. FT的实际实现
第2节描述了容错的基础设计和协议。但是为了创建一个可用的,健壮的自动化系统,还需要设计实现许多其他组件。
3.1 启动和重启 FT虚拟机
必须设计的最大的额外组件之一是以和主机相同的状态启动备机的机制。这个机制在故障发生重启备机的时候也会用到。因此,该机制对于运行任意状态(不仅仅是启动)的主机必须是可用的。另外,我们更希望该机制不会明显的打断主机的运行,因此这会影响到所有连接虚拟机的客户端。
对于VMware容错系统,我们适配了VMware vSphere的现有Vmotion功能。VMware VMotion可以在最小化中断的代价下将运行的虚拟机从一台服务器迁移到另一台服务器-虚拟机的暂停时间通常小于1秒。我们创建了一个修改版的Vmotion,通过在远端服务器上创建一个精确的虚拟机的运行拷贝,而不需要摧毁本地服务器上的虚拟机。也就是说,修改版的容错Vmotion克隆一个虚拟机到远端服务器而不是迁移虚拟机。容错Vmotion也会建立一个日志通道,源虚拟机会作为主机进入日志模式,目的虚拟机作为新的备机进入重放模式。和普通版本的Vmotion一样,容错Vmotion通常打断主机的时间少于1秒。因此,在运行中虚拟机启用容错是简单,无中断的操作
启动备机的另一个方面是选择哪台服务器来运行。容错虚拟机运行在访问共享存储的服务器集群上,因而所有的虚拟机是运行在集群中任意的服务器的。这种灵活性让VMware vSphere能够恢复容错冗余在一台或者多台服务器故障的时候。VMware vSphere实现了一个集聚服务来维护管理和资源信息。当故障发生而主机需要一个新的备机重建冗余的时候,主机会通知集聚服务它需要一个新的备机。集聚服务基于资源申请,使用和其他约束来选择运行备机的最佳服务器。然后集聚服务自动调用容错Vmotion来创建新的备机。当然,也有许多额外的复杂性,比如在第一次创建备机失败后的重试,和自动检测集群中服务器什么时候变为新的可用状态。最后的结果是VMware容错可以重建虚拟机冗余在服务器故障后几分钟,而不会对容错虚拟机执行有明显的打断。
3.2 管理日制作通道
管理日志通道的流量有一系列有趣的实现细节。在我们实现中,虚拟机管理程序维护了一个大的缓冲,保存了主机和备机的日志项。当主机运行的时候,会产生日志项到日志缓冲,类似的,备机从日志缓冲消费日志项。主机日志缓冲的内容会尽快刷到日志通道中,日志项写到日志缓冲后也会尽快读取到备机的日志缓冲中。备机发送确认信息给主机,在每一次通过网络读取一些日志项到日志缓冲的时候。这些确认信息让VMvare容错能够决定什么时候被输出规则延迟的输出可以被发送。图3说明了这个过程。

如果备机在读取新的日志项的时候遇到了空的日志缓冲,则会停止运行知道日志项变为可用。因为备机不是在外部通信,这种暂停不会虚拟机的客户端有影响。相似的,如果主机在需要写入日志项的时候发现复制缓冲满了,也会停止运行知道日志项被清除了。主机的停止是自然的流控机制,可以在生成的日志项速率过快的时候降低速度。然而,这种暂停会影响虚拟机的客户端,因为主机会完全停止变为不响应知道可以写入日志继续运行的时候。因此,我们的实现必须设计为最小化主机日志缓冲满的可能性
主机日志缓冲满的一个原因是日志通道的带宽太小以至于无法承载正在生成的日志项的容量。因为日志通道的带宽通常不太高(见第5节),我们强烈建议对于日志通道使用1Gbit/s的网络来避免网络瓶颈。
主机缓冲满的另一个可能原因是备机执行过慢以至于消费日志项太慢。通常,备机必须能以和主机记录执行大致相同的速度重放执行。幸运的是,VMware确定性重放中记录和重放的负载是大致相同的。然而,如果承载备机的服务器也加载了其他的虚拟机(因此使用资源过渡),备机可能无法获得足够的cpu和内存资源以和主机相同的速度执行,即使备机虚拟机管理程序的虚拟机调度器尽最大的努力
除了避免在日志缓冲满时不希望的暂停,还有另外原因是我们不希望执行的滞后变得太大。如果主机故障了,备机必须通过重放所有的在上线并开始和外部世界通信前已经确认了的日志项来赶上主机。结束重放的时间基本上是故障点的执行滞后时间。因此,备机上线的时间大致等于故障检测时间加上当前执行滞后时间。所以,我们不希望执行滞后时间太大(超过1秒),因为这将明显的增加故障转移的时间(备机上线的时间)
因此,我们有一个额外的机制来减慢主机的速度,避免备机落后太多。在发送和确认日志项的协议中,会发送额外的信息来决定实时的运行延迟,在主机和备机之间。通常执行延迟少于100毫秒。如果备机开始有了明显的执行延迟(比如超过1秒),VMware容错会开始减慢主机的速度,通过通知调度器给主机更少的cpu份额(初始时只有百分之几)。我们使用一个慢反馈环,会逐渐的精确话对于主机的cpu份额来让备机匹配上主机的运行。如果备机仍旧落后,我们会继续降低主机的cpu份额。相反了,如果备机追上了主机,我们会逐渐的增加主机的cpu份额知道备机返回微小的延迟
注意对于主机的减速是很罕见的,通常只在系统处于极端压力的情况下发生。第5节的所有性能数字包含了这些减速的成本。
3.3 FT 虚拟机的操作
另一个实际的问题是处理多种可能被应用于主机的控制操作。比如,当主机显式关机的时候,备机也应该关机,而不是尝试上线。另一个例子,主机上任何的资源管理改变(比如增加了cpu份额)也应该应用到备机。对于这些操作,特殊的控制项会通过日志通道从主机发送给备机,为了在备机上也应用适当的操作
通常,虚拟机的多数操作仅在主机上初始化。VMware容错会发送所有必要的控制项在备机上应用适当的变更。唯一可以在主机和备机上独立执行的操作是VMotion.也就是说,主机和备机可以分别独立的Vmotiond到其他主机。注意,VMware容错确保主机和备机都不会被VMotioned到对方所在的服务器上,因为这种情况下不再提供容错。
主机的Vmotion相对于普通Vmotion增加了一些复杂性,因为备机必须和源主机断开连接然后在合适的时间重新连接到目的主机。备机的VMtion有相同的问题,但是增加了额外的复杂性。对于普通的Vmotion,我们要求所有未完成的磁盘IO都暂停(即完成)就像VMotion上发生的最终切换。对于主机,这种暂停容易处理,可以一直等待直到物理IO完成并发送完成信息给虚拟机。然而,对于备机,没有简单的方法在任何需要的时间点让所有IO完成,因为备机必须重放主机的执行并且在相同的执行点完成IO.主机可以运行在总是有磁盘IO的工作负载上,在正常运行期间。VMware容错有独特的方法解决这个问题。当备机在VMotion的最终切换点的时候,它通过日志通道要求主机临时停止所有的IO.备机的IO也会在单独的执行点上自然的暂停,因为备机会重放主机暂停操作的执行命令
3.4 磁盘IO的实现细节
有一些和磁盘IO相关的细微的实现问题。首先,非阻塞的磁盘操作可以并行执行,因此对同一磁盘位置的同时访问可能导致不确定性。我们对磁盘IO的实现使用DMA直接读写虚拟机内存,所有对于相同内存页的同时访问也可能导致不确定性。我们的解决方案通常是检测所有这类IO竞争(是很罕见的),然后强制这些竞争的磁盘操作以相同的方式在主机和备机上顺序执行。有趣的是,单个磁盘读取操作也可能造成竞争,因为散聚的阵列可能引用相同的内存块多次,而导致内存页的内容变得不确定性。我们的解决方案还是检测这些竞争,保证在这种情况下最后的内存内容会在日志通道上发送,这样备机可以以相同的内存内存结束。
第二,虚拟机上的应用程序(或操作系统)的有关内存访问的磁盘操作也可能产生竞争,因为磁盘操作直接通过DMA访问内存。比如,如果虚拟机中的应用程序/操作系统在同一时间读取一个正在发生磁盘读取的内存块可能会导致不确定性。这种情况也是类似的,但是我们必须检测并解决它在发生的时候。我们的解决方案是设置临时的页保护在由磁盘操作标记的页上。如果虚拟机碰巧对未完成磁盘操作的标记页进行访问则页保护最终会进入陷阱,虚拟机会被暂停直到磁盘操作完成。因为修改页上的MMU保护是昂贵的操作,所以我们使用了bounce buffers. Bounce buffer是和由磁盘操作正在访问的内存大小一致的临时缓冲。磁盘读操作被修改为在bounce buffer中读取特定数据,并且数据仅在IO操作完成并被传递的时候拷贝到虚拟机内存。类似的,对于磁盘写操作,将要被发送的数据会先拷贝到bounce buffer,磁盘写操作位被修改为写数据到bounce buffer. Bounce buffer的使用能够减慢磁盘操作,但是我们还没有看到任何明显的性能差异。
第三,当主机故障的时候在主机上可能会有一些未完成的和磁盘IO相关的问题,而备机进行了接管。对新提升的主机就没有办法确定磁盘IO被发布到磁盘还是已经成功完成。另外,因为磁盘IO没有在外部的备机进行发布,当新提升的主机继续运行的时候,不会有明确的IO完成,最终可能导致虚拟机的虚拟机操作系统开始终止或者重置程序。因此,我们希望确保对于每一个挂起的IO,完成信息被发送给虚拟机。我们可以发送错误完成信息来表明IO失败,因为即使IO成功完成,返回错误也是可接受的。然而,虚拟机操作系统可能不会从本地磁盘很好的响应错误。相反,我们在虚拟机go-live的过程重新发布IO。因为我们已经消除了所有的竞争并且所有的IO直接指定了要访问的内存和磁盘块,这些磁盘操作可以重新发布即使已经成功完成了(即是幂等的)
3.5 网络IO的实现细节
VMware vSphere对于虚拟机网络提供了许多性能优化。多数这些优化是基于虚拟机管理程序异步更新虚拟机网络设备的状态。比如,在虚拟机运行的时候接收缓冲区可以被虚拟机管理程序直接更新。不幸的是,这种对于虚拟机状态的异步更新增加了不确定性。除非我们能够保证所有的更新在主机和备机的指令流同时发生,否则备机的执行可能和主机不同
对于容错的网络仿真代码的最大改变是消除了异步网络优化。所有对于虚拟机网络状态的更新必须在虚拟机不执行指令的时候完成,以便我们可以记录更新日志并在备机上指令流的同一点重放。异步更新虚拟机ring buffer的代码被修改为强制guest陷入到虚拟机管理程序,在虚拟机管理程序里可以更新然后应用更新日志带虚拟机。类似的,之前异步拉取传输队列的包的代码被容错禁用了,取而代之的我们要求通过陷入到虚拟机管理程序来完成传输(如下所示)
网络设备异步更新的消除和2.2节描述的发送包的延迟,为网络的性能带来了挑战。我们已经使用两种方法来提高运行容错的虚拟机的网络性能。首先,我们实现了集群优化来江都虚拟机的陷入和中断。当我们以足够的比特率传输数据,我们可以对于每一组包进行一次传输陷入,最好的情况下是0陷入,因为我们将包作为新接收的包的一部分进行传输。同样的,我们通过对每一组包发送一次中断,来降低对于传入包的虚拟机的中断次数。
我们对于网络的第二个性能优化涉及降低传输包的延迟。如前面提到的,我们必须延迟所有的传输包直到获取了备机的确认信息,在备机接受到合适的日志项。降低传输延迟的关键是降低要求的发送给备机的日志信息和获取更新的时间。我们在这个方面的主要优化设计确保发送接受日志项和确认信息都在不发生线程上下文切换的情况下完成。VMware vSphere虚拟机管理程序允许函数被注册为TCP栈,任何接收到tcp数据的时候,将在推迟执行上下文中调用(类似linux的软中断)。这允许我们在备机上快速处理所有的输入日志项和由主机收到的确认信息,而不会发生任何的线程上下文切换。另外,当主机将需要被传输的包入队,我们通过调度延迟执行上下文来将需要立即刷新的和输出日志项关联的日志进行刷新。
4. 设计取舍
在我们VMware容错的实现中,我们已经探索了许多有趣的设计替代方案。在这一节,我们探索一部分替代方案
4.1 共享 vs 非共享磁盘
在我们的缺省设计中,主机和备机共享相同的虚拟磁盘。因此,共享磁盘的内容在故障转移发生的时候自然是正确和可用的。基本上,共享磁盘被认为在主机和备机的外部,所以共享磁盘的写入是到外部世界的通信。因此,只有主机实际上写磁盘,共享磁盘的写入以和输出规则一致的方式进行延迟。共享磁盘模型在[3, 9, 7]中使用

对于主机和备机的一个替代设计是使用单独(非共享)的虚拟磁盘。在这种设计中,备机将所有的写写到自己的虚拟磁盘,这样做可以自然的保持备机的虚拟磁盘和主机的虚拟磁盘保持同步。图4说明了这种配置。对于非共享磁盘的情况,每个虚拟磁盘本质上被认为是每个虚拟机的内部状态的一部分。因此,主机的磁盘写不用根据输出规则做延迟。在共享存储对于主机和备机不可访问的时候非共享的设计是相当有用的。可能是因为共享存储不可用或太昂贵,或是因为运行主机和备机的服务器相距很远(远距离的容错)。非共享设计的一个缺点是在容错第一次启用的时候,虚拟磁盘的两份拷贝必须显式同步。另外,磁盘可能会在故障发生后脱离同步,所以在故障发生后虚拟机重启的时候,磁盘必须被显式的重新同步。也就是说,容错VMotion必须不光同步主机和备机的运行状态,也要同步磁盘的状态。
在非共享磁盘的配置下,可能没有可用的共享存储对于解决脑裂的情况。在这种情况下,系统可以使用一些其他的外部的”决胜局”,比如主机和备机都可以进行通信的第三方服务器。如果服务器是超过两个节点的集群的一部分,系统可以替代性的使用基于集群成员的多数派算法。在这种情况下,如果虚拟机运行在一个属于包含多数原始节点的通信子集群的一部分的服务器上,将仅仅被允许上线。
4.2 在备用VM执行磁盘读
在我们的缺省设计中,备机绝不会从虚拟磁盘(不管共享还是非共享)进行读取.因为磁盘读被认为是一个输入,通过日志通道发送磁盘读的结果给备机是自然的。
一个替代的设计是让备机执行磁盘读,这样可以消除磁盘读的日志。这样可以极大的降低日志通道的流量,在有大量磁盘读的工作负载上。然而,这种方法有很多微妙之处。它可能会减慢备机的执行速度,因为备机必须执行所有的磁盘读,并且在达到主机上执行完成的执行点上等待磁盘读是否在物理上完成
并且,必须做一些额外的工作来处理失败的磁盘读操作。如果主机的磁盘读成功了但是备机的磁盘读失败了,那么备机的磁盘读必须重试直到成功,因为备机必须在内存中获得和主机一样的数据。反过来,如果主机的磁盘读失败,必须通过日志通道将目的内存的内容发送给备机,因为内存的内容将会是不确定性的,并且备机的成功磁盘读可能是不必要的副本
最后,替代方案的磁盘读和共享磁盘配置一起使用的行为是微妙的。如果主机读取了一个特定的磁盘位置,然后很快又有一个对于相同磁盘位置的写操作,则第二次磁盘写将被延迟到备机已经执行了第一次的磁盘读。这种依赖可以被检测到并进行正确的处理,但是对于实现增加了额外的复杂性。
在5.1节,我们提供的一些性能结果表明在备机上执行磁盘读会对应用程序的吞吐有轻微的降低(1-4%),但也会显著降低日志的带宽。因此,对于日志通道带宽受限的情况,在备机执行磁盘读是有用的。
5. 性能评估
在本节中,我们将对VMware FT在一些应用程序工作负载和网络基准测试方面的性能进行基本评估。 对于这些结果,我们在相同的服务器上运行主vm和备份vm,每个服务器使用8个Intel Xeon 2.8 Ghz cpu和8 gb RAM。 服务器通过一个10 Gbit/s的交叉网络连接,尽管在所有情况下使用的网络带宽都远远小于1 Gbit/s。 两个服务器都访问它们共享的虚拟机来自EMC公司的磁盘通过标准的 4 gbit/s光纤通道网络连接。 用于驱动某些工作负载的客户机通过一个 1 gbit/s 网络连接到服务器。
我们在性能结果中评估的应用程序如下。 SPECJbb2005是一种工业标准的Java应用程序基准测试,它占用大量的CPU和内存,只做很少的IO工作。 内核编译是运行Linux内核编译的工作负载。 这个工作负载执行一些磁盘读写操作,并且由于许多编译过程的创建和销毁,所以对CPU和mmu的占用非常大。 Oracle Swingbench是一个工作负载,其中Oracle 11g数据库由Swingbench OLTP(在线事务处理)工作负载驱动。 这个工作负载执行大量的磁盘和网络IO,并且有80个同时的数据库会话。 MS-SQL DVD存储是一种工作负载,其中Microsoft SQL Server 2005数据库由DVD存储基准驱动,该基准有16个并发客户机。
5.1 基本性能结果
表1给出了基本的性能结果。 对于列出的每个应用程序,第二列给出在运行服务器工作负载的VM上启用FT时应用程序的性能与在同一VM上不启用FT时的性能之比。 计算性能比率时,小于1的值表示FT工作负载较慢。 显然,在这些典型的工作负载上启用FT的开销不到10%。 SPECJbb2005完全是受计算限制的,没有空闲时间,但是执行得很好,因为除了定时器中断之外,它有最小的不确定性事件。 其他工作负载执行磁盘IO并有一些空闲时间,因此FT开销的一部分可能被FT vm的空闲时间更少这一事实所掩盖。 然而,一般的结论是VMware FT能够以相当低的性能开销支持容错vm。

在表的第三列中,我们给出了运行这些应用程序时在日志通道上发送的数据的平均带宽。 对于这些应用程序,日志带宽是相当合理的,并且很容易满足1gbit /s网络。 事实上,低带宽要求表明多个FT工作负载可以共享相同的1 Gbit/s网络,而不会对性能产生任何负面影响。
对于运行Linux和Windows等常见客户操作系统的vm,我们发现当客户操作系统空闲时,典型的日志带宽是0.5-1.5 Mbits/秒。 “空闲”带宽主要是记录定时器中断的传输的结果。 对于具有活动工作负载的VM,日志记录带宽由必须发送到备份的网络和磁盘输入(接收到的网络数据包和从磁盘读取的磁盘块)控制。 因此,日志记录带宽可以很大,对于具有非常高的网络接收或磁盘读取带宽的应用程序,它比表1中测量的值要高。 对于这类应用程序,日志通道的带宽可能成为瓶颈,特别是在日志通道有其他用途的情况下。
对于许多实际应用程序,日志通道所需的相对较低的带宽使得基于重播的容错对于使用非共享磁盘的远程配置非常有吸引力。 对于主备相距1-100公里的长距离配置,光纤可以很容易地支持100- 1000mbit /s的带宽,延迟小于10毫秒。 对于表1中的应用程序,100- 1000mbit /s的带宽应该足以实现良好的性能。 但是,请注意,主备份和备份之间额外的往返延迟可能会导致网络和磁盘输出延迟至多20毫秒。 远程配置只适用于客户端能够容忍每个请求额外延迟的应用程序。
对于两个磁盘最密集的应用程序,我们测量了在备份VM上执行磁盘读(如4.2节所述)与通过日志通道发送磁盘读数据对性能的影响。 对于Oracle Swingbench,在备份VM上执行磁盘读取时,吞吐量大约降低4%; 对于MS-SQL DVD商店,吞吐量大约低1%。 同时,Oracle Swingbench的日志带宽从12兆比特/秒降低到3兆比特/秒,MS-SQL DVD商店的日志带宽从18兆比特/秒降低到8兆比特/秒。 显然,对于具有更大的磁盘读取带宽的应用程序,可以节省更多的带宽。 正如在第4.2节中提到的,当在备份VM上执行磁盘读取时,性能可能会有所下降。 但是,对于日志通道带宽有限的情况(例如,远程配置),在备份VM上执行磁盘读取可能很有用。
5.2 网络基准
网络基准测试对于我们的系统来说是非常具有挑战性的,原因有很多。 首先,高速网络可能具有非常高的中断率,这要求以非常高的速率记录和回放异步事件。 其次,以高速率接收信息包的基准测试将导致高速率的日志流量,因为所有这些信息包都必须通过日志通道发送到备份。 第三,发送信息包的基准测试将服从输出规则,该规则将延迟网络信息包的发送,直到收到来自备份的适当确认。 此延迟将增加到客户端的测量延迟。 这种延迟还可能减少到客户机的网络带宽,因为随着往返延迟的增加,网络协议(如TCP)可能必须降低网络传输速率。
表2给出了我们使用标准netperf基准测试进行的许多测量的结果。 在所有这些测量中,客户机VM和主VM通过一个1gbit /s网络连接。 当主主机和备份主机通过1 Gbit/s日志通道连接时,前两行给出发送和接收性能。 当主服务器和备份服务器通过10gbit /s日志通道连接时,第三和第四行给出了发送和接收性能,这不仅具有更高的带宽,而且比1gbit /s网络的延迟更低。 作为一个粗略的度量,1gbit /s连接的管理程序之间的ping时间约为150微秒,而10gbit /s连接的ping时间约为90微秒。
当不启用FT时,主VM可以实现接近(940 Mbit/s) 1 Gbit/s的行速率进行发送和接收。 当为接收工作负载启用FT时,日志带宽非常大,因为所有传入的网络数据包都必须在日志通道上发送。 因此,日志通道可能成为瓶颈,如1gbit /s日志网络的结果所示。 对于10gbit /s的测井网络,影响要小得多。 当为传输工作负载启用FT时,传输数据包的数据不被记录,但是网络中断必须被记录。 日志记录的带宽要低得多,因此可实现的网络传输带宽要高于网络接收带宽。 总的来说,我们可以看到,在非常高的发射和接收速率下,FT可以显著地限制网络带宽,但是高的绝对速率仍然是可以实现的。

6. 相关工作
Bressoud和Schneider[3]描述了通过完全包含在管理程序级别的软件为虚拟机实现容错的最初想法。 他们通过使用HP PA-RISC处理器的服务器原型,演示了保持备份虚拟机与主虚拟机同步的可行性。 然而,由于PA-RISC架构的限制,他们不能实现完全安全的、隔离的虚拟机。 此外,他们没有实现任何故障检测方法,也没有试图解决第3节中描述的任何实际问题。 更重要的是,他们对FT协议强加了一些不必要的约束。 首先,他们引入了epoch的概念,其中异步事件被延迟到一个集合间隔的末尾。 epoch的概念是不必要的——他们可能强加了它,因为他们不能足够有效地重放单个异步事件。 其次,它们要求主VM停止执行,直到备份已经接收并确认了所有以前的日志条目。 然而,只有输出本身(如网络包)必须延迟——主VM本身可以继续执行。
Bressoud[4]描述了一个在操作系统(Unixware)中实现容错的系统,因此为在该操作系统上运行的所有应用程序提供容错。 系统调用接口成为必须确定地复制的操作集。 这项工作与基于管理程序的工作具有类似的限制和设计选择。
Napper等人的[9]、Friedman和Kama[7]描述了容错Java虚拟机的实现。 它们遵循与我们类似的设计,在日志通道上发送关于输入和非确定性操作的信息。 与Bressoud一样,它们似乎并不专注于检测故障并在故障后重新建立容错能力。 此外,它们的实现仅限于为在Java虚拟机中运行的应用程序提供容错。 这些系统试图处理多线程Java应用程序的问题,但是要求所有数据都正确地受到锁的保护,或者在访问共享内存时强制进行序列化。
Dunlap等人的[6]描述了一种确定性重放的实现,其目标是调试半虚拟化系统上的应用软件。 我们的工作支持在虚拟机中运行的任意操作系统,并为这些vm实现容错支持,这需要更高级别的稳定性和性能。
Cully等人在一个名为Remus的项目中描述了一种支持容错vm的替代方法及其实现。 使用这种方法,主VM的状态在执行期间被反复检查,并被发送到备份服务器,备份服务器收集检查点信息。 检查点必须非常频繁地执行(每秒多次),因为外部输出必须延迟,直到发送并确认了以下检查点。 这种方法的优点是它同样适用于单处理器和多处理器vm。 主要问题是这种方法对网络带宽的要求非常高,需要在每个检查点将增量更改发送到内存状态。 在[5]中给出的Remus测试结果显示,当使用1 Gbit/s网络连接来传输内存状态变化时,内核编译和SPECweb基准测试的速度会降低100%到225%。 在减少所需的网络带宽方面,有一些优化可能是有用的,但是对于1 Gbit/s连接是否可以实现合理的性能,目前还不清楚。 相比之下,我们基于确定性重放的方法可以实现小于10%的开销,几个实际应用程序的主主机和备份主机之间所需的带宽小于20 Mbit/s。
7. 结论与未来工作
我们在VMware vSphere中设计并实现了一个高效、完整的系统,为运行在集群服务器上的虚拟机提供容错(FT)。 我们的设计基于使用VMware确定性重播,通过在另一台主机上的备份VM复制主VM的执行。 如果运行主VM的服务器发生故障,则备份VM立即接管,不会中断或丢失数据。
总的来说,VMware FT下的容错vm在普通硬件上的性能非常好,并且在某些典型应用程序上的开销还不到10%。 VMware FT的大部分性能成本来自于使用VMware确定性回放来保持主vm和备份vm同步的开销。 VMware FT的低开销是由VMware确定性重放的效率决定的。 此外,保持主备份同步所需的日志带宽通常非常小,通常小于20 Mbit/s。 因为在大多数情况下,日志记录带宽非常小,所以在主vm和备份vm之间用长距离(1-100公里)分隔的情况下实现配置似乎是可行的。 因此,VMware FT可以用于保护整个站点不受灾难影响的场景。 值得注意的是,日志流通常是可压缩的,简单的压缩技术可以通过少量额外的CPU开销显著减少日志带宽。
我们使用VMware FT的结果表明,可以在确定性重放的基础上构建容错vm的有效实现。 这样的系统可以透明地为运行任何操作系统和应用程序的vm提供容错,而且开销最小。 然而,要使容错vm系统对客户有用,它还必须是健壮的、易于使用的和高度自动化的。 一个可用的系统需要许多其他组件,而不仅仅是vm的复制执行。 具体来说,VMware FT通过在本地集群中找到一个合适的服务器并在该服务器上创建一个新的备份VM,在出现故障后自动恢复冗余。 通过解决所有必要的问题,我们已经演示了一个可以在客户的数据中心中用于实际应用程序的系统。
通过确定性重放实现容错的一个折衷之处是,目前确定性重放只在单处理器vm上有效地实现。 但是,单处理器vm对于各种工作负载来说已经足够了,特别是在物理处理器的功能不断增强的情况下。 此外,许多工作负载可以通过使用多个单处理器VM来扩展,而不是通过使用一个更大的多处理器VM来扩展。 针对多处理器vm的高性能回放是一个活跃的研究领域,可以通过微处理器中的一些额外硬件支持来启用它。 一个有趣的方向可能是扩展事务性内存模型,以促进多处理器回放。
今后,我们有兴趣调查前面提到的远距离容错配置的性能特征。我们也有兴趣扩展我们的系统来解决部分硬件。所谓的部分硬件故障,说的是服务器中部分功能缺失或冗余,不会导致数据的损坏或丢失。比如虚拟机的所有网络连接的丢失,或者物理服务器中冗余电源的丢失。如果部分硬件故障发生在运行主机的服务器上,在大多数情况(不是所有情况)下对于故障立即转移到备机是有利的。故障转移可以让关键的虚拟机恢复完整服务,并确保虚拟机从潜在不可靠的服务器中快速移出。
参考文献
[1] Alsberg, P., and Day, J. A Principle for Resilient Sharing of Distributed Resources. In Proceedings of the Second International Conference on Software Engineering (1976), pp. 627–644.
[2] AMD Corporation. AMD64 Architecture Programmer’s Manual. Sunnyvale, CA.
[3] Bressoud, T., and Schneider, F. Hypervisor-based Fault Tolerance. In Proceedings of SOSP 15 (Dec. 1995).
[4] Bressoud, T. C. TFT: A Software System for Application-Transparent Fault Tolerance. In Proceedings of the Twenty-Eighth Annual International Symposium on FaultTolerance Computing (June 1998), pp. 128–137.
[5] Cully, B., Lefebvre, G., Meyer, D., Feeley, M., Hutchison, N., and Warfield, A. Remus: High Availability via Asynchronous Virtual Machine Replication. In Proceedings of the Fifth USENIX Symposium on Networked Systems Design and Implementation (Apr. 2008), pp. 161–174.
[6] Dunlap, G. W., King, S. T., Cinar, S., Basrai, M., and Chen, P. M. ReVirt: Enabling Intrusion Analysis through Virtual Machine Logging and Replay. In Proceedings of the 2002 Symposium on Operating Systems Design and Implementation (Dec. 2002).
[7] Friedman, R., and Kama, A. Transparent Fault-Tolerant Java Virtual Machine. In Proceedings of Reliable Distributed System (Oct. 2003), pp. 319–328.
[8] Intel Corporation. IntelAˆR 64 and IA-32 Architectures Software Developer’s Manuals. Santa Clara, CA.
[9] Napper, J., Alvisi, L., and Vin, H. A Fault-Tolerant Java Virtual Machine. In Proceedings of the International Conference on Dependable Systems and Networks (June 2002), pp. 425–434.
[10] Nelson, M., Lim, B.-H., and Hutchins, G. Fast Transparent Migration for Virtual Machines. In Proceedings of the 2005 Annual USENIX Technical Conference (Apr. 2005).
[11] Nightingale, E. B., Veeraraghavan, K., Chen, P. M., and Flinn, J. Rethink the Sync. In Proceedings of the 2006 Symposium on Operating Systems Design and
Implementation (Nov. 2002).
[12] Schlicting, R., and Schneider, F. B. Fail-stop Processors: An Approach to Designing Fault-tolerant Computing Systems. ACM Computing Surveys 1, 3 (Aug.
1983), 222–238.
[13] Schneider, F. B. Implementing fault-tolerance services using the state machine approach: A tutorial. ACM Computing Surveys 22, 4 (Dec. 1990), 299–319.
[14] Stratus Technologies. Benefit from Stratus Continuing Processing Technology: Automatic 99.999% Uptime for Microsoft Windows Server Environments. At http://www.stratus.com/pdf/whitepapers/continuous-processing-for-windows.pdf, June 2009.
[15] Xu, M., Malyugin, V., Sheldon, J., Venkitachalam, G., and Weissman, B. ReTrace: Collecting Execution Traces with Virtual Machine Deterministic Replay. In
Proceedings of the 2007 Workshop on Modeling, Benchmarking, and Simulation (June 2007). |
|