> For the complete documentation index, see [llms.txt](https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/lecture-04-vmware-ft/4.3.md).

# 4.3 VMware FT 工作原理

让我来介绍一下VMware FT是如何工作的。

首先，VMware是一个虚拟机公司，它们的业务主要是售卖虚拟机技术。虚拟机的意思是，你买一台计算机，通常只能在硬件上启动一个操作系统。但是如果在硬件上运行一个虚拟机监控器（VMM，Virtual Machine Monitor）或者Hypervisor，Hypervisor会在同一个硬件上模拟出多个虚拟的计算机。所以通过VMM，可以在一个硬件上启动一到多个Linux虚机，一到多个Windows虚机。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDsI4C4wyajEqJD6cL8%2F-MDsTBlXQarl5eMf7HqJ%2Fimage.png?alt=media\&token=e9720d3d-6f63-4cc5-9b64-97fb35120885)

这台计算机上的VMM可以运行一系列不同的操作系统，其中每一个都有自己的操作系统内核和应用程序。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDsI4C4wyajEqJD6cL8%2F-MDsTlsYzPPorUWFPR9X%2Fimage.png?alt=media\&token=d41e7a42-a4e2-4e0f-9543-66239c780ee5)

这是VMware发家的技术，这里的硬件和操作系统之间的抽象，可以有很多很多的好处。首先是，我们只需要购买一台计算机，就可以在上面运行大量不同的操作系统，我们可以在每个操作系统里面运行一个小的服务，而不是购买大量的物理计算机，每个物理计算机只运行一个服务。所以，这是VMware的发家技术，并且它有大量围绕这个技术构建的复杂系统。

VMware FT需要两个物理服务器。将Primary和Backup运行在一台服务器的两个虚拟机里面毫无意义，因为容错本来就是为了能够抵御硬件故障。所以，你至少需要两个物理服务器运行VMM，Primary虚机在其中一个物理服务器上，Backup在另一个物理服务器上。在其中一个物理服务器上，我们有一个虚拟机，这个物理服务器或许运行了很多虚拟机，但是我们只关心其中一个。这个虚拟机跑了某个操作系统，和一种服务器应用程序，或许是个数据库，或许是MapReduce master或者其他的，我们将之指定为Primary。在第二个物理服务器上，运行了相同的VMM，和一个相同的虚拟机作为Backup。它与Primary有着一样的操作系统。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDthFjHlqUvEfDlwt2D%2Fimage.png?alt=media\&token=50be1591-5180-4ebb-a2a0-b09ab6a6f3bd)

两个物理服务器上的VMM会为每个虚拟机分配一段内存，这两段内存的镜像需要完全一致，或者说我们的目标就是让Primary和Backup的内存镜像完全一致。所以现在，我们有两个物理服务器，它们每一个都运行了一个虚拟机，每个虚拟机里面都有我们关心的服务的一个拷贝。我们假设有一个网络连接了这两个物理服务器。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtiWtS1vu1qcOlgzNK%2Fimage.png?alt=media\&token=0ff29a04-a3a7-441d-8674-7b7a556942b8)

除此之外，在这个局域网（LAN，Local Area Network），还有一些客户端。实际上，它们不必是客户端，可以只是一些我们的多副本服务需要与之交互的其他计算机。其中一些客户端向我们的服务发送请求。在VMware FT里，多副本服务没有使用本地盘，而是使用了一些Disk Server（远程盘）。尽管从论文里很难发现，这里可以将远程盘服务器也看做是一个外部收发数据包的源，与客户端的区别不大。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtjT2u52Qwr6ksEhvq%2Fimage.png?alt=media\&token=111b5f7f-2537-4ad6-b3e8-ab60cf9e8757)

所以，基本的工作流程是，我们假设这两个副本，或者说这两个虚拟机：Primary和Backup，互为副本。某些我们服务的客户端，向Primary发送了一个请求，这个请求以网络数据包的形式发出。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtkvtZ-w50Dk_uJeU_%2Fimage.png?alt=media\&token=9d4d16d6-67a2-4522-91e0-23c86a965df3)

这个网络数据包产生一个中断，之后这个中断送到了VMM。VMM可以发现这是一个发给我们的多副本服务的一个输入，所以这里VMM会做两件事情：

* 在虚拟机的guest操作系统中，模拟网络数据包到达的中断，以将相应的数据送给应用程序的Primary副本。
* 除此之外，因为这是一个多副本虚拟机的输入，VMM会将网络数据包拷贝一份，并通过网络送给Backup虚机所在的VMM。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtm7J9cSwVTuzpwOvC%2Fimage.png?alt=media\&token=271d099b-b138-4c03-bdba-17395e16f9f9)

Backup虚机所在的VMM知道这是发送给Backup虚机的网络数据包，它也会在Backup虚机中模拟网络数据包到达的中断，以将数据发送给应用程序的Backup。所以现在，Primary和Backup都有了这个网络数据包，它们有了相同的输入，再加上许多细节，它们将会以相同的方式处理这个输入，并保持同步。

当然，虚机内的服务会回复客户端的请求。在Primary虚机里面，服务会生成一个回复报文，并通过VMM在虚机内模拟的虚拟网卡发出。之后VMM可以看到这个报文，它会实际的将这个报文发送给客户端。

![说实话，这里画的挺乱的](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtnVrjVHke_k_9g8N4%2Fimage.png?alt=media\&token=641981c0-cb73-42ee-a1b0-2768a856967f)

另一方面，由于Backup虚机运行了相同顺序的指令，它也会生成一个回复报文给客户端，并将这个报文通过它的VMM模拟出来的虚拟网卡发出。但是它的VMM知道这是Backup虚机，会丢弃这里的回复报文。所以这里，Primary和Backup都看见了相同的输入，但是只有Primary虚机实际生成了回复报文给客户端。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtoMyD--fIalpCOTIf%2Fimage.png?alt=media\&token=0259f37a-7b48-448d-8c9d-010387cff1ce)

这里有一个术语，VMware FT论文中将Primary到Backup之间同步的数据流的通道称之为Log Channel。虽然都运行在一个网络上，但是这些从Primary发往Backup的事件被称为Log Channel上的Log Event/Entry。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDtfAj7Zq9oNnN5oFGi%2F-MDtoxLaiP_pMTorUOc7%2Fimage.png?alt=media\&token=78a3255a-969c-48bd-a937-0be7e6a6b7b9)

当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向处理器加了一些特性来支持这里的操作，但是论文没有具体说是什么特性。
