让我来介绍一下VMware FT是如何工作的。
首先,VMware是一个虚拟机公司,它们的业务主要是售卖虚拟机技术。虚拟机的意思是,你买一台计算机,通常只能在硬件上启动一个操作系统。但是如果在硬件上运行一个虚拟机监控器(VMM,Virtual Machine Monitor)或者Hypervisor,Hypervisor会在同一个硬件上模拟出多个虚拟的计算机。所以通过VMM,可以在一个硬件上启动一到多个Linux虚机,一到多个Windows虚机。
这台计算机上的VMM可以运行一系列不同的操作系统,其中每一个都有自己的操作系统内核和应用程序。
这是VMware发家的技术,这里的硬件和操作系统之间的抽象,可以有很多很多的好处。首先是,我们只需要购买一台计算机,就可以在上面运行大量不同的操作系统,我们可以在每个操作系统里面运行一个小的服务,而不是购买大量的物理计算机,每个物理计算机只运行一个服务。所以,这是VMware的发家技术,并且它有大量围绕这个技术构建的复杂系统。
VMware FT需要两个物理服务器。将Primary和Backup运行在一台服务器的两个虚拟机里面毫无意义,因为容错本来就是为了能够抵御硬件故障。所以,你至少需要两个物理服务器运行VMM,Primary虚机在其中一个物理服务器上,Backup在另一个物理服务器上。在其中一个物理服务器上,我们有一个虚拟机,这个物理服务器或许运行了很多虚拟机,但是我们只关心其中一个。这个虚拟机跑了某个操作系统,和一种服务器应用程序,或许是个数据库,或许是MapReduce master或者其他的,我们将之指定为Primary。在第二个物理服务器上,运行了相同的VMM,和一个相同的虚拟机作为Backup。它与Primary有着一样的操作系统。
两个物理服务器上的VMM会为每个虚拟机分配一段内存,这两段内存的镜像需要完全一致,或者说我们的目标就是让Primary和Backup的内存镜像完全一致。所以现在,我们有两个物理服务器,它们每一个都运行了一个虚拟机,每个虚拟机里面都有我们关心的服务的一个拷贝。我们假设有一个网络连接了这两个物理服务器。
除此之外,在这个局域网(LAN,Local Area Network),还有一些客户端。实际上,它们不必是客户端,可以只是一些我们的多副本服务需要与之交互的其他计算机。其中一些客户端向我们的服务发送请求。在VMware FT里,多副本服务没有使用本地盘,而是使用了一些Disk Server(远程盘)。尽管从论文里很难发现,这里可以将远程盘服务器也看做是一个外部收发数据包的源,与客户端的区别不大。
所以,基本的工作流程是,我们假设这两个副本,或者说这两个虚拟机:Primary和Backup,互为副本。某些我们服务的客户端,向Primary发送了一个请求,这个请求以网络数据包的形式发出。
这个网络数据包产生一个中断,之后这个中断送到了VMM。VMM可以发现这是一个发给我们的多副本服务的一个输入,所以这里VMM会做两件事情:
- 在虚拟机的guest操作系统中,模拟网络数据包到达的中断,以将相应的数据送给应用程序的Primary副本。
- 除此之外,因为这是一个多副本虚拟机的输入,VMM会将网络数据包拷贝一份,并通过网络送给Backup虚机所在的VMM。
Backup虚机所在的VMM知道这是发送给Backup虚机的网络数据包,它也会在Backup虚机中模拟网络数据包到达的中断,以将数据发送给应用程序的Backup。所以现在,Primary和Backup都有了这个网络数据包,它们有了相同的输入,再加上许多细节,它们将会以相同的方式处理这个输入,并保持同步。
当然,虚机内的服务会回复客户端的请求。在Primary虚机里面,服务会生成一个回复报文,并通过VMM在虚机内模拟的虚拟网卡发出。之后VMM可以看到这个报文,它会实际的将这个报文发送给客户端。
另一方面,由于Backup虚机运行了相同顺序的指令,它也会生成一个回复报文给客户端,并将这个报文通过它的VMM模拟出来的虚拟网卡发出。但是它的VMM知道这是Backup虚机,会丢弃这里的回复报文。所以这里,Primary和Backup都看见了相同的输入,但是只有Primary虚机实际生成了回复报文给客户端。
这里有一个术语,VMware FT论文中将Primary到Backup之间同步的数据流的通道称之为Log Channel。虽然都运行在一个网络上,但是这些从Primary发往Backup的事件被称为Log Channel上的Log Event/Entry。
当Primary因为故障停止运行时,FT(Fault-Tolerance)就开始工作了。从Backup的角度来说,它将不再收到来自于Log Channel上的Log条目。实际中,Backup每秒可以收到很多条Log,其中一个来源就是来自于Primary的定时器中断。每个Primary的定时器中断都会生成一条Log条目并发送给Backup,这些定时器中断每秒大概会有100次。所以,如果Primary虚机还在运行,Backup必然可以期望从Log Channel收到很多消息。如果Primary虚机停止运行了,那么Backup的VMM就会说:天,我都有1秒没有从Log Channel收到任何消息了,Primary一定是挂了或者出什么问题了。当Backup不再从Primary收到消息,VMware FT论文的描述是,Backup虚机会上线(Go Alive)。这意味着,Backup不会再等待来自于Primary的Log Channel的事件,Backup的VMM会让Backup自由执行,而不是受来自于Primary的事件驱动。Backup的VMM会在网络中做一些处理(猜测是发GARP),让后续的客户端请求发往Backup虚机,而不是Primary虚机。同时,Backup的VMM不再会丢弃Backup虚机的输出。当然,它现在已经不再是Backup,而是Primary。所以现在,左边的虚机直接接收输入,直接产生输出。到此为止,Backup虚机接管了服务。
类似的一个场景,虽然没那么有趣,但是也需要能正确工作。如果Backup虚机停止运行,Primary也需要用一个类似的流程来抛弃Backup,停止向它发送事件,并且表现的就像是一个单点的服务,而不是一个多副本服务一样。所以,只要有一个因为故障停止运行,并且不再产生网络流量时,Primary和Backup中的另一个都可以上线继续工作。
学生提问:Backup怎么让其他客户端向自己发送请求?
Robert教授:魔法。。。取决于是哪种网络技术。从论文中看,一种可能是,所有这些都运行在以太网上。每个以太网的物理计算机,或者说网卡有一个48bit的唯一ID(MAC地址)。下面这些都是我(Robert教授)编的。每个虚拟机也有一个唯一的MAC地址,当Backup虚机接手时,它会宣称它有Primary的MAC地址,并向外通告说,我是那个MAC地址的主人。这样,以太网上的其他人就会向它发送网络数据包。不过这只是我(Robert教授)的解读。
学生提问:随机数生成器这种操作怎么在Primary和Backup做同步?
Robert教授:VMware FT的设计者认为他们找到了所有类似的操作,对于每一个操作,Primary执行随机数生成,或者某个时间点生成的中断(依赖于执行时间点的中断)。而Backup虚机不会执行这些操作,Backup的VMM会探测这些指令,拦截并且不执行它们。VMM会让Backup虚机等待来自Log Channel的有关这些指令的指示,比如随机数生成器这样的指令,之后VMM会将Primary生成的随机数发送给Backup。
论文有暗示说他们让Intel向处理器加了一些特性来支持这里的操作,但是论文没有具体说是什么特性。