vm-ft


摘要(Abstract)

我们已经实现了一个基于容错虚拟机的商业化企业级系统,该系统通过运行在不同服务器上的备份虚拟机,将主虚拟机的运行情况进行了“复制”。我们已经在虚拟环境上设计了一个完整易上手的系统,它运行在商用服务器上,仅仅减少了真实应用不到10%的性能。此外,对于绝大多数真实应用,为了保证主从虚拟机运行协调,数据带宽不能超过20Mbit/s,这使得远距离实现容错成为了可能。一个容易使用的、能够在发生错误后自动地恢复冗余的商用系统需要许多额外运行在VM上的组件。我们已经设计并实现了这些额外的组件,并处理在使得VM能够支持运行企业级应用时所遇到的许多问题。在这篇论文中,我们描述了我们的基本设计,讨论了替代设计选项,以及一些实现细节,还提供了若干方面和真实应用的性能数据。

1、介绍(Introduction)

一个实现容错服务器的常见方法是主从复制,从属服务器总能够在主服务器出现错误的时候,及时地接管工作。从属服务器的状态必须一直与主服务器保持几乎一致,这样当主服务器退出的时候,从属服务器才能立即接管工作,让主服务器发生的错误对外部的用户不可见,并且不丢失数据。在从属服务器上复制主服务器状态的一个方法是连续不断地传输所有主服务器状态的变化给自己,包括CPU,存储,I/O设备。然而,这样要求传输的带宽会很高,尤其是在传输存储相关的状态变化的时候。

另外一个能够使用较少的带宽复制服务器的方法是状态机方法。状态机方法将服务器建模成确定性状态机,在启动是时候保证初始状态相同,以及之后它们收到相同顺序的相同输入请求,那么它们就能够保持同步。然而,绝大多数服务器或者设备都有一些不确定性操作,所以必须要使用额外的协作来保证主从同步。尽管如此,额外需要保持的信息也比状态机本身的状态更新信息要小得多。

实现能够确保物理服务器的确定性运行的协作是十分困难的,尤其是在处理器频率增加的情况下。与之对照的是,虚拟机运行在虚拟监视器上,是一个非常好的平台来实现状态机方法。一个VM其实是一个well_defined 的状态机,它的操作都是实际被虚拟化的物理机器的操作。和物理服务器一样,虚拟机有一些不确定性操作,所以额外的写作信息必须要发送给从属服务器以确保双方同步。因为虚拟监视器完全掌控着虚拟机的运行,包括输入的传递。所以一个虚拟监视器能够捕捉主VM上所有关于非确定性操作的必要信息,并且能够在从属VM上重新正确实现这些操作。

因此,状态机方法可以通过在商用硬件上运行虚拟机来实现,而无需硬件级别的特殊修正,并且允许在最新的微处理器上也能实现(容错)。此外,低带宽使得状态机方法让主从服务器物理隔离很远成为了可能。比如说,被复制的虚拟机们可以运行在分布在整个校园的物理机上,而不是仅仅分布在一座大楼里。

我们已经在Vmware vSphere 4.0上实现了基于状态机的容错虚拟机,该容错虚拟机是x86虚拟机。因为Vmware vSphere 实现了一个完整的 x86 虚拟机,我们自动地能够提供容错服务给所有的x86架构的应用和系统。允许我们记录主VM运行并确保从属VM能够以一致运行的技术是**确定性重放(Deterministic Replay)**。Vmware vSphere Fault Tolerance 基于确定性replay,但是添加了额外必须的协议以及功能来支持建立一个完整的容错系统。除了提供硬件容错,我们的系统在一次失败后,通过在局部集群中任何可接受的服务器上开始一个新的备份虚拟机,进行自动地存储备份。到目前为止,确定性重放和Vmware FT的产品版本 只支持 单处理器VMs。多处理器VM的操作记录和重放还在开发中,因为每个共享内存的操作都是一个非确定性的操作,因此还有重要的性能问题待解决。

Bressoud 和 Schneiderr 描述了一个协议版本 的HP PA-RISC平台上容错虚拟机的实现。我们的方法是相似的,但是我们因为性能原因进行了一些底层改变,并尝试了大量的替代设计。此外,我们已经在系统中设计并实现许多额外组件并且处理了大量的实际问题来建立完整、高效、能够运行企业级应用的系统。和许多物理系统类似的是,我们仅仅尝试处理fail-stop类型的服务器错误,这类错误能够在服务器做出外部可见的错误之前被系统察觉到。

Fail-stop failures(故障停止)是指在计算机系统中,当某个组件发生故障时,系统能够停止该组件的运行,以避免错误的输出或行为。也就是说,当发生故障时,系统会立即停止运行,并且不会继续执行任何操作,以防止出现更严重的问题。

这种类型的故障通常是由硬件故障或软件错误引起的。当硬件组件发生故障时,例如内存或CPU,系统会立即停止运行以避免出现错误的计算结果。同样,当软件组件出现故障时,例如操作系统或应用程序,系统也会立即停止运行以防止出现更多的错误。

在分布式系统中,Fail-stop failures 是指当节点发生故障时,该节点完全停止工作,不再发送或接收任何消息或请求,以避免系统中的其他节点出现不一致的状态。

本文剩余部分主要内容如下。首先,我们描述了 VM-FT的基本设计和基本协议的细节,这些设计和协议确保了如果一个从属VM从主服务器发生错误后进行接管,将不会导致数据损失。而后,我们描述了许多必须要处理的实际问题。此外,我们也阐述了多种实现VM-FT的设计选择,并对这些选择进行了相关讨论。然后,我们给出了我们实现的系统在一些实际企业应用上的性能数据。最后,我们阐述了相关工作和结论。

2、基本的FT设计(Basic FT Design)

