6.824 Lecture 4 Primary&Backup Replication Notes & Paper Reading

Posted on 二 24 八月 2021 in course • 4 min read

1 概要

本课主要是对分布式系统中复制这个主题进行了讨论,复制是为了容错而存在的,而复制本身又会带来更多的挑战。本课的论文是来自虚拟机提供商 VMWare 的 VMware vSphere Fault Tolerance 产品论文,这个产品是一个虚拟机指令级别的复制系统,是一个切实使用的企业级产品中的一个功能。虚拟机级别的复制对应用甚至操作系统都是透明的,VM 之上程序完全无感知,并且复制状态和粒度非常精确,可以带来很强大的复制功能,但是另一方面实现上也存在很多的困难。

本课相关的材料:

  • 课堂 Paper - https://pdos.csail.mit.edu/6.824/papers/vm-ft.pdf
  • 课堂录像: https://youtu.be/gXiDmq1zDq4
  • 课堂 Note: https://pdos.csail.mit.edu/6.824/notes/l-vm-ft.txt

2 要点

2.1 异常与失效

  • Fail-stop: 异常导致服务器宕机,完全无效 -> 网络、硬件、掉电等等;
  • 逻辑 bug: 分布式系统自身的代码逻辑错误导致异常;
  • 配置错误导致异常;
  • 不考虑恶意服务和黑客导致的异常;
  • 物理世界的异常:地震、台风等等导致机房出现异常或者网络中断;

2.2 挑战

  • 判断主节点 (Primary) 已经失效: 网络异常导致脑裂,备份节点认为主节点失效尝试提升为主节点并对外提供服务,在网络恢复后系统处于异常状态;
  • 维持主节点/备份节点数据同步:期待对于客户端无感,主备节点需要保证修改的顺序一致,并且处理好非确定性的执行结果同步;
  • Fail-over : 异常出现时,备份节点怎么才可以正常成功接管对外服务?应该尽量减少对外的影响,外部无感知;

2.3 复制同步方案

  • 状态传输:定时创建状态的 checkpoint,然后同步到备份节点,实现上可以考虑对比上个 checkpoint,只传输差异;
  • 复制状态机 (RSM) : 主节点同步操作命令到备份节点,备份节点按顺序执行一致的操作,以保证主备状态一致;

目的都是为保证主备节点的状态一致,状态传输的方式在状态很大的情况下会比较耗时,并且对网络带宽要求很大。

而复制状态机是常见的方法,上节课的 GFS 也是应用了复制状态机的方案。复制状态机的方案还需要考虑非确定的执行,比如获取当前时间的操作、或者随机数的操作。

操作复制的级别

  1. 应用级别的操作: 比如 GFS 的文件追加写操作,和应用强相关;
  2. 机器级别的操作指令: 机器执行的指令,与应用无关,不关注运行的应用程序;

2.4 VMware FT

虚拟机级别的复制,直接复制虚拟机执行指令操作,对应用程序透明,对请求的客户端隐藏具体实现,尽量减少复制对性能的影响。VMware FT 是真实的应用产品,是商用的。

2.4.1 总览

  • 层级:硬件 -> 虚拟机 (VM / Hypervisor/VM FT) -> 操作系统(linux) -> 应用程序;
  • 捕获操作系统的中断,由 VM FT 执行复制到备份 VM,通过日志通道;
  • 主备之间存在一个日志通道用于传输主节点的非确定相关操作指令;
  • 客户端只与主节点交互和通信;
  • 备份节点和主节点执行一样的操作指令,但是不会直接与客户端交互,不会对外输出;
  • 备份节点操作系统的对外写数据会被 VM FT 处理掉;
  • 主备节点同网络内会存在一个存储服务,用于主备之间的协调处理和数据存储;
  • 主备节点之间如果存在网络分区,需要依赖共享存储去协调进行主备切换,备节点状态切换为单节点的主节点状态,并开始接收和处理客户端的请求及进行响应;
  • 主备节点在共享存储上利用一个类锁机制标识(flag)来实现状态切换;
  • 主节点失效,备份节点转换为主节点对外服务,这时候就是单点状态,需要考虑启动一个新的备份节点继续执行复制,VM FT 是利用 VMMotion 复制主虚拟机来实现创建新的备份虚拟机的;

