第1-5部分回顾

  1. 我们通过重新定义共识问题,将解决分布式系统中的持久性作为核心目标,并从顶层设计的角度来解决问题。
  2. 我们展示了一种方法,可以将持久性视作抽象需求,而不是用多数节点(majority quorum)这种更严格的方法。
  3. 我们定义了一组高级规则,这些规则可以满足共识系统的属性,同时尊重任意(但有意义的)持久性要求。
  4. 我们提出将领导权变更视作撤销和建立的方式,这为实现提供了更多选项,而现有系统通常没有充分利用这些选项。
  5. 我们指出,在处理竞争条件时存在两种根本不同的方法,并讨论了它们的权衡利弊。

可以在本文底部找到前几篇博客文章的链接。

共识系统的要求

共识系统的主要要求是:它不能忘记已确认接受的请求。为了满足该要求,领导者(Leader)必须将请求传输给足够数量的节点,以满足持久性要求。此外,还必须存在一种机制,用于在持久性要求未满足之前取消请求,如果操作失败即可停止请求进一步传播。

两阶段协议(Two-phase Protocol)

上述要求可以通过引入两阶段协议来满足。领导者首先将请求的内容作为临时状态(Tentative)发送给所有节点。临时请求是一种可以稍后完成或取消的请求。

负责领导者持久性的跟随者(Follower)需要确认收到临时请求。一旦领导者从其跟随者接收到必要的确认,表示该请求已经达到持久性要求且不可取消。随后,领导者可以发送消息完成临时请求。

我们可以将一个请求的状态分为三个阶段:

  1. 未完成(Incomplete): 请求仍在传输中,尚未达到持久性要求。在跟随者之间,该请求被标记为临时状态,随后可以完成或取消。
  2. 持久(Durable): 请求仍在传输中,但已达到持久性要求。这是一个隐性的但非常重要的阶段。持久的请求不会被取消。
  3. 完成(Complete): 请求已完成。跟随者可以将请求标记为完成并执行任何后续的完成操作(如数据存储或增量处理)。

一个优化:一旦请求成为持久状态,领导者可以直接将此请求以“完成”状态发送给尚未收到消息的跟随者,以简化步骤。

如果领导者未能使请求达到持久状态,可以继续尝试,但不能尝试取消请求。这是因为导票器可能正在进行领导权变更,并可能尝试传播未成功的请求。在下一篇文章中,我们将分析这个过程。

完成与取消

完成和取消是互斥的:一个已完成的请求永远不会被取消,而一个已取消的请求永远不会被完成。

当跟随者接收到完成请求的消息时,可以执行必要的步骤来实施该请求的效果。例如,如果请求旨在修改变量值,此修改现在可以被应用。

如果接收到取消请求的消息,跟随者可以删除该请求,就像它从未发生过一样。

响应的时机

领导者可以在请求达到持久状态时立即向客户端发回成功消息。但也可以选择延迟确认,直到它将完成消息发送给所有跟随者为止。等待完成节点确认需要两轮通信(round-trip),因此比提前响应更慢。不过,这种方法可以提高多数派读(quorum reads)的性能。对于选择使用多数派读方法的系统,这种权衡可能是必要的。这是一个更大的话题,之后可能需要单独的文章来讨论。

对于使用基于锁定的故障切换的系统,可以向当前领导者发送读操作请求,而不是依赖多数派读方法。这允许领导者在接收到足够的确认后立即响应。

在MySQL中的请求完成

MySQL的“半同步协议(semi-sync protocol)”并不支持这种两阶段完成请求的方法。当副本接收到请求时,它会立即应用该请求。这种行为可能引发一些需要缓解的边界情况。我在之前的一篇文章《在MySQL中实现分布式持久性》中讨论了部分边界情况。

另一个MySQL的行为是:在崩溃后重新启动的主库会完成所有未完成的请求,而不验证是否收到必要的确认。这可能导致“脑裂(split-brain)”情景。



共识算法扩展系列:第6部分——完成请求插图

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.choupangxia.com/2025/08/02/algorithms-6/