图一展示了VM-FT系统的基本设置。对于某个希望能够支持容错的VM(主VM),我们在另外一个物理机上运行从属VM,该从属VM与主VM保持同步,并且相比主VM能够同步地运行着,尽管会有些时延。我们把这叫做虚拟同步。VMs的虚拟硬盘都是建立在共享存储上的(例如一个Fibre Channel或者iSCSI磁盘阵列),因此可以接受主备服务器的输入和输出。(我们将在4.1节中讨论带有分隔的非共享虚拟磁盘的主备VM的设计) 只有主VM在网络中宣告自己的存在,所以所有的网络输入都会去往主VM,相似的,所有的其他输入(例如键盘和鼠标)也仅仅是去往主VM。

所有主VM接收到的输入都会通过名为logging channel的网络连接,被发送到备份VM上。对于服务器负载而言,主要的输入瓶颈是网络和磁盘。为了保证备份VM和主VM使用相同的方式执行非确定性操作,下面2.1节讨论的额外的信息也需要发送。结果备份VM总是执行和主VM一致的操作。然而,备份VM的输出会被管理程序扔掉,因此只有主VM产生实际输出,并被返回给客户端。和2.2节中描述的一样,为了确保主VM失败后没有数据丢失,主备VM遵循一个具体的协议,包括备份VM明确的确认信息。

为了检测主、从属VM是否出现故障,我们的系统在相关的服务器间使用了心跳通信,并且监视了logging channel 上的网络情况(是否发送网络拥堵)。此外,我们必须确保仅有一台主或者从属VM接管运行,即使存在脑裂(split brain)的场景,在这种场景中主备服务器互相之间会失去通信。

在下面的小节中,我们在几个重要的方面提供更多的细节。在2.1节中,我们给出一些确定性重放技术的细节,保证主备VMs通过 logging channel 上的信息保持一致。在2.2节中,我们描述了我们的FT协议中的一个基础规则,保证了主VM失败后没有数据丢失。在2.3节中,我们描述我们的方法,它能够通过正确的方式检测及响应故障。

2.1、确定性重放实现(Deterministic Replay Implementation)

正如我们所提到的,复制服务器运行 可以被抽象成 复制一个确定性状态机。如果两个确定性状态机开始在相同状态,之后它们经历相同的状态序列,将产生相同的输出序列。一个虚拟机有着各种形式的输入,包括网络数据包,硬盘读取的数据,来自键盘和数据的数据等。不确定性事件(比如虚拟中断)以及不确定性操作(比如读取cpu 的时钟计数器)也会影响VM的状态。这揭示了复制任何运行任何操作系统和工作负载的VM的运行,都需要面临三大挑战:(1) 正确地捕捉所有输入和必要的不确定性行为来保证从属VM的确定性运行。(2) 正确地把输入和必要的不确定行为应用到从属VM上。(3) 以不影响性能的前提下实现(1)(2)。除了这三点以外,许多在x86微处理器上复杂的操作都有未定义的边际影响。捕捉这些边际影响并重现它们,来达到相同的状态(对于从属VM而言),仍然是一个挑战。

针对在VMare vSphere平台上的x86虚拟机,VMware确定性地重放恰好提供了这个功能。确定性重放记录了 VM 的输入以及与 VM执行相关的所有可能的不确定性的日志条目流,这些条目会被写入日志文件。在读取日志文件中的条目后,VM 操作会被精确地重放。 对于非确定性操作,为了允许操作以相同的状态变化和输出再现,需要记录足够的信息。 对于非确定性事件,例如定时器或 IO 完成中断,事件发生的确切指令也会被记录下来。 在重播期间,事件被传递在指令流中的同一位置。 VMware 确定性重放采用各种技术,实现了高效的事件记录和事件传递机制,包括使用AMD [2] 和英特尔 [8] 联合开发的硬件性能计数器。

Bressoud 和 Schneider [3] 提到将VM执行切分成不同的时期(epoch),其中非确定性事件,例如中断仅在一个epoch结束时传递。 epoch的概念似乎被用作批处理机制,因为在它发生的确切指令处单独传递每个中断的成本太高。然而,我们的事件传递机制足够高效,以至于 VMware确定性重放不需要使用epochs。 每次中断在发生时被记录,并且在重放时有效地传递到适当的指令处。

2.2、FT协议(FT Protocol)

对于 VMware FT而言,我们使用确定性重放来生成必要的日志条目来记录主VM的执行情况,但是不是将日志条目写入磁盘,而是通过日志通道将它们发送到备份 VM。备份 VM 实时重放日志条目,因此与主 VM 的执行保持一致。 然而,我们必须在日志通道中使用严格的 FT 协议以增强日志条目,从而确保我们实现容错。 我们的基本要求如下:

输出要求:如果备份VM在主VM发生故障后接管,那么备份VM将继续以一种与主虚拟机发送到外部世界的所有输出完全一致的方式执行。

请注意,在发生故障转移后(即备份 VM 需要在主VM故障后接管),备份VM开始执行的方式可能与主 VM 相当不同,因为在执行期间发生了许多非确定性事件。但是,只要备份VM满足输出要求,在故障转移到备份 VM期间没有外部可见状态或数据的丢失,客户端将注意到他们的服务没有中断或不一致。

可以通过延迟任何外部输出(通常是网络数据包)直到备份VM 已收到重放的所有信息来确保输出要求,这些信息允许它至少执行到该输出操作的点。一个必要条件是备份 VM 必须接收到输出操作之前生成的所有日志条目。这些日志条目将允许它执行到最后一个日志条目的点。但是,假设失败是在主VM执行输出操作后立即发生。备份 VM 必须知道它必须继续重播到输出操作点,并且到那时只能“上线”(停止重播并作为主VM接管,如2.3 节所述)。如果备份将在输出操作之前的最后一个日志条目点上线,一些非确定性事件(例如计时器传递给 VM 的中断)可能会在执行输出操作之前改变其执行路径。

