Files
MIT6.824/lecture-09-more-replication-craq/9.6-lian-fu-zhi-de-gu-zhang-hui-fu-fail-recover.md
2022-01-25 02:41:31 +00:00

5.6 KiB
Raw Blame History

9.6 链复制的故障恢复Fail Recover

在Chain Replication中出现故障后你可以看到的状态是相对有限的。因为写请求的传播模式非常有规律我们不会陷入到类似于Raft论文中图7和图8描述的那种令人毛骨悚然的复杂场景中。并且在出现故障之后也不会出现不同的副本之间各种各样不同步的场景。

在Chain Replication中因为写请求总是依次在链中处理写请求要么可以达到TAIL并commit要么只到达了链中的某一个服务器之后这个服务器出现故障在链中排在这个服务器后面的所有其他服务器不再能看到写请求。所以只可能有两种情况committed的写请求会被所有服务器看到而如果一个写请求没有commit那就意味着在导致系统出现故障之前写请求已经执行到链中的某个服务器所有在链里面这个服务器之前的服务器都看到了写请求所有在这个服务器之后的服务器都没看到写请求。

总的来看Chain Replication的故障恢复也相对的更简单。

如果HEAD出现故障作为最接近的服务器下一个节点可以接手成为新的HEAD并不需要做任何其他的操作。对于还在处理中的请求可以分为两种情况

  • 对于任何已经发送到了第二个节点的写请求不会因为HEAD故障而停止转发它会持续转发直到commit。
  • 如果写请求发送到HEAD在HEAD转发这个写请求之前HEAD就故障了那么这个写请求必然没有commit也必然没有人知道这个写请求我们也必然没有向发送这个写请求的客户端确认这个请求因为写请求必然没能送到TAIL。所以对于只送到了HEAD并且在HEAD将其转发前HEAD就故障了的写请求我们不必做任何事情。或许客户端会重发这个写请求但是这并不是我们需要担心的问题。

如果TAIL出现故障处理流程也非常相似TAIL的前一个节点可以接手成为新的TAIL。所有TAIL知道的信息TAIL的前一个节点必然都知道因为TAIL的所有信息都是其前一个节点告知的。

中间节点出现故障会稍微复杂一点,但是基本上来说,需要做的就是将故障节点从链中移除。或许有一些写请求被故障节点接收了,但是还没有被故障节点之后的节点接收,所以,当我们将其从链中移除时,故障节点的前一个节点或许需要重发最近的一些写请求给它的新后继节点。这是恢复中间节点流程的简单版本。

Chain Replication与Raft进行对比有以下差别

  • 从性能上看对于Raft如果我们有一个Leader和一些Follower。Leader需要直接将数据发送给所有的Follower。所以当客户端发送了一个写请求给LeaderLeader需要自己将这个请求发送给所有的Follower。然而在Chain Replication中HEAD只需要将写请求发送到一个其他节点。数据在网络中发送的代价较高所以Raft Leader的负担会比Chain Replication中HEAD的负担更高。当客户端请求变多时Raft Leader会到达一个瓶颈而不能在单位时间内处理更多的请求。而同等条件以下Chain Replication的HEAD可以在单位时间处理更多的请求瓶颈会来的更晚一些。
  • 另一个与Raft相比的有趣的差别是Raft中读请求同样也需要在Raft Leader中处理所以Raft Leader可以看到所有的请求。而在Chain Replication中每一个节点都可以看到写请求但是只有TAIL可以看到读请求。所以负载在一定程度上在HEAD和TAIL之间分担了而不是集中在单个Leader节点。
  • 前面分析的故障恢复Chain Replication也比Raft更加简单。这也是使用Chain Replication的一个主要动力。

学生提问如果一个写请求还在传递的过程中还没有到达TAILTAIL就故障了会发生什么

Robert教授如果这个时候TAIL故障了TAIL的前一个节点最终会看到这个写请求但是TAIL并没有看到。因为TAIL的故障TAIL的前一个节点会成为新的TAIL这个写请求实际上会完成commit因为写请求到达了新的TAIL。所以新的TAIL可以回复给客户端但是它极有可能不会回复因为当它收到写请求时它可能还不是TAIL。这样的话客户端或许会重发写请求但是这就太糟糕了因为同一个写请求会在系统中处理两遍所以我们需要能够在HEAD抑制重复请求。不过基本上我们讨论的所有系统都需要能够抑制重复的请求。

学生提问假设第二个节点不能与HEAD进行通信第二个节点能不能直接接管成为新的HEAD并通知客户端将请求发给自己而不是之前的HEAD

Robert教授这是个非常好的问题。你认为呢

你的方案听起来比较可行。假设HEAD和第二个节点之间的网络出问题了

HEAD还在正常运行同时HEAD认为第二个节点挂了。然而第二个节点实际上还活着它认为HEAD挂了。所以现在他们都会认为另一个服务器挂了我应该接管服务并处理写请求。因为从HEAD看来其他服务器都失联了HEAD会认为自己现在是唯一的副本那么它接下来既会是HEAD又会是TAIL。第二个节点会有类似的判断会认为自己是新的HEAD。所以现在有了脑裂的两组数据最终这两组数据会变得完全不一样。

(下一节继续分析怎么解决这里的问题)