主节点通过日志通道发送给备份节点的情况:

  1. 有可能会导致主备执行出现分离的时候,相关执行指令及数据会发送给备份节点:外部事件,客户端的 packet 数据,中断等;
  2. 非确定性执行指令的结果需要发送给备份节点;

备份节点必须要落后主节点一个日志条目的执行,以保证备份节点的执行不会超出主节点,导致和主节点出现分离。

2.4.2 设计

目标是希望对外能表现为一个单节点服务器一样,外部客户端对主备异常下的切换无感知。

指令类型:

  1. 确定性指令:inc, dec, ... 需要保证执行的顺序一致;
  2. 非确定性指令:执行多次结果产生的结果不一样,如果直接复制到备份节点执行会影响到结果,导致主备的状态不一致 -> 获取时间操作,计时器中断

多核的情况:多个线程执行是抢占式的,难以保证主备的多核执行指令顺序一致,本论文中应用的是单核虚拟机,暂不考虑多核的实现。

操作系统执行非确定指令时,操作被 FT 捕获,执行结果并记录结果,然后将非确定执行转换为确定性的执行,通过日志通道传输结果给备份节点,在备份节点执行同样的指令时也会捕获指令并返回一致的结果给备份节点的操作系统。

主备复制机制的存在,为了避免在异常切换主备时对外输出存在不一致,主节点对外输出需要特别考虑:

  • 主节点执行输出前,需要确保产生输出的操作指令已经同步到备份节点;
  • 只是延迟对外输出,主节点接下来指令的执行还是继续的;

客户端可以进行重试或者重置连接,但是基于输出规则,不会存在数据不一致。这个输出机制在实际应用时,比如流量大的应用,会导致应用带宽大幅度下降(40%),因为主节点需要等待指令操作复制到背节点后再对外响应数据接收,所以运行时带宽就会下降。

3 Paper

本课讨论的论文是来自 VMware 公司的企业级商用系统 VMware vSphere Fault Tolerance,下文简称 FT。FT 包含在其商用产品 VMware vSphere 4.0 ,是一个虚拟机指令级别复制的容错系统,实现了主备虚拟机之间完整的指令及状态复制,应用性能影响不超过 10%,并且对运行的应用无需额外实现应用层的复制。

我们常见的分布式系统中,为了容错而考虑复制机制时,通常采用的是应用级别的操作日志复制实现,而本论文的思路是对应用及操作系统运行的虚拟机级别指令进行复制。这个方案可以使得主备虚拟机之间无论上层运行的应用是什么,都可以完成无感透明的复制容错。

这不是一个常见的方案,在具体实现上,涉及到虚拟机底层及硬件指令级别的诸多细节,可想而知存在着很多的难点。本论文主要描述了 FT 整体的设计思路及实现,其中详细讨论了几个关键点,但是整个系统的实现肯定是存在着大量的细节难点,甚至本论文实现的还是针对单核的虚拟机的复制。虽然这个方案并没有被广泛应用,但是 FT 实现中的一些实际考虑和设计也值得我们参考。

3.1 简介

当我们想要实现一个支持容错的分布式系统时,一个常见的方案是主备机制,备份服务始终保持和主服务的状态同步,这样在主服务挂掉时,备份服务可以直接接手对外提供一直的服务。主备服务之间状态的同步通常是通过复制实现的,而无论是什么级别的复制,我们实现一个主备复制支持容错的系统时有两种常见的方案:

  1. 状态变化数据复制:把主节点的所有状态变化数据(CPU/Memory/IO设备等等)同步到备份节点;
  2. 状态机复制:将主备节点视为启动时状态一致的状态机,这样只需要把会导致主节点状态变化的指令和数据同步到备份节点,然后由备份节点按和主节点一致的顺序执行,这样可以保证主备的状态完全一致,也就实现了同步的效果;