给定上述的限制,强制满足输入要求的最容易的方式是在每个输出操作时创建一个特殊的日志条目。然后,输入要求一定被下面特殊的规则限制:

输出规则:主VM可能不发送一个输出到外部世界,直到备份VM 已收到并确认与产生输出的操作相关的日志条目。

如果备份 VM 已收到所有日志条目,包括生成输出操作的日志条目,然后备份 VM 将能够准确地重现主 VM在输出点的状态,所以如果主VM死了,备份将正确地达到一个与输出一致的状态。相反,如果备份 VM在没有收到所有必要的日志条目的情况下接管,那么它的状态可能会迅速分歧,以至于与主服务器的输出不一致。输出规则在某些方面类似于 [11] 中描述的方法,其中“外部同步” IO 实际上可以被缓存,只要它在下一次外部通信之前确实被写入磁盘了。

请注意,输出规则没有说明关于停止主VM执行的任何事。我们只需要延迟输出发送,但 VM 本身可以继续执行。由于操作系统通过异步中断来指示完成,因此可以执行非阻塞的网络和磁盘输出,VM可以轻松地继续执行并且不一定会立即受到输出延迟的影响。相比之下,以前的工作 [3, 9] 通常必须在执行输出之前完全停止主VM,直到备份 VM 已确认来自主 VM 的所有必要信息。

作为一个例子,我们在图2中展示了 FT 协议的需求。该图显示了一个主VM和备份VM上的事件时间线。从主线到备份线的箭头表示日志条目的传输,从备份线路到主线路的箭头表示确认。有关异步事件、输入和输出操作的信息必须作为日志条目发送到备份VM并确认。如图所示,到外部世界的输出被延迟,直到主VM收到来自备份 VM 的确认,它已经收到与输出操作相关的日志条目。鉴于遵循输出规则,备份VM将能够以这样一种状态接管,即与主VM最后的输出一致。

我们不能保证一旦出现故障转移情况,所有输出都准确地产生一次。当主VM打算发送输出时,没有使用两阶段提交事务,备份VM无法确定主VM是在发送它的最后一个输出之前还是之后立即崩溃。 幸运的是,网络基础设施(包括常用的TCP)旨在处理丢失的数据包和相同(重复)的数据包。 请注意传入到主VM的数据包也可能在其故障的期间丢失,因此不会被传递给备份VM。 但是,传入的数据包可能会由于与服务器故障无关的任何原因被丢弃,因此网络基础设施、操作系统和应用程序都被写入,以确保他们可以弥补丢失的数据包。

2.3、检测与故障响应(Detecting and Responding to Failure)

如上所述,如果另一个 VM 出现故障,主备VMs必须快速响应。如果备份VM出现故障,主VM将上线,即离开记录模式(因此停止发送条目到日志通道)并开始正常执行。如果主VM失败,备份VM应该同样上线(go live),但过程更为复杂。由于其执行的滞后,备份 VM 可能会有许多它已收到并确认,但尚未消耗的日志条目,因为备份 VM 尚未达到执行的适当点。备份VM必须继续重放日志条目,直到它消耗了最后一个日志条目。此时,备份 VM 将停止重放模式并开始作为正常VM执行。本质上备份VM被提升为主VM(现在缺少备份VM)。由于它不再是备份 VM,当操作系统执行输出操作时,新的主VM现在将向外部世界生产输出。在过渡到正常模式期间,可能会有一些特定设备的操作需要允许正确地发送输出。特别是,出于联网目的,VMware FT 自动在网络上通告新的主VM的MAC 地址,以便物理网络交换机知道新的主 VM 所在的服务器。此外,新提升的主VM可能需要重做一些磁盘 IO(如第 3.4 节所述)。

有许多可能的方法来尝试检测主备VMs的故障。VMware FT在运行容错VMs的服务器之间使用 UDP心跳,来检测服务器何时崩溃。此外,VMware FT 监控日志流量,包括从主到备的发送以及从备到主的确认。因为定时器中断,日志流量应该是有规律的,并且永远不会停止。因此,在日志条目或确认流中的中断可能表明VM故障。如果心跳或记录流量已停止超过特定超时时间(大约几秒钟),就可能发生故障了。

