The Design of aPractical System forFault Tolerant Virtual Machines论文
Daniel J. Scales, Mike Nelson, and Ganesh Venkitachalam
VMware, Inc
{scales,mnelson,ganesh}@vmware.com
vmware ft
test-and-set server:
比如现在primary和backup之间的联系丢了,他们要决定新的primary,这时一个backup就会请求test-and-set server,将0设为1,然后后面的来访问,就发现已经有人来申请嘞,这就有效的避免了脑裂。
ABSTRACT
我们实施了一个商业的企业级系统,用于提供容错虚拟机,该系统基于通过其他服务器上的备份虚拟机复制主虚拟机(VM)的执行的方法。我们在VMwarevSphere 4.0中设计了一个完整的系统,该系统易于使用,在商品服务器上运行,并且通常将实际应用的性能降低到10%以下。此外,在几个实际应用中,保持主虚拟机和辅助虚拟机同步执行所需的数据带宽低于20Mbit/s,这使得在更远的距离上实现容错成为可能。一个易于使用的、能在故障后自动恢复冗余的商业系统,除了复制的虚拟机执行外,还需要许多额外的组件。我们已经设计并实现了这些额外的组件,并解决了在支持运行企业应用程序的虚拟机方面遇到的许多实际问题。在本节中,我们描述了我们的基本设计,讨论了其他的设计选择和一些实施细节,并提供了微观测试和实际应用的性能结果。
1 INTRODUCTIONA
实现容错服务器的常见方法是主/备份方法[1],在这种方法中,如果主服务器发生故障,备份服务器总是可以接替。备份服务器的状态必须始终保持与主服务器几乎相同,这样当主服务器发生故障时,备份服务器就可以立即接管,而且对外部客户来说,故障是隐藏的,没有数据丢失。复制备份服务器上的状态的一种方法是将主服务器的所有状态(包括CPU、内存和I/O设备)的变化几乎持续地传送到备份服务器上。然而,发送这种状态所需的带宽,特别是内存的变化,可能非常大。 一种不同的复制服务器的方法,可以使用少得多的带宽,有时被称为状态机方法[13]。这个想法是将服务器建模为确定性的状态机,通过从相同的初始状态开始并确保它们以相同的顺序接收相同的输入请求来保持同步。由于大多数服务器或服务有一些操作是不确定的,所以必须使用额外的协调来确保主服务器和备份服务器保持同步。然而,保持主备同步所需的额外信息量远远小于主备中变化的状态(主要是内存更新)的数量。
实施协调以确保物理服务器的确定性执行[14]是困难的,特别是随着处理器频率的提高。相比之下,在管理程序之上运行的虚拟机(VM)是实现状态机方法的绝佳平台。一个虚拟机可以被认为是一个定义明确的状态机,其操作是被虚拟化的机器(包括其所有设备)的操作。与物理服务器一样,虚拟机有一些非确定性的操作(例如,读取时间时钟或交付中断),因此必须向备份发送额外的信息以确保其保持同步。由于管理程序完全控制了虚拟机的执行,包括所有输入的交付,管理程序能够捕获所有关于主虚拟机上的非确定性操作的必要信息,并在备份虚拟机上正确重放这些操作。 因此,状态机方法可以在商品硬件上为虚拟机实现,不需要对硬件进行修改,可以立即为最新的微处理器实现容错。此外,状态机方法所需的低带宽允许主机和备份有更大的物理分离的可能性。例如,复制的虚拟机可以在分布在校园内的物理机上运行,这比在同一建筑物内运行的虚拟机提供更多的可靠性。
我们在VMware vSphere 4.0平台上使用主/备份方法实现了容错虚拟机,该平台以一种高效的方式运行完全虚拟化的x86虚拟机。由于VMware vSphere实现了完整的x86虚拟机,我们自动能够为任何x86操作系统和应用程序提供容错。使我们能够记录主程序的执行情况并确保备份的执行情况相同的基础技术被称为确定性重放[15]。VMware vSphere Fault Tolerance(FT)以确定性重放(deterministic replay)为基础,但加入了必要的额外协议和功能,以构建一个完整的容错系统。除了提供硬件容错外,我们的系统在故障后会自动恢复冗余,在本地集群的任何可用服务器上启动一个新的备份虚拟机。目前,确定性重放和VMware FT的生产版本都只支持单处理器的虚拟机。记录和重放多处理器虚拟机的执行仍在进行中,由于几乎对共享内存的每一次访问都可能是一个非确定性的操作,因此存在很大的性能问题。
Bressoud和Schneider[3]描述了HP PA-RISC平台的容错虚拟机的原型实现。我们的方法是类似的,但是我们出于性能的考虑做了一些根本性的改变,并研究了一些设计方案。此外,我们不得不在系统中设计和实现许多额外的组件,并处理一些实际问题,以建立一个完整的系统,该系统是有效的,可供运行企业应用程序的客户使用。与讨论的其他大多数实用系统类似,我们只试图处理故障停止的故障[12],即在故障的服务器引起外部可见的错误动作之前可以检测到的服务器故障。 本文的其余部分组织如下。首先,我们描述了我们的基本设计,并详细介绍了我们的基本协议,这些协议确保在主虚拟机故障后由备份虚拟机接管时不会丢失数据。然后,我们详细描述了为建立一个强大的、完整的、自动化的系统而必须解决的许多实际问题。我们还描述了在实现容错虚拟机时出现的几种设计选择,并讨论了这些选择中的权衡。接下来,我们给出了我们的实现在一些基准和一些实际企业应用中的性能结果。最后,我们描述了相关工作并得出结论。
2 基本设计
图1显示了我们的系统对容错虚拟机的基本设置。对于我们希望提供容错的特定虚拟机(主虚拟机),我们在不同的物理服务器上运行一个备份虚拟机,该备份虚拟机与主虚拟机保持同步,并以相同的方式执行,尽管有一点时间滞后。我们说,这两个虚拟机处于虚拟锁定状态。虚拟机的虚拟磁盘在共享存储上(如光纤通道或iSCSI磁盘阵列),因此,主虚拟机和备份虚拟机都可以访问,以便进行输入和输出。(我们将在第4.1节中讨论主用虚拟机和备份虚拟机拥有独立的非共享虚拟磁盘的设计)。只有主虚拟机在网络上宣传它的存在,所以所有的网络输入都是针对主虚拟机的。同样,所有其他的输入(如键盘和鼠标)也只针对主虚拟机。 主虚拟机收到的所有输入都通过被称为日志通道的网络连接发送到备份虚拟机。对于服务器工作负载,主要的输入路径是网络和磁盘。如下文第2.1节所述,额外的信息会根据需要而被传送,以确保备份虚拟机以与主虚拟机相同的方式执行非确定性的操作。其结果是,备份虚拟机总是与主虚拟机执行相同的操作。然而,备份虚拟机的输出被管理程序放弃,因此只有主虚拟机产生实际的输出,并返回给客户。如第2.2节所述,主虚拟机和备份虚拟机遵循一个特定的协议,包括备份虚拟机的明确确认,以确保在主虚拟机故障时不会丢失数据。 为了检测主用或备用虚拟机是否发生故障,我们的系统结合使用相关服务器之间的心跳和对日志通道的traffic进行监测。此外,我们必须确保只有一个主用或备用虚拟机接管执行,即使出现了主用和备用服务器彼此失去通信的分脑情况。 在下面的章节中,我们将提供更多关于七个重要领域的细节。在第2.1节中,我们给出了一些关于确定性重放(deterministic replay)技术的细节,该技术确保主用和备用虚拟机通过日志通道的信息传递保持同步。 在第2.2节中,我们描述了我们的FT协议的基本规则,确保在主服务器故障时不会丢失数据。在第2.3节中,我们描述了我们以正确的方式检测和应对故障的方法。
Figure 1: Basic FT Configuration.
2.1 确定性复制的实现
正如我们所提到的,复制服务器(或虚拟机)的执行可以被建模为确定性状态机的复制。如果两个确定性状态机以相同的初始状态启动,并以相同的顺序提供完全相同的输入,那么它们将经历相同的状态序列并产生相同的输出。一个虚拟机有一个广泛的输入集合,包括传入的网络数据包、磁盘读取、以及来自键盘和鼠标的输入。非确定性的事件(如虚拟中断)和非确定性的操作(如读取处理器的时钟周期计数器)也会影响虚拟机的状态。这为复制运行任何操作系统和工作负载的任何虚拟机的执行提出了三个挑战。(1)正确捕捉所有必要的输入和非确定性,以确保备份虚拟机的确定性执行,(2)正确地将输入和非确定性应用于备份虚拟机,以及(3)以不降低性能的方式进行。此外,x86微处理器中的许多复杂操作都有未定义的副作用,因此是非确定性的。捕获这些未定义的副作用并重放它们以产生相同的状态是一个额外的挑战。 VMware确定性重放[15]正是为VMware vSphere平台上的x86虚拟机提供了这种功能。确定性重放记录了虚拟机的输入以及与虚拟机执行相关的所有可能的非确定性,并将其写入日志文件的日志条目流中。以后可以通过从文件中读取日志条目来精确重放虚拟机的执行。对于非确定性操作,记录足够的信息以允许以相同的状态变化和输出来重现该操作。对于非确定性的事件,如定时器或IO完成中断,事件发生的确切指令也被记录下来。在重放过程中,该事件在指令流中的同一位置被传递。VMware确定性重放实现了高效的事件记录和事件交付机制,采用了各种技术,包括使用与AMD[2]和Intel[8]共同开发的硬件性能计数器。 Bressoud和Schneider[3]提到将虚拟机的执行划分为epochs,其中非确定性的事件(如中断)只在epoch结束时交付。epoch的概念似乎被用作一种批处理机制,因为在发生中断的确切指令处单独交付每个中断的成本太高。然而,我们的事件传递机制足够高效,以至于VMware的确定性重放没有必要使用epochs。每个中断在发生时被记录下来,并在重放时在适当的指令处有效地交付。
2.2 FT协议
对于VMware FT,我们使用确定性重放来产生必要的日志条目,以记录主虚拟机的执行情况,但我们没有将日志条目写入磁盘,而是通过日志通道将其发送给备份虚拟机。备份虚拟机实时重放这些条目,因此执行起来与主虚拟机完全一样。然而,我们必须在日志通道上用严格的FT协议来增加日志条目,以确保我们实现容错。我们的基本要求如下:
输出要求:如果备份虚拟机在主虚拟机发生故障后接管,备份虚拟机将继续执行,
与主虚拟机向外部世界发送的所有输出完全一致。
请注意,在故障切换发生后(即备份虚拟机在主虚拟机故障后接管),备份虚拟机开始执行的方式可能与主虚拟机继续执行的方式完全不同,因为在执行过程中发生了许多非确定性的事件。然而,只要备份虚拟机满足输出要求,在故障切换到备份虚拟机的过程中就不会丢失外部可见的状态或数据,客户也不会注意到他们的服务中断或不一致。
输出要求可以通过延迟任何外部输出(通常是网络数据包)来确保,直到备份虚拟机收到所有信息,使其至少在输出操作点上重放执行。一个必要条件是,备份虚拟机必须收到输出操作之前产生的所有日志条目。这些日志条目将允许它执行到最后一个日志条目的位置。然而,假设在主服务器执行输出操作后,立即发生了故障。备份虚拟机必须知道,它必须继续重放,直到输出操作的那一刻,并且只在那一刻 "上线"(停止重放并作为主虚拟机接管,如2.3节所述)。如果备份在输出操作前的最后一条日志条目处上线,一些非确定性的事件(例如传递给虚拟机的定时器中断)可能会在它执行输出操作之前改变其执行路径。
鉴于上述限制,执行 "输出要求 "的最简单方法是在每个输出操作中创建一个特殊的日志条目。然后,输出要求可以通过这个特定的规则来执行:
输出规则:主虚拟机不得向外部世界发送输出,直到备份虚拟机收到并确认与产生输出的操作相关的日志条目。
如果备份虚拟机收到了所有的日志条目,包括产生输出的操作的日志条目,那么备份虚拟机将能够准确地重现主虚拟机在该输出点的状态,因此如果主虚拟机死亡,备份将正确地达到与该输出一致的状态。相反,如果备份虚拟机在没有收到所有必要的日志条目的情况下接管,那么它的状态可能会很快发生变化,从而与主虚拟机的输出不一致。输出规则在某些方面类似于[11]中描述的方法,其中 "外部同步 "的IO实际上可以被缓冲,只要它在下一次外部通信之前被实际写入磁盘。
请注意,输出规则并没有说要停止主虚拟机的执行。我们只需要延迟输出的发送,但虚拟机本身可以继续执行。由于操作系统用异步中断做非阻塞的网络和磁盘输出来表示完成,所以虚拟机可以很容易地继续执行,不一定会立即受到输出延迟的影响。相反,以前的工作[3,9]通常表明,在做输出之前,主虚拟机必须完全停止,直到备份虚拟机确认了主虚拟机的所有必要信息。
作为一个例子,我们在图2中展示了一个说明FT协议要求的图表。该图显示了主虚拟机和备份虚拟机上的事件的时间线。从主线到备份线的箭头代表日志条目的传输,从备份线到主线的箭头代表确认。关于异步事件、输入和输出操作的信息必须作为日志条目发送到备份并确认。如图所示,对外部世界的输出被延迟,直到主虚拟机收到备份虚拟机的确认,即它已经收到与输出操作相关的日志条目。鉴于输出规则被遵循,备份虚拟机将能够以与主虚拟机最后一次输出一致的状态接管。
我们不能保证在故障切换的情况下,所有的输出都能准确地产生一次。如果在主服务器打算发送输出时不使用两阶段提交的事务,备份就没有办法确定主服务器是在发送最后一次输出之前还是之后崩溃的。幸运的是,网络基础设施(包括普遍使用的TCP)被设计用来处理丢失的数据包和相同(重复)的数据包。请注意,在主服务器发生故障时,传入主服务器的数据包也可能丢失,因此不会被传递到备份服务器。然而,传入的数据包可能会因为与服务器故障无关的任何原因而丢失,所以网络基础设施、操作系统和应用程序都是为了确保它们能够补偿丢失的数据包而编写的。
Figure 2: FT Protocol.
2.3 检测和应对故障
如上所述,如果其他虚拟机出现故障,主虚拟机和备份虚拟机必须迅速做出反应。如果备份虚拟机发生故障,主虚拟机将上线--即离开记录模式(并因此停止在日志通道上发送条目),并开始正常执行。如果主虚拟机发生故障,备份虚拟机也应同样上线,但这个过程要复杂一些。由于执行的滞后性,备份虚拟机可能会有一些它已经收到并确认的日志条目,但还没有被消耗,因为备份虚拟机还没有到达执行的适当点。备份虚拟机必须继续从日志条目中重放其执行,直到它消耗了最后一个日志条目。在这一点上,备份虚拟机将停止重放模式,并开始作为正常虚拟机执行。实质上,备份虚拟机已经被提升为主虚拟机(现在缺少一个备份虚拟机)。由于它不再是一个备份虚拟机,新的主虚拟机现在将在客体操作系统进行输出操作时向外部世界产生输出。在过渡到正常模式期间,可能需要一些特定设备的操作,以使这种输出正常发生。特别是,为了联网的目的,VMware FT自动在网络上宣传新的主虚拟机的MAC地址,这样物理网络交换机就会知道新的主虚拟机位于哪台服务器上。此外,新晋升的主虚拟机可能需要重新发出一些磁盘IO(如第3.4节所述)。
有许多可能的方法来尝试检测主虚拟机和备份虚拟机的故障。VMware FT使用正在运行容错虚拟机的服务器之间的UDP心跳来检测服务器可能已经崩溃的情况。此外,VMware FT监控从主虚拟机发送到备份虚拟机的日志流量以及从备份虚拟机发送到主虚拟机的确认。由于定期的定时器中断,对于一个正常运行的客户操作系统来说,日志流量应该是有规律的,永远不会停止。因此,日志条目或确认信息流的停止可能表明一个虚拟机的故障。如果心跳或日志流量停止的时间超过了特定的超时(在几秒钟的数量级上),就会宣布失败。
然而,任何这样的故障检测方法都很容易受到脑裂问题的影响。如果备份服务器停止接收来自主服务器的心跳,这可能表明主服务器已经失败,或者它可能只是意味着所有的网络连接已经在仍然运行的服务器之间丢失。如果备份虚拟机随后上线,而主虚拟机实际上仍在运行,那么很可能会出现数据损坏和与虚拟机通信的客户端出现问题。因此,我们必须确保在检测到故障时,主虚拟机或备份虚拟机中只有一个会上线。为了避免脑裂问题,我们利用了存储虚拟机虚拟磁盘的共享存储。当主用或备用虚拟机想要上线时,它在共享存储上执行一个原子测试和设置操作。如果操作成功,该虚拟机被允许上线。如果操作失败,那么另一个虚拟机肯定已经上线了,所以当前的虚拟机实际上停止了自己("提交自杀")。如果虚拟机在试图进行原子操作时无法访问共享存储,那么它就会等待,直到它能够访问。请注意,如果共享存储因为存储网络的某些故障而无法访问,那么虚拟机很可能无论如何都无法做有用的工作,因为虚拟磁盘驻留在同一个共享存储上。因此,使用共享存储来解决脑裂的情况并没有引入任何额外的不可用性。
该设计的最后一个方面是,一旦发生故障,其中一个虚拟机已经上线,VMware FT就会通过在另一台主机上启动一个新的备份虚拟机来自动恢复冗余性。虽然这个过程在以前的大多数工作中都没有涉及,但它是使容错虚拟机发挥作用的基础,需要精心设计。更多细节见第3.1节。
3 FT的实际实现
第2节描述了我们对FT的基本设计和协议。然而,为了创建一个可用的、稳健的和自动的系统,还有许多其他组件必须被设计和实施。****
3.1启动和重启FT虚拟机
必须设计的最大附加组件之一是在与主虚拟机相同的状态下启动备份虚拟机的机制。这一机制也将在故障发生后重新启动备份虚拟机时使用。因此,这个机制必须可以用于处于任意状态(即不是刚启动)的运行中的主虚拟机。此外,我们希望该机制不会严重扰乱主虚拟机的执行,因为这将影响虚拟机的任何当前客户。 对于VMware FT,我们改编了VMware vSphere的现有VMotion功能。VMware VMotion[10]允许将运行中的虚拟机从一台服务器迁移到另一台服务器上,而且干扰最小--虚拟机的暂停时间通常不到一秒钟。我们创建了一种修改过的VMotion形式,在远程服务器上创建一个完全运行的虚拟机副本,但不会破坏本地服务器上的虚拟机。也就是说,我们修改后的FT VMotion将一个虚拟机克隆到远程主机上,而不是迁移它。FT VMotion还设置了一个日志通道,并使源虚拟机作为主设备进入日志模式,而目标虚拟机作为新的备份进入重放模式。与正常的VMotion一样,FT VMotion通常会中断主虚拟机的执行,时间不超过一秒钟。因此,在运行中的虚拟机上启用FT是一个简单、无干扰的操作。
启动备份虚拟机的另一个方面是选择一台服务器来运行它。容错虚拟机在一个可以访问共享存储的服务器集群中运行,因此所有虚拟机通常可以在集群中的任何服务器上运行。这种灵活性使VMware vSphere即使在一台或多台服务器发生故障时也能恢复FT冗余。VMware vSphere实现了一个维护管理和资源信息的集群服务。当故障发生时,主虚拟机现在需要一个新的备份虚拟机来重新建立冗余,主虚拟机会通知集群服务它需要一个新的备份。集群服务根据资源使用情况和其他约束条件确定运行备份虚拟机的最佳服务器,并调用FT VMotion来创建新的备份虚拟机。其结果是,VMware FT通常可以在服务器发生故障的几分钟内重新建立虚拟机冗余,而容错虚拟机的执行不会出现任何明显的中断。
3.2管理日志通道
在管理日志通道的流量方面,有许多有趣的实现细节。在我们的实现中,管理程序为主用和备用虚拟机的日志条目维护一个大的缓冲区。当主虚拟机执行时,它产生日志条目到日志缓冲区,同样,备份虚拟机从其日志缓冲区消耗日志条目。主虚拟机的日志缓冲区的内容会尽快刷新到日志通道,而日志条目一旦到达,就会从日志通道读入备份虚拟机的日志缓冲区。每次备份从网络上读取一些日志条目到其日志缓冲区时,都会向主服务器发送确认信息。这些确认允许VMware FT确定何时可以发送被输出规则延迟的输出。图3说明了这个过程。
Figure 3: FT Logging Buffers and Channel.
如果备份虚拟机在需要读取下一个日志条目时遇到一个空的日志缓冲区,它将停止执行,直到有一个新的日志条目可用。由于备份虚拟机没有进行外部通信,这种暂停不会影响虚拟机的任何客户端。同样地,如果主虚拟机在需要写一个日志条目时遇到一个满的日志缓冲区,它必须停止执行,直到日志条目可以被刷新出来。这种停止执行是一种自然的流量控制机制,当主虚拟机以过快的速度产生日志条目时,它会减慢速度。然而,这种暂停会影响到虚拟机的客户端,因为主虚拟机将完全停止,没有反应,直到它可以记录其条目并继续执行。因此,我们的实现必须被设计为尽量减少主日志缓冲区填满的可能性。主日志缓冲区可能被填满的一个原因是,备份虚拟机的执行速度太慢,因此消耗日志条目的速度太慢。一般来说,备份虚拟机必须能够以与主虚拟机记录执行的速度大致相同的速度回放执行。幸运的是,在VMware的确定性重放中,记录和重放的开销大致是一样的。然而,如果托管备份虚拟机的服务器被其他虚拟机严重加载(因此资源 overcommitted ),备份虚拟机可能无法获得足够的CPU和内存资源,无法像主虚拟机那样快速执行,尽管备份管理程序的虚拟机调度器做出了最大努力。
除了避免在日志缓冲区填满的情况下出现意外停顿外,还有一个原因是我们不希望执行滞后变得太大。如果主虚拟机发生故障,备份虚拟机必须 "迎头赶上",重新执行它在上线并开始与外部世界通信之前已经确认的所有日志条目。完成重放的时间基本上是故障点的执行滞后时间,所以备份上线的时间大致等于故障检测时间加上当前执行滞后时间。因此,我们不希望执行滞后时间很大(超过一秒),因为这将给故障转移时间增加大量时间。
因此,我们有一个额外的机制来减缓主虚拟机的速度,以防止备份虚拟机落后太远。在我们发送和确认日志条目的协议中,我们发送额外的信息,以确定主虚拟机和备份虚拟机之间的实时执行滞后。通常情况下,执行滞后小于100毫秒。如果备份虚拟机开始有明显的执行滞后(例如,超过1秒),VMware FT开始放慢主虚拟机的速度,通知调度器给它稍小的CPU数量(最初只有百分之几)。我们使用一个缓慢的反馈回路,它将尝试逐步确定主虚拟机的适当CPU限制,使备份虚拟机能够匹配其执行。如果备份虚拟机继续落后,我们就继续逐步减少主虚拟机的CPU限制。反之,如果备份虚拟机赶上了,我们就逐渐增加主虚拟机的CPU限制,直到备份虚拟机恢复到有一点滞后。
请注意,主虚拟机的这种减速是非常罕见的,通常只有在系统处于极端压力下才会发生。第5节的所有性能数字都包括任何此类减速的成本。
3.3对FT虚拟机的操作
另一个实际问题是处理可能适用于主虚拟机的各种控制操作。例如,如果主虚拟机明确关闭了电源,那么备份虚拟机也应该停止,并且不尝试上线。再比如,主虚拟机上的任何资源管理变化(如增加CPU份额)也应该应用到备份上。对于这类操作,特殊的控制条目会通过日志通道从主服务器发送到备份服务器,以便对备份服务器进行适当的操作。 一般来说,对虚拟机的大多数操作应该只在主虚拟机上启动。然后,VMware FT发送任何必要的控制条目,以在备份虚拟机上引起适当的变化。唯一可以在主虚拟机和备份虚拟机上独立完成的操作是VMotion。也就是说,主虚拟机和备份虚拟机可以独立地被VMotion到其他主机上。请注意,VMware FT确保两个虚拟机都不会被移动到其他虚拟机所在的服务器上,因为这种情况将不再提供容错。主虚拟机的VMotion比普通的VMotion增加了一些复杂性,因为备份虚拟机必须从源主虚拟机断开连接,并在适当的时间重新连接到目标主虚拟机。备份虚拟机的VMotion有一个类似的问题,但增加了额外的复杂性。 对于正常的VMotion,我们要求在VMotion的最终切换发生时,所有未完成的磁盘IO都被静态化(即完成)。对于主虚拟机来说,通过等待物理IO完成并将这些完成交付给虚拟机,这种静止是很容易处理的。但是,对于备份虚拟机来说,没有简单的方法可以使所有IO在任何需要的时间点上完成,因为备份虚拟机必须重放主虚拟机的执行,并在同一执行点上完成IO。主虚拟机可能正在运行一个工作负载,其中在正常执行期间总是有磁盘IO在飞行。VMware FT有一个独特的方法来解决这个问题。当一个备份虚拟机处于VMotion的最终切换点时,它通过日志通道请求主虚拟机暂时停止其所有IO的运行。然后,备份虚拟机的IO在复制主虚拟机执行静止操作时,自然也会在一个执行点被静止。
3.4 磁盘IO的实施问题
有一些与磁盘IO相关的微妙的实施问题。首先,鉴于磁盘操作是非阻塞的,因此可以并行执行,同时访问同一磁盘位置的磁盘操作可能导致非确定性。另外,我们对磁盘IO的实现使用DMA直接进入/离开虚拟机的内存,所以同时进行的磁盘操作访问相同的内存页也会导致非决定性。我们的解决方案通常是检测任何这样的IO race(这是很罕见的),并强制这种race性的磁盘操作以相同的方式在主机和备份上顺序执行。
其次,磁盘操作也可能与虚拟机中的应用程序(或操作系统)的内存访问发生race,因为磁盘操作通过DMA直接访问虚拟机的内存。例如,如果虚拟机中的应用程序/操作系统在读取一个内存块的同时对该块进行磁盘读取,可能会出现非决定性的结果。这种情况也不太可能,但我们必须检测到它,并在它发生时加以处理。一个解决方案是在作为磁盘操作目标的页面上临时设置页面保护。如果虚拟机碰巧访问了一个也是未完成磁盘操作的目标的页面,那么页面保护就会导致一个陷阱,虚拟机可以暂停,直到磁盘操作完成。由于改变MMU对页面的保护是一个昂贵的操作,我们选择使用反弹缓冲区。弹跳缓冲区是一个临时缓冲区,其大小与磁盘操作所访问的内存相同。一个磁盘读取操作被修改为读取指定的数据到缓冲区,而数据只在IO完成时被复制到客户内存。同样,对于磁盘写操作,要发送的数据首先被复制到缓冲区,磁盘写被修改为从缓冲区写数据。使用反弹缓冲区会减慢磁盘操作,但我们没有看到它造成任何明显的性能损失。
第三,有一些与磁盘IO有关的问题,当故障发生时,主磁盘上的IO是未完成的(i.e. not completed),而备份则接管。新晋级的主虚拟机没有办法确定磁盘IO是否已经发出或成功完成。此外,因为磁盘IO没有在备份虚拟机上从外部发出,所以在新晋升的主虚拟机继续运行时,不会有明确的IO完成,这最终会导致虚拟机中的客户操作系统启动中止或重置程序。我们可以发送一个错误完成,表明每个IO都失败了,因为即使IO成功完成,返回一个错误也是可以接受的。因为客户操作系统可能对来自其本地磁盘的错误反应不大。然而,我们在备份虚拟机的上线过程中重新发出待定IO。因为我们已经消除了所有的race,而且所有的IO都直接指定访问哪些内存和磁盘块,所以这些磁盘操作即使已经成功完成,也可以重新发布(即它们是等效的)。
3.5 网络IO的实施问题
VMware vSphere 为虚拟机网络提供了许多性能优化。其中一些优化是基于管理程序异步更新虚拟机的网络设备的状态。例如,接收缓冲区可以在虚拟机执行时由管理程序直接更新。不幸的是,这些对虚拟机状态的异步更新增加了非确定性。除非我们能保证所有的更新都发生在主程序和备份程序的指令流中的同一个点上,否则备份程序的执行可能会与主程序的执行发生分歧。 对FT的网络仿真代码最大的改变是禁用异步网络优化。用传入的数据包异步更新虚拟机环形缓冲区的代码已被修改,以迫使客户向管理程序进行捕获,在那里它可以记录更新,然后将其应用于虚拟机。同样,通常从传输队列中异步拉出数据包的代码在FT中被禁用,而是通过向管理程序发出陷阱来完成传输(下文指出的情况除外)。 消除网络设备的异步更新与第2.2节中描述的发送数据包的延迟相结合,为网络提供了一些性能挑战。我们已经采取了两种方法来改善运行FT时的虚拟机网络性能。首先,我们实施了集群优化,以减少虚拟机的陷阱和中断。当虚拟机以足够的比特率进行数据流时,管理程序可以对每组数据包进行一次传输陷阱,在最好的情况下,陷阱为零,因为它可以将数据包作为接收新数据包的一部分进行传输。同样,管理程序可以通过只发布一组数据包的中断来减少对虚拟机传入数据包的中断次数。
我们对网络的第二个性能优化涉及减少传输数据包的延迟。如前所述,管理程序必须延迟所有传输的数据包,直到它从备份那里得到适当的日志条目的确认。减少传输延迟的关键是减少向备份发送日志信息并获得确认的时间。我们在这方面的主要优化涉及确保发送和接收日志条目和确认都可以在没有任何线程上下文切换的情况下完成。VMware vSphere管理程序允许在TCP堆栈中注册一些函数,每当收到TCP数据时,这些函数就会从一个延迟执行的上下文(类似于Linux中的tasklet)中被调用。这可以使我们能够快速处理备份上的任何传入的日志消息和主虚拟机收到的任何确认,而无需任何线程上下文切换。此外,当主虚拟机排队等待传输数据包时,我们通过调度一个延迟执行的上下文来强迫立即对相关的输出日志条目进行日志刷新(如第2.2节所述)。
4.设计方案
在我们实现VMware FT的过程中,我们已经探索了一些有趣的设计方案。在本节中,我们将探讨其中的一些替代方案。
4.1共享vs非共享磁盘
在我们的默认设计中,主虚拟机和备份虚拟机共享相同的虚拟磁盘。因此,共享磁盘的内容自然是正确的,并且在发生故障切换时可以使用。从本质上讲,共享磁盘被认为是主用和备用虚拟机的外部,所以任何对共享磁盘的写入都被认为是对外部世界的通信。因此,只有主虚拟机对磁盘进行实际写入,而对共享磁盘的写入必须根据输出规则进行延迟。
另一种设计是主虚拟机和备份虚拟机拥有独立的(非共享的)虚拟磁盘。在这种设计中,备份虚拟机确实对其虚拟磁盘进行了所有的磁盘写入,在这样做的过程中,它自然会使其虚拟磁盘的内容与主虚拟机的虚拟磁盘的内容保持同步。图4说明了这种配置。在非共享磁盘的情况下,虚拟磁盘基本上被认为是每个虚拟机的内部状态的一部分。因此,根据输出规则,主磁盘的写入不需要延迟。非共享设计在主虚拟机和备份虚拟机无法访问共享存储的情况下相当有用。这种情况可能是因为共享存储不可用或太贵,或者因为运行主用和备用虚拟机的服务器相距甚远("远距离FT")。非共享设计的一个缺点是,在首次启用容错时,必须以某种方式明确同步虚拟磁盘的两个副本。此外,磁盘在故障后可能会失去同步,因此在故障后重新启动备份虚拟机时,必须明确地重新同步它们。也就是说,FT VMotion不仅要同步主用和备份虚拟机的运行状态,而且还要同步它们的磁盘状态。
在非共享磁盘配置中,可能没有共享存储可用于处理脑裂的情况。在这种情况下,系统可以使用一些其他的外部分割器,比如两个服务器都可以对话的第三方服务器。如果服务器是一个有两个以上节点的集群的一部分,系统可以替代性地使用基于集群成员的多数算法。在这种情况下,只有当一个虚拟机运行在一个包含大多数原始节点的通信子集群的服务器上时,它才会被允许上线。
Figure 4: FT Non-shared Disk Configuration.
4.2 在备份虚拟机上执行磁盘读取操作
在我们的默认设计中,备份虚拟机从不从其虚拟磁盘(无论是共享还是非共享的)中读取数据。由于磁盘读取被认为是一种输入,所以自然会通过日志通道将磁盘读取的结果发送给备份虚拟机。另一种设计是让备份虚拟机执行磁盘读取,从而消除磁盘读取数据的日志记录。对于进行大量磁盘读取的工作负载,这种方法可以大大减少日志通道上的流量。然而,这种方法有许多微妙之处。它可能会减慢备份虚拟机的执行速度,因为备份虚拟机必须执行所有的磁盘读取,如果它们在到达虚拟机执行过程中在主服务器上完成的时候还没有物理上的完成,则必须等待。 另外,必须做一些额外的工作来处理失败的磁盘读取操作。如果主磁盘读取成功,但备份的相应磁盘读取失败,那么备份的磁盘读取必须重试,直到它成功,因为备份必须在内存中获得与主磁盘相同的数据。相反,如果主磁盘读取失败,那么目标内存的内容必须通过日志通道发送给备份,因为内存的内容将是不确定的,不一定会被备份虚拟机的成功磁盘读取复制。 最后,如果这种磁盘读取方式与共享磁盘配置一起使用,还有一个微妙的问题。如果主虚拟机对某一特定磁盘位置进行了读取,随后相当快地对同一磁盘位置进行了写入,那么磁盘写入必须延迟到备份虚拟机执行了第一次磁盘读取之后。这种依赖性可以被正确检测和处理,但会给实现增加额外的复杂性。在第5.1节中,我们给出了一些性能结果,表明在备份上执行磁盘读取会导致实际应用的吞吐量略有下降(1-4%),但也会明显地减少日志带宽。因此,在备份虚拟机上执行磁盘读取,在日志通道的带宽相当有限的情况下,可能是有用的。
5. PERFORMANCE EVALUATION
在本节中,我们对VMware FT在一些应用工作负载和网络基准方面的性能做了基本评估。对于这些结果,我们在相同的服务器上运行主虚拟机和备份虚拟机,每台服务器有8个英特尔至强2.8Ghz CPU和8G字节的内存。这些服务器通过一个10Gbit/s的交叉网络连接,尽管在所有情况下都会看到,使用的网络带宽远低于1Gbit/s。两台服务器通过一个标准的4Gbit/s光纤通道网络连接的EMC Clariion访问它们的共享虚拟磁盘。用于驱动一些工作负载的客户端通过1 Gbit/s网络与服务器相连。
我们在性能结果中评估的应用程序如下。SPECJbb2005是一个行业标准的Java应用基准,它的CPU和内存都非常密集,并且很少进行IO。内核编译是一个运行Linux内核编译的工作负载。这个工作负载进行一些磁盘读写,并且由于许多编译过程的创建和销毁,CPU和MMU都非常密集。Oracle Swingbench是一个工作负载,其中Oracle 11g数据库由Swingbench OLTP(在线交易处理)工作负载驱动。这个工作负载做了大量的磁盘和网络IO,并且有80个同步的数据库会话。MS-SQL DVD Store是一个工作负载,其中一个Microsoft SQL Server 2005数据库由DVD Store基准驱动,它有16个同步客户端。
5.1 基本的性能结果
表1给出了基本性能结果。对于列出的每个应用,第二栏给出了在运行服务器工作负载的虚拟机上启用FT时该应用的性能与在同一虚拟机上未启用FT时的性能的比率。性能比的计算方法是,数值小于1表示FT工作负载的速度较慢。显然,在这些代表性工作负载上启用FT的开销低于10%。SPECJbb2005是完全计算的,没有空闲时间,但表现良好,因为它除了定时器中断外,非确定性事件极少。其他工作负载做磁盘IO,有一些空闲时间,所以一些FT的开销可能被FT虚拟机的空闲时间较少的事实所掩盖。然而,总的结论是,VMware FT能够以相当低的性能开销支持容错虚拟机。 在表格的第三列,我们给出了这些应用运行时在日志通道上发送的数据的平均带宽。对于这些应用来说,日志带宽是相当合理的,1 Gbit/s的网络可以轻松满足。事实上,低带宽要求表明,多个FT工作负载可以共享同一个1 Gbit/s网络,而不会对性能产生任何负面影响。
(FT / non-FT)
bandwidth
SPECJbb2005
0.98
1.5 Mbits/sec
Kernel Compile
0.95
3.0 Mbits/sec
Oracle Swingbench
0.99
12 Mbits/sec
MS-SQL DVD Store
0.94
18 Mbits/sec
Table 1: Basic Performance Results
对于运行Linux和Windows等常见客户操作系统的虚拟机,我们发现,客户操作系统空闲时的典型记录带宽为0.5-1.5 Mbits/sec。这个 "空闲 "带宽主要是记录定时器中断交付的结果。对于一个有活动工作负载的虚拟机来说,日志带宽被必须发送到备份的网络和磁盘输入所支配--接收的网络数据包和从磁盘上读取的磁盘块。因此,对于那些具有非常高的网络接收或磁盘读取带宽的应用,日志带宽可能远远高于表1中测量的带宽。对于这类应用,日志通道的带宽可能是一个瓶颈,特别是当日志通道还有其他用途时。 许多实际应用在日志通道上所需的带宽相对较低,这使得基于重放的容错对于使用非共享磁盘的长距离配置非常有吸引力。对于主用和备用可能相隔1-100公里的长距离配置,光纤可以很容易地支持100-1000Mbit/s的带宽,延迟小于10毫秒。对于表1中的应用,100-1000Mbit/s的带宽应该足以实现良好的性能。但是,请注意,主备之间的额外往返延迟可能会导致网络和磁盘输出延迟达20毫秒。长途配置只适合于那些客户能够容忍每个请求的额外延迟的应用。 对于两个磁盘密集型的应用,我们测量了在备份虚拟机上执行磁盘读取(如第4.2节所述)与通过日志通道发送磁盘读取数据的性能影响。对于Oracle Swingbench来说,在备份虚拟机上执行磁盘读取时,吞吐量降低了大约4%;对于MS-SQL DVD Store来说,吞吐量降低了大约1%。同时,Oracle Swingbench的日志带宽从12Mbits/sec下降到3Mbits/sec,而MS-SQL DVD Store的日志带宽从18Mbits/sec下降到8Mbits/sec。显然,对于具有更大磁盘读取带宽的应用来说,节省的带宽可能要大得多。如第4.2节所述,当磁盘读取在备份虚拟机上执行时,预计性能可能会差一些。然而,对于日志通道带宽有限的情况(例如,长距离配置),在备份虚拟机上执行磁盘读取可能是有用的。
5.2 网络基准
由于一些原因,网络基准测试对我们的系统来说是相当具有挑战性的。首先,高速网络会有非常高的中断率,这就要求以非常高的速率记录和重放异步事件。第二,以高速度接收数据包的基准将导致高速度的日志流量,因为所有这些数据包必须通过日志通道发送到备份。第三,发送数据包的基准将受制于输出规则,该规则将延迟网络数据包的发送,直到收到来自备份的适当确认。这种延迟将增加对客户端的测量延迟。这种延迟也可能减少客户端的网络带宽,因为网络协议(如TCP)可能不得不随着往返延迟的增加而降低网络传输速率。
表2给出了我们对标准netperf基准的一些测量结果。在所有这些测量中,客户虚拟机和主虚拟机通过1 Gbit/s网络连接。前两行给出了主用和备用主机通过1Gbit/s的记录通道连接时的发送和接收性能。第三行和第四行给出了主服务器和备份服务器通过10Gbit/s日志通道连接时的发送和接收性能,该通道不仅有更高的带宽,而且比1Gbit/s网络的延迟更低。作为一个粗略的衡量标准,1Gbit/s连接的hypervisor之间的ping时间约为150微秒,而10Gbit/s连接的ping时间约为90微秒。
当未启用FT时,主虚拟机可以实现接近(940 Mbit/s)的1 Gbit/s线路速率的传输和接收。当为接收工作负载启用FT时,日志带宽非常大,因为所有进入的网络数据包都必须在日志通道上发送。因此,日志通道可能成为一个瓶颈,如1 Gbit/s日志网络的结果所示。对于10Gbit/s的日志网络,这种影响要小得多。当FT为传输工作负载启用时,传输数据包的数据不被记录,但网络中断仍然必须被记录。记录带宽要低得多,所以可实现的网络传输带宽要高于网络接收带宽。总的来说,我们看到FT可以在非常高的发送和接收速率下大大限制网络带宽,但高的绝对速率仍然可以实现。
bandwidth
bandwidth
bandwidth
Receive (1Gb)
940
604
730
Transmit (1Gb)
940
855
42
Receive (10Gb)
940
860
990
Transmit (10Gb)
940
935
60
Table 2: Performance of Network Transmit and Receive to a Client (all in Mbit/s) for 1Gb and 10Gb Logging Channels
6.相关的工作
Bressoud和Schneider[3]描述了通过完全包含在管理程序级别的软件来实现虚拟机的容错的最初想法。他们通过HP PA-RISC处理器的服务器原型,证明了使备份虚拟机与主虚拟机保持同步的可行性。然而,由于PA-RISC架构的限制,他们无法实现完全安全、隔离的虚拟机。而且,他们没有实现任何故障检测方法,也没有试图解决第3节中描述的任何实际问题。更重要的是,他们对其FT协议施加了一些不必要的限制。首先,他们强加了一个纪元的概念,即异步事件被延迟到一个设定的时间间隔结束。纪元的概念是不必要的--他们强加这个概念可能是因为他们无法足够有效地重放单个异步事件。其次,他们要求主虚拟机基本上停止执行,直到备份收到并确认所有先前的日志条目。然而,只有输出本身(如网络数据包)必须被延迟 - 主虚拟机本身可以继续执行。
Bressoud[4]描述了一个在操作系统(Unixware)中实现容错的系统,因此为运行在该操作系统上的所有应用程序提供了容错。系统调用接口成为必须确定地复制的操作集。这项工作与基于管理程序的工作有类似的限制和设计选择。
Napper等人[9]和Friedman和Kama[7]描述了容错的Java虚拟机的实现。他们遵循与我们类似的设计,在日志通道上发送关于输入和非确定性操作的信息。与Bressoud一样,他们似乎没有把重点放在检测故障和故障后重新建立容错上。此外,他们的实现仅限于为运行在Java虚拟机中的应用程序提供容错。这些系统试图处理多线程的Java应用程序的问题,但要求所有的数据都被锁正确保护,或者在访问共享内存时强制执行序列化。
Dunlap等人[6]描述了一个针对在准虚拟化系统上调试应用软件的确定性重放的实现。我们的工作支持在虚拟机内运行的任意操作系统,并为这些虚拟机实现容错支持,这需要更高水平的稳定性和性能。
Cully等人[5]描述了支持容错虚拟机的另一种方法及其在一个名为Remus的项目中的实现。通过这种方法,主虚拟机的状态在执行过程中被反复检查,并被发送到一个备份服务器,该服务器收集检查点信息。检查点必须非常频繁地执行(每秒多次),因为外部输出必须延迟到下一个检查点被发送和确认。这种方法的优点是,它同样适用于单处理器和多处理器的虚拟机。主要问题是,这种方法对网络带宽的要求非常高,以便在每个检查点发送内存状态的增量变化。在[5]中介绍的Remus的结果显示,当试图使用1Gbit/s的网络连接来传输内存状态的变化时,内核编译和SPECweb基准测试的速度降低了100%到225%。有一些优化措施可能有助于减少所需的网络带宽,但目前还不清楚是否可以用1Gbit/s的连接实现合理的性能。相比之下,我们基于确定性重放的方法可以实现不到10%的开销,在几个实际应用中,主主机和备份主机之间需要的带宽不到20Mbit/s。
7.结论和未来工作
我们在VMware vSphere中设计并实现了一个高效、完整的系统,为集群中服务器上运行的虚拟机提供了容错(FT)。我们的设计是基于使用VMware确定性重放,通过另一台主机上的备份虚拟机来复制主虚拟机的执行。如果运行主虚拟机的服务器发生故障,备份虚拟机会立即接管,不会出现中断或数据丢失。
总的来说,在商品硬件上的VMware FT下的容错虚拟机的性能是非常好的,对于一些典型的应用,显示出不到10%的开销。VMware FT的大部分性能成本来自于使用VMware确定性重放以保持主用和备用虚拟机同步的开销。因此,VMware FT的低开销来自于VMware确定性重放的效率。此外,保持主备同步所需的日志带宽通常相当小,通常低于20 Mbit/s。因为在大多数情况下,日志带宽相当小,所以实现主用和备用虚拟机相隔很远(1-100公里)的配置似乎是可行的。因此,VMware FT可用于同时保护整个站点发生故障的灾难的场景中。值得注意的是,日志流通常是相当可压缩的,简单的压缩技术可以在少量的额外CPU开销下大大降低日志带宽。
我们对VMware FT的研究结果表明,容错虚拟机的有效实施可以建立在确定性的重放之上。这样的系统可以以最小的开销为运行任何操作系统和应用程序的虚拟机透明地提供容错。然而,为了使容错虚拟机系统对客户有用,它还必须是强大的、易于使用的和高度自动化的。一个可用的系统除了虚拟机的复制执行外,还需要许多其他组件。特别是,VMware FT在发生故障后会自动恢复冗余,方法是在本地集群中找到一个合适的服务器,并在该服务器上创建一个新的备份虚拟机。通过解决所有必要的问题,我们已经展示了一个可用于客户数据中心的实际应用的系统。
通过确定性重放实现容错的一个权衡因素是,目前确定性重放只在单处理器虚拟机上有效实现。然而,单处理器虚拟机对于各种工作负载来说是绰绰有余的,尤其是在物理处理器不断增强的情况下。此外,许多工作负载可以通过使用许多单处理器虚拟机来扩展,而不是通过使用一个更大的多处理器虚拟机来扩大规模。多处理器虚拟机的高性能重放是一个活跃的研究领域,有可能通过微处理器的一些额外硬件支持实现。一个有趣的方向可能是扩展事务性内存模型以促进多处理器重放。
在未来,我们也有兴趣扩展我们的系统以处理部分硬件故障。所谓部分硬件故障,我们指的是服务器中部分功能或冗余的损失,但不会导致数据的损坏或丢失。一个例子是虚拟机的所有网络连接的损失,或者物理服务器中的冗余电源的损失。如果运行主虚拟机的服务器发生部分硬件故障,在许多情况下(但不是全部),立即故障转移到备份虚拟机是有利的。这样的故障切换可以立即恢复关键虚拟机的全部服务,并确保虚拟机迅速从可能不可靠的服务器上移开。
Last updated