状态变化数据复制需要对比状态差异,并且如果内存因为指令发生大量的变化,需要同步的数据将会是非常大的,而状态机复制是关注导致变化的指令,只需要同步指令,这样实际需要同步的数据就小很多。但是因为虚拟机有很多指令是非确定性的,每次执行的结果可能都不一致,这种指令需要额外的机制来协调处理,以保证主备节点之间的状态不会出现分离。

在物理机器上实现指令级别的复制是很难的,特别是多核的服务器,各种非确定性指令难以实现同步。而本论文产品是基于 hypervisor 实现的虚拟机级别的指令复制,hypervisor 拥有对虚拟机执行指令的完全控制,可以捕获所有非确定性操作的必要信息,并且同步到备份虚拟机进行重放执行,保证状态一致。

基于 hypervisor 实现的虚拟机状态机复制方法不需要硬件修改,可以直接运行在商用机器机器上,并且因为这个方案对于带宽要求不大,还可以考虑部署在不同地点服务器上,以保证更高的容错和可用性。

本论文实现的 FT 是基于 x86 架构的,可以对操作系统及其上运行的应用提供透明的容错支持,实现上是依赖确定性指令回放 (deterministic replay) 的方式,当前版本只支持单处理器的虚拟机复制。

3.2 基本设计

vmft

如上图是 FT 的整体架构,主备 VM 分布部署在物理上分离的两个服务器上,只有主 VM 接收外部的请求和输入,并且通过 logging channel 把数据传输到备份 VM 上进行同步。除了外部输入数据之外,传输的还包含了非确定性的指令及相关信息会同步到备份 VM,备 VM 执行一致的指令和产生一致的结果,以保证主备 VM 状态安全一致。对于指令执行产生的对外输出,只有主 VM 的输出会响应到客户端,备份 VM 的输出将会被 hypervisor 丢弃。

3.2.1 确定性回放实现

FT 复制是基于确定性状态机复制来实现的,如果两个状态机初始状态一致,那么只要保证输入数据和顺序完全一致,这两个状态机就可以保证一致的状态变化,产生一样的输出。

VM 的输入包含以下:

  • 网络数据包
  • 磁盘读
  • 键盘及鼠标等外设的输入信息

非确定性的事件(虚拟中断)及操作(读取处理器的时钟)也会影响到 VM 的状态,对于实现 VM 的执行复制,主要是面临着下面三个挑战:

  1. 正确捕获所有的输入和非确定性操作;
  2. 正确地把输入和非确定操作应用到备份 VM;
  3. 完成以上两点并且不会降低整体的性能,或者尽量要减少影响;

实现上,一些复杂的操作系统在 x86 处理器上也有一些未定义的指令执行副作用,对于这些的捕获和在备份 VM 上重放也是一个额外的挑战。

VMware 的 FT 在限定的范围内解决了上面提的这些挑战,其中的确定性回放机制记录了 VM 的输入和关联的非确定性操作指令,以日志条目的形式写到日志文件,再同步到备份 VM 完全按照顺序执行,产生一致的结果和状态。

对于非确定性的指令操作,需要记录主 VM 执行时的额外信息同步到备份 VM,比如 timer 或者 IO 完成中断,这种非确定性事件发生时的指令也会被记录下来,在备份 VM 重放时,执行到该记录指令时,也会产生同样的中断事件。

3.2.2 FT 协议

FT 中使用确定性回放来产生相关的操作日志,但是日志记录还需要通过日志通道传输到备份 VM 执行,为了确保实现容错支持,FT 对日志通道和传输提出了一个协议 (个人感觉应该是成为原则) ,其中基本的需求是:

  • 输出需求:备份 VM 在主 VM 失效接管后,需要以保证和主 VM 已经发送到外部的所有输出完全一致的方式继续执行;