但是,任何此类故障检测方法都容易受到脑裂(split brain)问题的影响。如果备份服务器停止接收来自主服务器的心跳,这可能表明主服务器出现故障,或者可能只是意味着所有仍在运行的服务器之间的网络连接丢失。如果备份VM随后上线,而主VM也仍然在运行,对于与VM通信的客户端而言可能会有数据损坏以及其他问题。因此,我们必须确保当检测到故障时,主VM和备份VM只有一个在线。为了避免脑裂问题,我们利用共享存储,来存储VM的虚拟磁盘。 当任一主或备份VM想要上线时,它会在共享存储中执行一个原子性的测试设置操作。 如果操作成功,VM 被允许上线。 如果操作失败,那么另一个 VM 一定已经上线,所以当前虚拟机实际上停止了自己(“自杀”)。 如果尝试执行此原子操作时,VM 无法访问共享存储,然后它只是等待,直到可以访问。 注意如果由于存储网络上的某些故障而无法访问共享存储时,那么虚拟机可能无法做有用的工作,因为虚拟磁盘在同样的共享存储中,因此,为了解决脑裂问题而使用共享存储不会引入任何额外的不可接受性。(注:使用共享存储这种解决方案本身使得主备又得以通信了,只不过是通过信号量,而非socket。

这个设计的一个最终方面是一旦故障发生并且一个VM已经上线,VMware FT自动地通过在另一个主机上开始一个新的备份VM,来恢复备份。虽然这个过程不能覆盖过去大部分的工作,但是对容错的VM有用,它是基础,需要仔细设计。 更多细节是在第 3.1 节中给出。

3、FT的实际执行(Practical Implementation Of FT)

第二节描述了我们基础的设计以及FT协议。然而,为了创建一个有用的、健壮的以及自动化的系统,有许多其他组件必须设计实现。

3.1、启动与重启 FT VMs(Starting and Restarting FT VMs)

对于 VMware FT而言,我们调整了VMware vSphere上现有的 VMotion 功能。 VMware VMotion [10] 允许以最少中断的方式,将正在运行的 VM 从一台服务器迁移到另一台服务器,VM的暂停时间通常不到一秒钟。我们创建了一个VMotion的修改形式,可在远程服务器上创建准确的 VM 运行副本,但不会破坏本地服务器的虚拟机。也就是说,我们修改后的 FT VMotion 将VM克隆到远程主机上而不是迁移它。 FT VMotion还设置了一个日志记录通道,并导致源VM作为主VM进入日志记录模式,而目的VM 作为备份进入重放模式。像平常的VMotion一样,FT VMotion 通常会中断主VM的执行不到一秒。因此,启用 FT在正在运行的 VM 上是一个简单的、无中断的操作。

启动备份 VM 的另一个方面是选择一个运行它的服务器。容错 VM 在服务器集群中运行,可以访问共享存储,因此所有 VM通常可以运行在集群上的任何服务器中。这种灵活性允许VMware vSphere恢复FT冗余,即使一个或多个服务器失效。VMware vSphere 实现了一种集群服务,用于维护管理以及资源信息。 当发生故障并且主VM 现在需要一个新的备份 VM 来重新建立冗余时,主 VM 通知集群服务它需要一个新的备份。 集群服务基于资源利用率以及其他约束,决定运行备份VM最好的服务器,并调用 FT VMotion 以创建新的备份 VM。 结果是 VMware FT通常可以在几分钟内重新建立VM冗余,在一个容错VM的执行上,所有这些都没有任何明显的中断。

3.2、管理日志通道(Managing the Logging Channel)

在管理日志通道上的流量时,有许多有趣的实现细节。在我们的实现中,管理程序为主备 VM 的日志记录条目维持了一个大的缓冲区。当主 VM 执行时,它生成日志条目到缓冲区中,类似地,备份VM从它的日志缓冲区中消耗日志条目。主日志缓冲区的内容会被尽快刷新到日志记录通道,这些日志条目一到日志通道,就会被读取到备份的日志缓冲区。备份每次从网络上读取一些日志条目到它的日志缓冲区时,都会发送确认返回给主VM。这些确认允许 VMware FT 确定一个被输入规则延迟的输出何时可以被发送。图3说明了这个过程。

如果备份 VM 在需要读取下一个日志条目时,遇到空的日志缓冲区,它将停止执行直到有新的日志条目可用。由于备份 VM 是不与外部通信的,此暂停不会影响任何VM 的客户端。同样地,当主VM需要写入一个日志条目时,如果主VM遇到一个满的日志缓冲区,它必须停止执行,直到可以刷新日志条目。这种执行的停止是一种自然的流控制机制,当主VM生产日志条目太快了,它会减慢主VM。但是,此暂停可能会影响VM的客户端,因为主 VM 将完全停止并且无响应,直到它可以记录其条目并继续执行。因此,我们的实现必须设计为尽量减少主日志缓冲区填满的可能性。

主日志缓冲区可能填满的原因之一是备份 VM 执行速度太慢,因此消耗日志条目太慢。一般来说,备份VM必须能够以与正在记录执行的主VM大致相同的速度重放执行。幸运的是,在 VMware 确定性重放中,记录和重放的开销大致相同。然而,如果由于其他VMs,托管备份 VM 的服务器负载很重(因此过度使用资源),备份VM 可能无法获得足够的 CPU 和内存资源,来与主 VM 一样快地执行,尽管备份管理程序的VM调度器已经尽了最大努力。

如果日志缓冲区填满,除了避免意外暂停,还有另一个原因是我们不希望滞后变得太大。如果主VM出现故障,备份VM 必须通过重放它在上线和开始与外部世界交流之前已经确认的所有日志条目来“赶上”。完成重放的时间基本上是失败点的执行延迟时间,所以备份上线的时间大约等于故障检测时间加上当前执行时差。因此,我们不希望执行滞后时间太大(超过一秒),因为这将显著地增加故障转移时间。

因此,我们有一个额外的机制减慢主VM,以防止备份 VM 获取太滞后了。在我们的发送和确认日志条目的协议中,我们发送附加信息来确定主备VM之间的实时执行滞后。通常执行滞后小于 100 毫秒。如果备份 VM 有一个显著的执行滞后(例如,超过 1 秒),VMware FT 通过通知调度程序给它稍微少一点的CPU(最初只是百分之几)来减慢主 VM。我们使用一个缓慢的反馈循环,这将尝试逐步确定适当的 CPU 限制,将允许主备 VM同步执行。如果备份 VM 继续滞后,我们继续逐步降低主VM的 CPU 限制。反之,如果备份VM赶上,我们逐渐增加主VM的 CPU 限制,直到备份虚拟机恢复轻微的滞后。

请注意,主VM的这种减速很少见,通常只在系统处于低压力时发生。第 5 节的所有性能编号包括任何此类放缓的成本。

3.3、FT VMs上的操作(Operation on FT VMs)

另一个实际问题是处理各种控制操作,它们可以应用于主 VM 。例如,如果主VM明确关闭电源,备份 VM 也应该停止,而不是尝试上线。 再举一个例子,任何主VM上的资源管理更改(例如增加 CPU 份额)应该 也适用于备份。 对于此类操作,为了影响备份进行合适的操作,特殊的控制条目通过日志通道从主发送到备份。

一般来说,VM 上的大部分操作都应该仅在主 VM 上初始化。 VMware FT 然后发送任何必要的控制条目以造成备份VM上适当的更改。 唯一可以独立在主VM和备份VM上完成的操作是 VMotion。 即主VM和备份VM可以独立被 VMotioned到其他主机。 请注意,VMware FT 确保两个 VM 都不会移动到另一个 VM 所在的服务器,因为这种场景将不再提供容错。

主VM的VMotion增加了比普通VM更多的复杂性,因为备份VM一定会与源主VM失去连接以及在适当的时间重连。备份VM的VMotion有一个相似的问题,但是只增加了一个额外的复杂性。对于一个正常的VMotion而言,我们需要当VMotion上最后的切换发生时,所有的磁盘IO停止(或完成)。对于一个主VM而言,这种停顿是容易应付的,通过等待直到物理IO完成并将这些完成信息发送给VM。然而,对于一个备份VM而言,没有容易的方式来使得所有IO在任何需要的时刻完成,因为备用VM必须重放主VM的执行过程,并在相同的执行点完成IO。主VM可能正运行在一个工作负载上,在正常执行过程中总是有磁盘IO。VMware FT有一个独一无二的方法来解决这个问题。当一个备份VM是在VMotion最后的切换点时,它需要通过日志通道来告知主VM临时停止所有IO。备份VM的IO将自然地被停止在一个单独的执行点,因为它需要重放主VM的停止操作的过程。

3.4、磁盘IO的实现问题(Implementation Issues for Disk IOs)

有许多与磁盘IO相关的微小的实现问题。首先,假设磁盘操作是非阻塞的,因此访问相同磁盘位置的并行、同时执行的磁盘操作将引起非确定性。此外,我们的磁盘 IO 实现使用DMA 直接from/to虚拟机的内存,所以同时访问相同内存页的磁盘操作也可能导致不确定性。我们的解决方案是经常检测任何此类 IO 竞争(很少见),以及强制此类竞争磁盘操作在主备VM上按顺序执行。

第二, VM 中的应用程序(或操作系统)中,磁盘操作与内存访问也会存在竞争,因为磁盘操作通过 DMA 直接访问 VM 的内存。例如,如果一个VM 中的应用程序/操作系统正在读取内存块,同时对该块进行磁盘读取。(这里的意思应该是,该块内存作为DMA操作的目的地址。)这个情况也不太可能发生,但如果它发生,我们必须检测它并处理它。一种解决方案是临时设置页保护,在作为磁盘操作目标的页面上。如果VM 碰巧访问一个页,同时该页面也是磁盘操作的目标,页保护将导致一个陷阱(trap,陷入系统调用),VM将暂停直到磁盘操作完成。因为改变页上的MMU 保护是一项昂贵的操作,所以我们选择使用弹跳缓冲区(Bounce Buffer)代替。bounce buffer是临时缓冲区,与正在被磁盘操作访问的内存大小相同。磁盘读取操作被修改为读取指定数据到bounce buffer,并在IO完成时将数据复制到内存中。相似地,对于磁盘写操作,首先将要发送的数据复制到bounce buffer,磁盘写入修改为向bounce buffer写入数据。bounce buffer的使用会减慢磁盘操作,但我们还没有看到它会导致任何明显的性能损失。(bounce buffer存在的意义是在内存访问这个操作之前加了一个拦截器,其最本质的意义是为了supervisor监控DMA操作,使得数据从bounce buffer拷贝到到内存和系统中断这两个步骤,能够同时在backup VM上被复制,否则网卡直接将网络数据包DMA到Primary虚机中这个操作是无法通过log channel进行复制的

第三,有一些与故障发生并且备份VM接管时,主VM未完成的磁盘 IO 相关的问题。对于新上线的主VM,没有办法确定磁盘IO是有问题的还是成功完成了。另外,由于磁盘IO没有从外部发布到备用VM上,而是通过主备传递,因此对于继续运行的新上任的主VM来说,将没有明确的IO完成信息,最终将导致VM上的操作系统开始中止或者重调度程序。我们能够发送一个错误完成,表示每个IO失败,因为即使IO成功完成了,它可以接受返回一个错误。然而,操作系统可能不能对这些来自本地磁盘的错误有很好的响应。反之,我们在备份VM上线的过程中,重新发送这些悬挂着的IO。因为我们已经限制了所有的竞争和所有的直接指定内存和磁盘的IO,这些磁盘操作可以被重新发送,即使它们已经成功完成了(即他们是幂等的)。

idempotent 幂等 ,指一个操作可以重复执行多次,但只会产生一次结果

3.5、网络IO的实现问题(Implementation Issues for Network IO)

VMware vSphere针对VM网络提供了很多性能优化。一些优化是基于管理程序(supervisor)异步更新虚拟机的网络设备状态。例如,当VM正在执行时,接收缓冲区可以由管理程序直接更新。不幸的是这些对 VM 状态的异步更新会增加不确定性。除非我们可以保证所有更新都发生在主备指令流上的同一点,否则备份VM的执行可能与主VM的执行不同。

对于FT而言,网络仿真代码的最大变化是禁用异步网络优化。异步更新带有传入数据包的VM环形缓冲区的代码已被修改,以强制管理程序捕获到操作系统,它可以在其中记录更新然后将它们应用到 VM。同样,异步地将数据包从传输队列中拉出也被修改了,取而代之的是通过管理程序traps来完成传输(如下所述)。

网络设备异步更新的消除结合第 2.2 节中描述的发送数据包的延迟带来了一些网络性能的挑战。我们采取了两种方法在运行 FT 时提高 VM 的网络性能。第一,我们实施了集群优化以减少 VM 的陷阱和中断。当 VM 以足够的比特率流式传输数据时,管理程序可以对每组数据包做一个传输trap,在最好的情况下零trap,因为它可以传输所接收新数据包的一部分数据包。同样地,通过仅对于一组数据包发布中断,管理程序可以将接收包的中断数量减少。

我们对网络的第二个性能优化涉及减少传输数据包的延迟。如前所述,管理程序必须延迟所有发送的包直到它得到备份VM对于某些日志条目的确认。减少发送延迟的关键在于减少发送/接收备份VM信息的所需时间。我们的主要优化包括保证收发信息在无需任何线程上下文切换的情形下就可以被执行。VMware vSphere管理程序允许函数被注册到TCP栈中,只要TCP数据被接收到了,函数就会被一个延期执行的上下文调用(和Linux中的tasklet类似)。这允许我们快速处理备份VM上任何即将到来的日志消息,以及主VM接收的任何确认消息,而不需要任何线程上下文的切换。另外,当主VM有一个包要寄出去时,我们强制一次相关输出日志条目的日志刷出(正如2.2节中所描述的),通过调度一个延迟执行的上下文来执行这次刷出。

4. 替代设计(DESIGN ALTERNATIVES)

在我们VMware FT的实现中,我们已经探索了许多有趣的替代设计。在这节中,我们探索一些替代设计。

4.1、共享 vs. 非共享磁盘(Shared vs. Non-shared Disk)

在我们默认的设计中,主备VM共享相同的虚拟磁盘。因此,如果一次故障转移发生,共享磁盘的内容自然是正确、可接受的。必要地,对于主备VM来说,共享磁盘被认为是外部的,因此任何共享磁盘的写入被认为是一次与外部世界的沟通。因此,只有主VM做这种实际的磁盘写入,并且为了遵循输出规则,这种写入必须被延迟。

对于主备VM而言,一种可替代的选择是分隔的虚拟磁盘。在这种设计中,备份VM要执行所有虚拟磁盘的写入操作。而且这样做的话自然要保持它的虚拟磁盘内容与主VM虚拟磁盘内容一致。图4阐述了这种配置。在非共享磁盘的情况下,虚拟磁盘必须被认为是每个VM的内部状态。因此,依据输出规则,主VM的磁盘写入不必延迟。在共享存储不能被主备VM接受的情况下,非共享的设计是相当有用的。这种情况可能是由于共享存储不可接受或者太昂贵,或者由于运行主备VM的服务器相隔太远(“长距离FT”)。非共享设计的一个缺点是在首次启动故障容错时,虚拟磁盘的两个复制必须以相同的方式进行显示同步。另外,发生故障后磁盘可能会不同步,因此当在一次失败后备份VM重启的时候,他们必须再显式地同步。FT VMotion必须不止同步主备VM的运行状态,还要同步他们的磁盘状态。

在这种非共享磁盘的配置中,他们也能应付脑裂场景。在这种场景中,系统能够使用一些其他的外部决策者,例如所有服务器可以沟通的一个第三方服务。如果服务器是超过两个节点的集群的一部分,这个系统能够基于集群关系使用一种majority算法。在这个例子中,一个VM能够被允许上线,如果它正在一个服务器上运行,这个服务器是包含大多数原始节点的正在通信的子集群的一部分。

4.2 在备份VM上执行磁盘读(Executing Disk Reads on the Backup VM)

在我们默认的设计中,备份的VM从不会从它自己的虚拟磁盘上读取(无论共享还是非共享)。因为磁盘读取被认为是一个输入,它是自然地通过日志通道将磁盘读取的结果发送到备份VM上。

一种替代的设计是让备份VM执行磁盘读取,因此消除了磁盘读取的日志。对于大多数时候都做磁盘读取的工作负载而言,这种方法可以很好地降低日志通道上的流量。然而,这种方法有很多小问题。它可能会减慢备份VM的执行速度,因为备份VM必须执行所有的磁盘读取,当到达VM执行中主VM已经完成的位置时,如果备份上的磁盘读取还没完成就必须等待。

同样地,为了处理失败的磁盘读取操作,必须做一些额外的工作。如果一个主VM的磁盘读取成功了,但是相应的备份VM磁盘读取失败了,备份VM的磁盘读取必须重试直到成功。因为备份VM必须获得和主VM一样的数据到内存中。相反地,如果一个主VM的磁盘读取失败了,目标内存的内容必须通过日志通道发送给备份服务器,因此内存的内容将被破坏,不能被备份VM成功的磁盘读取复制。

最后,如果这种磁盘读取被用于共享磁盘配置的话,还有一个小问题。如果主VM做了一次对具体磁盘位置的读取,然后紧跟相同磁盘位置的写入,然后这个磁盘写必须被延迟到备份VM已经执行了第一次磁盘读取。这种依赖可以被检测和正确处理,但是需要增加实现上额外的复杂性。

在5.1节中,对于实际的应用而言,我们给出一些性能结果以表示在备份VM上执行磁盘读取会造成一些轻微的吞吐量减少(1-4%),因此在日志通道的带宽被限制的情况下,在备份VM上执行磁盘读取可能是有用的。

5、性能评估(PERFORMANCE EVALUATION)

在这节中,我们做了一次VMware FT性能的基础评估,针对许多应用负载以及网络基准。为了得到这些结果,我们在一样的服务器上运行主备VM,每个都带9个Intel Xeon 2.8Ghz CPUs and 8Gbytes of RAM。服务器间通过10 Gbit/s的交换机连接,但是在所有的例子中都能看到被使用的网络带宽远远少于1Gbit/s。从一个通过标准的4Gbit/s的光纤通道网络连接的EMC Clariion中,服务器可以连接他们的共享虚拟磁盘。客户端通过1 Gbit/s的网络来驱动一些连接服务器的工作负载。

我们评估性能结果的应用如下所示。SPECJbb2005是工业标准的Java应用基准,非常耗费CPU和内存,但是IO非常少。Kernel Compile是一种运行Linux核编译的工作负载。由于许多编译过程的创建和毁灭,这个工作负载做很多磁盘读取和写入,是非常耗费CPU和MMU的。Oracle Swingbench是被Swingbench OLTP工作负载(在线事务处理)驱动的一个Oracle 11g的数据库。这个工作负载做连续的磁盘和网络IO,有80个同时在线的数据库会话。MS-SQL DVD Store是一种工作负载,运行了一个Microsoft SQL Server 2005的数据库,有60个同时在线的客户端。

5.1、基本性能结果(Basic Performance Results)

表 1 列出了基本的性能结果。对于每个应用程序,第二列给出了应用程序的性能比例,运行服务器工作负载的虚拟机上启用和未启用FT的情况。性能比小于 1 表示带FT的工作负载更慢。显然,这些有代表性的工作负载上启用FT 的开销小于10%。 SPECJbb2005 完全受计算限制,没有空闲时间,但其表现性能良好,因为它具有最小的除定时器中断以外的不确定性事件。另一个工作负载做磁盘 IO 有一些空闲时间,所以一些FT 开销可能被 FT虚拟机的空闲时间更少的真实情况隐藏。然而,一般的结论是VMware FT 能够支持容错VM,并且具备相当低的性能开销。

在表的第三列中,我们给出了当应用程序正在运行时,在日志通道上发送数据的平均带宽。对于这些应用程序,日志带宽相当合理,1 Gbit/s的网络就能满足 。事实上,低带宽要求表明多个 FT 工作负载可以共享相同的 1 Gbit/s网络,同时没有任何负面的性能影响。

对于运行常见操作系统的 VM,例如Linux 和 Windows,我们发现当操作系统空闲时,通常的日志记录带宽为 0.5-1.5 Mbits/sec。”空闲”带宽主要是记录定时器中断发送的结果。对于具有活动中工作负载的 VM而言,日志带宽由网络和必须发送到备份的磁盘输入主导—网络收到的数据包和从磁盘读取的磁盘块。因此,对于非常高的网络接收或者磁盘读取带宽的应用而言,日志带宽高于表1中的测量值。对于这类应用而言,日志通道的带宽可能是瓶颈,特别是日志通道还有其他使用时。

对于许多实际应用程序而言,日志记录所需的带宽相对较低,这使得基于重放的容错对于使用非共享磁盘的长距离配置非常有吸引力。对于远距离配置而言,其主备VM可能相隔1-100公里,光纤可以轻松地支持延迟小于 10 毫秒的100-1000 Mbit/s带宽。对于表 1 中的应用而言,主备之间的额外往返延迟,可能会导致网络和磁盘输出最多延迟 20 毫秒。远距离配置仅适用于这类应用程序:他的客户端可以容忍每个请求的额外延迟。

对于两个最占用磁盘空间的应用程序,我们测量了在备份 VM上执行磁盘读取(如第 4.2 节所述)与通过日志记录通道发送磁盘读取数据相比,对于性能的影响。对于 Oracle Swingbench来说,在备份VM上执行磁盘读取时的吞吐量降低约 4%;对于 MS-SQL DVD 存储,吞吐量约降低 1%。同时,Oracle Swingbench的日志带宽从 12 Mbits/sec 降低到 3 Mbits/sec,MS-SQL DVD 存储从 18 Mbits/sec 降低到 8 Mbits/sec。显然,对于具有更大磁盘读取带宽的应用程序,带宽可能会节省很多。如第 4.2 节所述,预计在备份 VM 上执行磁盘读取时,性能可能会更差。但是,对于日志通道的带宽是有限的(例如,远程配置)情况下,在备份 VM 上执行磁盘读取可能有用。

5.2、 网络基准测试(Network Benchmarks)

出于多种原因。网络基准测试对我们的系统来说非常具有挑战性。第一,高速网络会有一个非常高的中断率,这需要以非常高的速度记录和重放异步事件。 第二,以高速率接收数据包的基准将导致高速率的日志流量,因为所有这些数据包必须通过日志通道发送到备份。第三,发送数据包的基准测试将受制于输出规则,延迟网络数据包的发送直到已收到来自备份VM的确认。 此延迟会增加对客户端测量的延迟。这种延迟还可能会降低到客户端的网络带宽,因为网络协议(如 TCP)由于往返延迟增加,可能不得不降低网络传输速率。

表 2 给出了我们通过标准的netperf 基准测试,多次测量的结果。在所有这些测量中,客户端 VM 和主 VM 通过 1 Gbit/s 网络连接。前两行给出了主备主机间通过1 Gbit/s 的日志通道连接时,发送和接收的性能。第三行和第四行给出当主备服务器通过10 Gbit/s的日志通道连接时,发送和接收的性能,不仅带宽更高,延迟也低于 1 Gbit/s。作为一个粗略的测量,在1 Gbit/s 网络连接的管理程序之间, ping 时间约为 150 微秒,而对于 10 Gbit/s 连接,ping时间大约需要 90 微秒。

未启用 FT 时,主 VM 对于接收和发送,可以实现接近 (940 Mbit/s) 1 Gbit/s 的线路传输速率。当为接收工作负载启用 FT 时,日志记录带宽非常大,因为所有传入的网络数据包必须在日志通道上发送。因此,日志记录通道可能成为瓶颈,正如1 Gbit/s 日志网络的结果。对于 10 Gbit/s 的日志网络,影响则小了很多。当为上传工作负载启用 FT 时,上传数据包的数据不会记录,但仍必须记录网络中断。日志带宽要低得多,因此可实现的网络上传带宽高于网络接收带宽。总的来说,我们看到 FT 在非常高的上传和接收速率情况下,可以显著地限制网络带宽,但仍然可以实现很高的速率

6、相关工作(RELATED WORK)

Bressoud 和 Schneider [3] 描述了实施的最初想法,通过完全包含在管理程序级别的软件对虚拟机进行容错。他们展示了保持一个备份虚拟机的可行性,该备份通过配备 HP PA-RISC 处理器的服务器原型与主虚拟机同步。但是,由于PA-RISC 架构的限制,他们无法实现完全安全、隔离的虚拟机。此外,他们没有实现任何故障检测方法,也没有尝试解决第 3 节中描述的任何实际问题。更重要的是,他们对他们的 FT 协议提出的很多限制是不必要的。首先,他们强加了epoch的概念,其中异步事件被延迟到设定的时间间隔结束。一个epoch的概念是不必要的—他们可能强加了它,因为他们无法足够有效地重放单个异步事件。其次,他们要求主虚拟机基本上停止执行,直到备份收到并且确认所有以前的日志条目。然而,只有输出本身(例如网络数据包)必须延迟 –主 VM 本身可能会继续执行。

Bressoud [4] 描述了一个在操作系统(Unixware)中实现容错的系统,因此为在该操作系统上运行的所有应用程序提供容错。系统调用接口变成了必须确定性地复制的一组操作。这项工作与基于管理程序的工作有着相似的限制与设计选择。

纳珀等人 [9] 以及 Friedman 和 Kama [7] 描述了容错 Java 虚拟机的设计。他们在日志通道中发送输入与非确定性操作时遵循与我们类似的设计。像 Bressoud 一样,他们似乎并不专注于检测故障并在故障后重新建立容错。此外,它们的实现仅限于对在 Java 虚拟机中运行的应用程序提供容错。这些系统试图处理多线程Java 应用程序的问题,但要求所有数据都正确地受锁保护或强制执行序列化到共享内存。

邓拉普等 [6] 描述了确定性重放的实现,主要针对在半虚拟化系统上调试应用软件。我们的工作支持在虚拟机内运行的任何操作系统并实现了对这些 VM 的容错支持,这需要更高水平的稳定性和性能。

库利等人[5] 描述了一种支持容错VMs的替代方法,并且在一个名为Remus的项目里实现了。通过这种方法,在执行期间主VM的状态被反复检查,并且被发送到备份服务器,该服务器收集检查点信息。检查点必须非常频繁地执行(每秒多次),因为外部输出必须延迟到下一个检查点被发送和确认。这种方法的优点是它同样适用于单处理器和多处理器 VM。

这种方法的主要问题是有非常高的网络带宽需要,以将每个检查点内存状态的增量更改发送出去。 Remus 的结果[5] 显示,对于发送内存状态的改变,当使用一个1 Gbit/s 网络连接尝试每秒做40个检查点时,内核编译与SPECweb 基准测试减速 100% 到 225%。有许多优化可能有助于减少所需的网络带宽,但不清楚1 Gbit/s 连接是否可以实现合理的性能。相比之下,我们基于确定性重放的方法可以实现低于 10% 的开销,在几个真实应用中主备主机所需的带宽远远少于 20 Mbit/s。

7、结论与今后的工作(CONCLUSION AND FUTURE WORK)

我们在VMware vSphere 中设计并实施了一个高效完整的系统(FT) ,用于为服务器上运行的虚拟机提供容错。我们的设计基于复制主VM中的执行,再通过另一台主机上的备份VM执行VMware确定性重放。如果运行主 VM的服务器出现故障,备份 VM 能立即接管且不会中断或丢失数据。

总体而言,在商业硬件上运行VMware FT时,故障容错VM的性能非常出色,并且对于某些典型应用程序,其开销低于 10%。大多数 VMware FT 的性能成本来自于使用 VMware 确定性重放来保持主备VM同步。因此,VMware FT 的低开销源自 VMware 确定性重放的效率。此外,保持主备同步所需的日志带宽非常小,通常小于 20 Mbit/s。因为日志带宽在大多数情况下很小,主备相隔很长的距离(1-100公里)似乎也是可行的实施配置。因此,VMware FT 可用于这种场景:可以防止整个站点发生故障的灾难。值得注意的是,日志流通常是可压缩的,因此简单的压缩技术可以显著地减少日志带宽,虽然有少量额外的 CPU 开销。

我们对 VMware FT 的结果表明,一个高效的故障容错VM的实现可以建立在确定性重放的基础上这样的系统可以透明地为运行任何操作系统和应用的虚拟机提供容错能力,仅会带来极小的开销。然而,对客户有用的故障容错VM系统而言,它必须还具有强大、易于使用和高度自动化的特点。一个可用的系统除了复制虚拟机执行之外,还需要许多其他组件。特别是VMware FT 故障后自动地恢复冗余,通过在本地集群中找到合适的服务器并在其上创建一个新的备份VM。通过解决所有必要的问题,我们已经展示了一个在客户的数据中心可用于实际应用的系统。

通过确定性重放实现容错的权衡之一是当前确定性重放仅针对单处理器VM 。然而,单处理器虚拟机足够应付各种各样的工作负载,特别是因为物理处理器不断变得更加强大。此外,许多工作负载可以通过使用许多单处理器的虚拟机来扩展,而不是通过使用一个更大的多处理器虚拟机来扩展。多处理器 VM 的高性能重放是一种活跃的研究领域,并且可以潜在地被微处理器中的一些额外硬件支持。一个有趣的方向可能是扩展事务内存模型以促进多处理器重放。

将来,我们也有兴趣扩展我们的系统处理部分硬件故障。通过部分硬件故障,我们的意思是服务器上功能或冗余的部分丢失,不会导致损坏或丢失数据。一个例子是到 VM所有网络连接的丢失,或在物理服务器中备用电源丢失。如果在运行主 VM 的服务器上发生部分硬件故障,在许多情况下(但不是all) 故障转移到备份 VM 将是有利的。这样的故障转移对于关键VM而言,可以立即恢复完整服务,并确保虚拟机从可能不可靠的服务器上快速地移走。


文章作者: wck
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 wck !
评论
  目录