# 4.6 重复输出（Duplicated Output）

还有一种可能的情况是，回复报文已经从VMM发往客户端了，所以客户端收到了回复，但是这时Primary虚机崩溃了。而在Backup侧，客户端请求还堆积在Backup对应的VMM的Log等待缓冲区（详见4.4倒数第二个学生提问），也就是说客户端请求还没有真正发送到Backup虚机中。当Primary崩溃之后，Backup接管服务，Backup首先需要消费所有在等待缓冲区中的Log，以保持与Primay在相同的状态，这样Backup才能以与Primary相同的状态接管服务。假设最后一条Log条目对应来自客户端的请求，那么Backup会在处理完客户端请求对应的中断之后，再上线接管服务。这意味着，Backup会将自己的计数器增加到11（原来是10，处理完客户端的自增请求变成11），并生成一个输出报文。因为这时，Backup已经上线接管服务，它生成的输出报文会被它的VMM发往客户端。这样客户端会收到两个内容是11的回复。如果这里的情况真的发生了，那么明显这也是一个异常行为，因为不可能在运行在单个服务器的服务上发生这种行为。

好消息是，几乎可以肯定，客户端通过TCP与服务进行交互，也就是说客户端请求和回复都通过TCP Channel收发。当Backup接管服务时，因为它的状态与Primary相同，所以它知道TCP连接的状态和TCP传输的序列号。当Backup生成回复报文时，这个报文的TCP序列号与之前Primary生成报文的TCP序列号是一样的，这样客户端的TCP栈会发现这是一个重复的报文，它会在TCP层面丢弃这个重复的报文，用户层的软件永远也看不到这里的重复。

这里可以认为是异常的场景，并且被意外的解决了。但是事实上，对于任何有主从切换的复制系统，基本上不可能将系统设计成不产生重复输出。为了避免重复输出，有一个选项是在两边都不生成输出，但这是一个非常糟糕的做法（因为对于客户端来说就是一次失败的请求）。当出现主从切换时，切换的两边都有可能生成重复的输出，这意味着，某种程度上来说，所有复制系统的客户端需要一种重复检测机制。这里我们使用的是TCP来完成重复检测，如果我们没有TCP，那就需要另一种其他机制，或许是应用程序级别的序列号。

在lab2和lab3中，基本上可以看到我们前面介绍的所有内容，例如输出控制，你会设计你的复制状态机。

> 学生提问：太长了，听不太清，直接看回答吧。
>
> Robert教授：第一部分是对的。当Backup虚机消费了最后一条Log条目，这条Log包含了客户端的请求，并且Backup上线了。从这个时间点开始，我们不需要复制任何东西，因为Primary已经挂了，现在没有任何其他副本。
>
> 如果Primary向客户端发送了一个回复报文，之后，Primary或者客户端关闭了TCP连接，所以现在客户端侧是没有TCP连接的。Primary挂了之后，Backup虚机还是有TCP连接的信息。Backup执行最后一条Log，Backup会生成一个回复报文，但是这个报文送到客户端时，客户端并没有相应的TCP连接信息。客户端会直接丢弃报文，就像这个报文不存在一样。哦不！这里客户端实际会发送一个TCP Reset，这是一个类似于TCP error的东西给Backup虚机，Backup会处理这里的TCP Reset，但是没关系，因为现在只有一个副本，Backup可以任意处理，而不用担心与其他副本有差异。实际上，Backup会直接忽略这个报文。现在Backup上线了，在这个复制系统里面，它不受任何人任何事的限制。
>
> 学生提问：Backup接手服务之后，对于之前的TCP连接，还能用相同的TCP源端口来发送数据吗（因为源端口一般是随机的）？
>
> Robert教授：你可以这么认为。因为Backup的内存镜像与Primary的完全一致，所以它们会以相同的TCP源端口来发送数据，它们在每一件事情上都是一样的。它们发送的报文每一bit都是一样的。
>
> 学生提问：甚至对于IP地址都会是一样的吗，毕竟这里涉及两个物理服务器？
>
> Robert教授：在这个层面，物理服务器并没有IP地址。在我们的例子中，Primary虚机和Backup虚机都有IP地址，但是物理服务器和VMM在网络上基本是透明的。物理服务器上的VMM在网络上并没有自己的唯一标识。虚拟机有自己独立的操作系统和独立的TCP栈，但是对于IP地址和其他的关联数据，Primary和Backup是一样的（类似于HA VIP）。当虚机发送一个网络报文，它会以虚机的IP地址和MAC地址来发送，这些信息是直接透传到局域网的，而这正是我们想要的。所以Backup会生成与Primary完全一样的报文。这里有一些tricky，因为如果物理服务器都接在一个以太网交换机上，那么它们必然在交换机的不同端口上，在发生切换时，我们希望以太网交换机能够知道当前主节点在哪，这样才能正常的转发报文，这会有一些额外的有意思的事情。大部分时候，Primary和Backup都是生成相同的报文，并送出。

> （注：早期的VMware虚机都是直接以VLAN或者Flat形式，通过DVS接入到物理网络，所以虚拟机的报文与物理机无关，可以直接在局域网发送。以太网交换机会维护MAC地址表，表明MAC地址与交换机端口的对应，因为Primary和Backup虚机的MAC地址一样，当主从切换时，这个表需要更新，这样同一个目的MAC地址，切换前是发往了Primary虚机所在的物理服务器对应的交换机端口，切换之后是发往了Backup虚机所在的物理服务器对应的交换机端口。交换机MAC地址表的切换通常通过虚机主动发起GARP来更新。）


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/lecture-04-vmware-ft/4.6-zhong-fu-shu-chu-duplicated-output.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