对于一个基于复制机制实现高可用的分布式系统来说,高可用不仅要求节点异常时其他节点可以进行故障切换接管对外服务,还需要实现对于外部客户端来说,整个故障切换过程是无感知的。而系统对外的沟通就是输出,所以这里只要能保证主备切换时对外输出是一致的,那么对于外部客户端来说,整个切换就是无感知的。

在这里,FT 提出了一个规则:

  • 输出规则:主 VM 在备份 VM 接收并且确认产生输出的关联指令之前都不能发送输出数据到外部;

从这个输出规则来看,只要备份 VM 接收到了产生输出的所有关联指令,包含输出的那个指令,那在主 VM 失效时,备份 VM 是可以顺利接管并且和之前输出保持一致对外继续产生输出。如果相关的指令没有接收到就接管对外服务,因为主 VM 并未对外产生输出,那么接下来的输出就由备份 VM 产生了,即使执行产生了非确定的事件,对于外部客户端来说整个输出也是一致的。

值得注意的一点是,输出规则并不会限制主 VM 继续执行其他的指令,只是延迟了主 VM 对外部输出的命令。因为输出相关基本也是 IO 操作,而操作系统可以支持非阻塞的网络 IO 和磁盘输出,并且通过异步中断来指示输出完成,所以延迟对外部输出对于操作系统执行其他的指令并不会产生太大的影响。

ftprotocol.jpeg

如上图是一个示例,从左到右是主备节点按时间顺序执行指令,而主备之间的线是同步相关的日志,其中主 VM 往备份 VM 同步日志,备份 VM 向主 VM 响应收到日志,上图相关的执行顺序如下:

  1. 异步事件从主 VM 同步到备份 VM;
  2. 输入指令及数据从主 VM 同步到备份 VM;
  3. 主 VM 输出操作同步到备份 VM ,但是这时主 VM 并未对发生输出,而且暂时延迟了;
  4. 备份 VM 响应收到输出相关的指令给主 VM,此时主 VM 可以执行真正的对外输出;
  5. 主 VM 发生异常失效时,备份 VM 进行故障切换,接管对外服务,因为输出相关指令已经接收到,备份 VM 可以和主 VM 一致地对外输出;

此外,FT 并不保证对外输出是仅有一次的,比如主 VM 接收到备份 VM 的输出相关日志确认后,对外进行输出,然后出现异常,备份 VM 接管后也可能会再次对外进行输出。这种情况,需要依赖操作系统及传输协议来进行容错,比如 TCP 协议对于重复的数据包会自动进行识别和丢弃,这样对于应用来说也是无感知的。

3.2.3 检测和响应故障

在实际运行的过程中,主 VM 和备份 VM 都有可能发生故障:

  • 备份 VM 故障时:主 VM 需要从复制日志的模式切换到普通执行模式,停止往日志通道发生日志记录;
  • 主 VM 故障时:备份 VM 接管,但是需要先执行完毕所有从主 VM 同步并且已经确认的指令,然后就从回放模式转换为普通执行模式,并且被提升为主 VM,被允许对外产生输出;

备份 VM 接管时,系统会自动广播新的主 VM MAC 地址到网络中,这样物理网络设备可以识别主 VM 的位置。

故障的检测有下面几点相关的:

  1. FT 系统会通过 UDP 心跳来检测运行 VM 的服务器的状态;
  2. FT 还会检测日志通道的流量情况,包括主向备发送的日志和备向主发生的确认,因为操作系统总是存在定期的 timer 中断,所以主备之间的流量是不会完全消失的;
  3. 网络分区总是可能存在的,如果只按上面两点,是有可能存在脑裂的情况,备份 VM 以为主 VM 发生故障而自提升为主 VM,同时存在两个主 VM;
  4. FT 中主要是利用共享的存储来处理脑裂的情况,主备 VM 尝试接管对外服务时,会在共享存储上执行一个原子的 test-and-set 操作,如果操作成功就会被允许继续,失败则停止;

