VMware-FT
VMware-FT
1.摘要
我们已经实现了一个商业企业级系统,用于提供容错虚拟机,该系统基于通过在另一台服务器上的备份虚拟机复制主虚拟机(VM)的执行这一方法。我们在 VMware vSphere 4.0 中设计了一个完整的系统,该系统易于使用,可在商用服务器上运行,并且通常会使实际应用程序的性能降低不到 10%。此外,对于一些实际应用程序,使主虚拟机和辅助虚拟机同步执行所需的数据带宽小于 20 Mbit/s,这使得在更长距离上实现容错成为可能。一个易于使用的商业系统,在故障后自动恢复冗余,除了复制虚拟机执行之外还需要许多额外的组件。我们已经设计并实现了这些额外的组件,并解决了在支持运行企业应用程序的虚拟机时遇到的许多实际问题。在本文中,我们描述了我们的基本设计,讨论了替代设计选择和许多实现细节,并提供了微基准测试和实际应用程序的性能结果。
2
2.2
对于 VMware FT,我们使用确定性重放来生成记录主虚拟机执行情况所需的日志条目,但不是将日志条目写入磁盘,而是通过日志通道将它们发送到备份虚拟机。备份虚拟机实时重放这些条目,因此与主虚拟机执行方式完全相同。然而,我们必须在日志通道上用严格的 FT 协议来扩充日志条目,以确保实现容错。我们的基本要求如下:
输出要求:如果在主虚拟机出现故障后备份虚拟机接管,那么备份虚拟机将继续以与主虚拟机发送到外部世界的所有输出完全一致的方式执行。
由于在执行期间会发生许多非确定性事件,如果没有故障发生,主虚拟机本来会继续执行。然而,只要备份虚拟机满足输出要求,在故障转移到备份虚拟机期间,就不会有外部可见的状态或数据丢失,并且客户端在其服务中不会注意到任何中断或不一致。
可以通过延迟任何外部输出(通常是网络数据包)来确保满足输出要求,直到备份虚拟机接收到所有能使其重放执行至少到该输出操作点的信息。一个必要条件是备份虚拟机必须已接收在输出操作之前生成的所有日志条目。这些日志条目将使其执行到最后一个日志条目的位置。然而,假设在主虚拟机执行输出操作后立即发生故障。备份虚拟机必须知道它必须继续重放到输出操作的位置,并且只有在那个点才 “上线”(停止重放并像 2.3 节中描述的那样接管成为主虚拟机)。如果备份在输出操作之前的最后一个日志条目的位置上线,某些非确定性事件(例如传递给虚拟机的定时器中断)可能会在其执行输出操作之前改变其执行路径。
鉴于上述限制,满足输出要求的最简单方法是在每次输出操作时创建一个特殊的日志条目。然后,可以通过这个特定规则来满足输出要求:
输出规则:主虚拟机不得向外部发送输出,直到备份虚拟机已接收并确认与产生该输出的操作相关的日志条目。
如果备份虚拟机已接收所有日志条目,包括产生输出操作的日志条目,那么备份虚拟机将能够在该输出点精确地重现主虚拟机的状态,因此如果主虚拟机出现故障,备份将正确地达到与该输出一致的状态。相反,如果备份虚拟机在未接收所有必要日志条目的情况下接管,那么它的状态可能会迅速偏离,从而与主虚拟机的输出不一致。输出规则在某些方面类似于 [11] 中描述的方法,在那里 “外部同步” 的 I/O 实际上可以被缓冲,只要它在下一次外部通信之前实际被写入磁盘。
请注意,输出规则没有提及停止主虚拟机的执行。我们只需要延迟输出的发送,但虚拟机本身可以继续执行。由于操作系统通过异步中断进行非阻塞网络和磁盘输出以指示完成,虚拟机可以轻松地继续执行,并且不一定会立即受到输出延迟的影响。相比之下,先前的工作 [3,9] 通常表明在进行输出之前,主虚拟机必须完全停止,直到备份虚拟机已从主虚拟机确认所有必要信息。
例如,我们在图 2 中展示了一个图表,说明了 FT 协议的要求。该图展示了主虚拟机和备份虚拟机上的事件时间线。从主线条指向备份线条的箭头表示日志条目的传输,从备份线条指向主线条的箭头表示确认。关于异步事件、输入和输出操作的信息必须作为日志条目发送到备份并得到确认。如图所示,向外部的输出被延迟,直到主虚拟机从备份虚拟机收到确认,确认它已接收到与输出操作相关的日志条目。如果遵循输出规则,备份虚拟机将能够在与主虚拟机的最后一个输出一致的状态下接管。
在故障转移情况下,我们不能保证所有输出都恰好产生一次。如果在主虚拟机打算发送输出时不使用两阶段提交的事务,那么备份就无法确定主虚拟机是在发送最后一个输出之前还是之后立即崩溃。幸运的是,网络基础设施(包括普遍使用的 TCP)被设计为处理丢失的数据包和相同(重复的)数据包。请注意,在主虚拟机出现故障期间,传入主虚拟机的数据包也可能会丢失,因此不会传递到备份。然而,传入的数据包可能由于与服务器故障无关的各种原因而被丢弃,所以网络基础设施、操作系统和应用程序都被编写为确保它们能够补偿丢失的数据包。
关于FT的策略,我产生的一些问题:
1.客户端请求过来要求对某个数据自增,当Primary给Backup发送了操作日志,backup也回应了Primary收到了日志,正准备发送回应的时候,Primary机器挂掉了,那么客户端会显示超时,但其实业务已经完成,一般怎么处理这个问题?
这种情况可以通过幂等性设计解决。
幂等性是指相同的请求多次执行,只会产生一次效果。在你的场景中,确保自增操作是幂等的,客户端每次请求都能确定是否需要执行自增。
使用唯一请求ID:客户端在每次请求时生成一个唯一的请求ID,并将其发送给服务端。服务端在处理请求时,检查该请求ID是否已经处理过,如果已处理则直接返回之前的结果。
客户端超时之后,会再次尝试,这个时候会发送到backup上,backup因为同步了相应的操作,发现这个操作已经执行过,因此不再执行,直接返回。