最后,当 FT 出现一个 VM 故障时,在另外一个 VM 成功接管后,FT 会再启动一个冗余的备份 VM,继续进行复制和维持与主 VM 的状态一致。

3.3 FT 的实践设计

3.3.1 VM 的启动与重启

在 FT 中的一个 VM 启动或者重启时,能够快速地将 VM 的状态和已有 VM 同步是一个很关键的问题,并且我们希望这个 VM 的启动不会影响到现有 VM 的性能和执行。在 FT,这主要是通过使用 VMware VMotion 功能修改版本来实现的。VMotion 是设计用于实现将 VM 在不同服务器上迁移的,在 FT 中,具体实现调整为复制,创建日志通道并且让主 VM 进入日志记录模式,并且尽量减少影响,整个过程不会导致主 VM 中断超过一秒。

FT 中的所有 VM 都是运行在同一个 VMware vSphere 集群服务器上的,共享了同样的存储,所以在 VM 需要启动一个新的备份 VM 时,可以由集群管理服务根据资源和情况选择一个合适的服务器进行复制和启动,整个过程完全自动并且外部无感知。

3.3.2 日志通道管理

日志通道相关的实现上,FT 系统是通过 hypervisor 在主备 VM 上都维持一个很大的缓存空间,主 VM 把需要同步的操作日志写到主 VM 的缓存空间上,备份 VM 从其缓存空间消费和处理执行操作日志。日志被写到主 VM 的缓存空间后立即就会备刷入到日志通道上,并且尽快地读取到备份 VM 的日志缓存上。日志从网络到备份 VM 的日志缓存后就会立即给主 VM 发生日志确认消息,以方便主 VM 执行输出规则相关逻辑。

下面几个情形会影响整体的执行:

  1. 主 VM 的日志缓存被写满:主 VM 会停止执行,这将会影响到外部客户端;
  2. 备份 VM 的日志缓存被写满:备份 VM 会进入停止状态,因为备份 VM 本来就不对外输出,所以对外部无影响;

主 VM 的日志缓存是有可能被写满的,虽然备份 VM 理论上执行速度应该是和主 VM 基本一致的,但是在极端压力的情况下,备份 VM 运行的服务器上可能会存在资源不足,包括 CPU, 内存等资源可能都缺乏,从而导致了相关操作的执行慢于主 VM,随着运行时间增长,主备之间的差距可能会越来越大,也就有可能导致主 VM 的日志缓存被写满。

从 FT 系统的实现来考虑,我们也不希望主备 VM 之间的指令间隔越来越大。因为在主 VM 失效之后,备份 VM 需要接管对外进行服务,在正式对外输出之前,备份 VM 也需要将同步到的日志按顺序执行完毕才行。如果间隔过大,那在备份 VM 在能正式对外提供服务之前会有比较大的一段时间,这样外部也会感知到了 FT 下的主备 VM 异常。

基于降低 FT 中主备 VM 操作日志间隔的考虑,FT 对于这种异常情况的处理方案是,通过额外的信息记录主备 VM 之间的执行间隔和保证大小 (100 毫秒)。当执行间隔大于一定值时 (大于 1 秒),主 VM 的执行速度将会被减缓,直到主备 VM 之间的执行间隔恢复到正常范围,如果备份 VM 的执行速度跟上来,主 VM 的 CPU 限制也会被逐渐放开,整体的执行性能也慢慢恢复到正常值。

3.3.3 FT VM 运维

对于 FT 中的 VM 正常运维操作也需要进行考虑:

  • 主 VM 执行正常关机操作,备份 VM 也应该进行关机,而不应该尝试接管对外服务;
  • 主 VM 的资源比如 CPU、内存进行了调整,备份 VM 也应该执行相对应的调整;

这些运维操作,会生成特定的控制日志并发生到日志通道上传输给备份 VM 执行。对于大部分针对 VM 的运维操作,一个原则是这些操作只能在主 VM 上执行,然后再通过特定的控制日志同步给备份 VM 执行。

唯一例外的运维操作是 VMotion 的执行,这个操作可以针对备份 VM 进行,用于调整备份 VM 的运行服务器或者恢复备份 VM。VMotion 操作给 FT 的实现带来很大的复杂性:

  • 主 VM 进行 VMotion 操作时,备份 VM 需要断开和原来主 VM 的日志通道连接,再重新连接到新的主 VM;
  • 备份 VM 进行 VMotion 时,也需要主 VM 进行日志通道的切换;

在进行 VMotion 操作时,FT 要求所有的磁盘操作都完全暂停,对于主 VM 来说,磁盘操作暂停很容易,直接执行就可以了,而备份 VM 则面临更复杂的情况。因为备份 VM 是执行主 VM 的指令的,这也可能包含正常的磁盘 IO 操作,对于备份 VM 来说难以保证在正确的地方停止磁盘 IO。实现上,当备份 VM 在 VMotion 操作最后切换的阶段时,会通过日志通道通知主 VM 临时停止所有的 IO 操作,这样备份 VM 消费到主 VM 同步过来的 IO 停止后会按照顺序执行,然后再执行后续的正常操作。

3.3.4 磁盘 IO 相关实现问题

在 FT 实现上,关于磁盘 IO 有几类问题需要考虑和解决。

第一是磁盘 IO 操作的非确定性执行。磁盘 IO 操作是非阻塞并且可以并行执行访问同一个磁盘位置的,并且在使用 DMA 操作进行内存和磁盘之间的数据传输时,也可能会并发访问同一个内存位置,而并发带来不确定性。FT 主要是通过检测这类型的 IO 操作并转换为顺序的执行来解决这个问题的。

第二个问题是磁盘操作和应用内存操作之间的冲突。磁盘操作包含了 DMA 可以直接读取内存数据,而当应用和磁盘操作同时访问内存同样位置时,也会带来不确定性。FT 主要是通过一个临时的弹性缓存 (bounce buffer) 来解决这个问题的。这个弹性缓存空间和磁盘操作要访问的内存大小一致,磁盘读操作的数据将会先缓存到这个弹性缓存空间中,直到读 IO 完成才会将数据拷贝到操作系统内存。而写磁盘操作则先写到弹性缓存空间,然后再从弹性缓存写到磁盘上。

第三个问题是主 VM 的磁盘操作可能在主 VM 发生异常失效时还没有完成,对于即将要被提升为主 VM 的原备份 VM 来说这个是不可知结果的,并且也不会接收到相关的磁盘 IO 操作完成事件。新的主 VM 也不能直接对操作系统返回一个磁盘 IO 操作失败,因为这样可能会导致不确定的情况,操作系统未必能正常处理磁盘 IO 错误。FT 的方法是重新执行等待完成事件的磁盘 IO 操作,配合之前并发 IO 调整为顺序执行,这样可以保证重新执行也不会产生异常的不一致的情况。

3.3.5 网络 IO 相关实现问题

VMware vSphere 对于 VM 的网络相关内容有特别的性能优化,主要是基于 hypervisor 的异步更新虚拟机的网络设备来实现的。但是异步操作往往意味着非确定性,对于 FT 的 VM 来说,很有可能会导致主备 VM 的状态发生分离。所以,在 FT 中,异步网络优化被取消了,异步地将接受到的数据包更新到 VM ring buffer 的代码会被 hypervisor 拦截并记录下来再应用到 VM 上。

取消网络的异步优化对于性能有一定的影响,在 FT 的实现上,主要是采用以下两个方法来提升 VM 的网络性能:

  1. 基于集群优化 VM 的相关拦截和中断:hypervisor 在流式数据传输时可以按数据包分组进行拦截处理,同样相关的中断也可以分组批量进行;
  2. 减少数据包传输的延迟:如上面提及的,基于输出原则,主 VM 需要延迟对外的数据传输直至备份 VM 确认相关联的日志已经收到,hypervisor 支持在 TCP 协议栈上注册函数,在接收到数据时可以从一个延迟执行的上下文调用,这样备份 VM 在接收到日志和主 VM 接收到确认都可以快速处理,而无需进行上下文切换。

3.4 参考设计

本节内容主要是一些实现方案的参考设计方案。

3.4.1 共享和非共享磁盘

FT 的默认设计实现中,主备 VM 是共享相同的虚拟磁盘的,这样两个 VM 之间的数据天然就是保持一致,只要维持只有主 VM 对外输出,在故障切换时,备份 VM 可以直接在同样的虚拟磁盘上进行读写操作。

另外一个方案是主备 VM 使用分离的磁盘,各自维护各自的磁盘数据状态,备份 VM 也需要执行写磁盘相关操作。这种方案在主备 VM 物理上的距离太长而不能共享虚拟磁盘的情况,此外对于无法使用共享磁盘的场景也可以支持。非共享磁盘的方案有几点需要注意的:

  1. 因为主备 VM 各自维护分离的磁盘,所以对于磁盘写,主 VM 不需要根据输出规则进行延迟;
  2. 首次启用主备 VM 时,需要把主 VM 磁盘数据快速同步到备份 VM 的磁盘;
  3. 主备可能发生不同步的情况,在同步恢复之后还需要额外考虑磁盘数据的同步处理;
  4. 对于脑裂的场景,因为不存在共享磁盘来处理,主备 VM 需要依赖额外的第三方来进行协调;

3.4.2 备份 VM 执行磁盘读操作

FT 的默认设计中,备份 VM 不会从其虚拟磁盘中读数据,只会从主 VM 读取后再视为输入操作同步日志到备份 VM 执行进行同步。

一个替代方案是支持备份 VM 读取磁盘数据,这样主 VM 就不再需要同步磁盘读取的数据,这样可以降低整个日志通道的带宽和数据。不过这个方案也有几点问题:

  1. 首先因为备份 VM 也需要执行磁盘读操作,而磁盘读操作有可能会延迟,备份 VM 的执行速度将有可能受到影响,从而影响到主备 VM 的同步处理,此外主 VM 磁盘操作完成后,备份 VM 有可能还没完成;
  2. 备份 VM 读取磁盘的操作是有可能失败的,这样还需要进行额外的处理,比如主 VM 读取磁盘成功但是备份 VM 读取失败的情况,或者反过来,实现上都需要更复杂的处理;
  3. 在共享磁盘的方案下,如果主 VM 对磁盘的同样位置进行读写,那为了让备份 VM 后续同步后能读取到同样的数据,还需要考虑延迟主 VM 的写磁盘操作。

总而言之,支持备份 VM 也执行磁盘读操作会带来实现上很大的复杂性,而优点只是降低日志通道的带宽和流量。这个方案只是在特定的应用场景下适用,比如磁盘读操作非常多而写相对少的应用。

4 总结

VMware 的 FT 系统是非常有意思的一个实现,在看到本篇论文之前,个人对于复制相关的系统基本上都是基于应用层的一个理解和场景印象,而 FT 基于虚拟机指令级别的复制的确给我带来的一定的震撼。当然,FT 的实现还是有其前提条件的,一个是基于 hypervisor 对虚拟机的管理,使得 FT 系统可以拦截和处理虚拟机的任何执行指令,进行复制相关的逻辑,另外,本论文实现的 FT 还是只针对单处理器的虚拟机,对于并行多核的虚拟机暂未有实际的支持和实现。

虽然 FT 的应用和实现比较受限,但是最终还是实现了一个完整商用的虚拟机级别的复制容错分布式系统,在 FT 上运行的任意操作系统及应用,都可以无需任何额外处理即可获得分布式容错的能力。而 FT 实现中的很多设计和考虑,在我们实现应用层级别的复制时也是可以进行参考的。