大家好,这里是架构资源栈!点击上方关注,添加“星标”,一起学习大厂前沿架构!


引言

在构建分布式系统时,实现多个节点之间的一致性是一项核心挑战。无论是微服务架构、分布式缓存,还是多副本数据库系统,都绕不开一致性协议的支撑。

相比于早期的两阶段提交(2PC)和三阶段提交(3PC)协议,Paxos 协议能在节点宕机、消息乱序或丢失、网络分区等复杂场景下,依旧保障最终的一致决议,因此被广泛研究和应用。然而,Paxos 同样因其逻辑复杂、难以理解而“臭名昭著”。

本文将结合经典论文《Paxos Made Simple》和《The Part-Time Parliament》,系统推演 Paxos 协议的基本原理与实现思路,帮助大家真正理解 Paxos 的设计哲学。


Basic Paxos

我们首先回到问题的本质:在一个节点可能宕机、消息可能乱序或丢失的网络环境中,如何让一群互不信任的节点就一个值达成一致?

初步设想

Paxos 将节点角色划分为两类:

  • Proposer:发起提议,想要推动某个值被接受
  • Acceptor:负责接收提议并根据规则作出响应

在最简单的理想情况中,只有一个 proposer 存在、节点不宕机、网络无延迟。那么,一项规则就足以达成一致:

P1:每个 acceptor 接受自己收到的第一个提议。

当然,这种设定过于理想化,现实系统中通常存在多个 proposer 并发提议,节点可能掉线或恢复,消息也可能在传输中丢失。因此,我们需要引入更多机制来确保一致性不被破坏。


提议的结构与多数派机制

为应对现实中的复杂情况,Paxos 对提议进行编号,每个提议为 (ID, value) 的结构。提议编号(Proposal ID)必须是全局唯一且单调递增的,常用时间戳加节点 ID 的方式生成。

同时,引入“多数派”机制 —— 只要多数 acceptor 接受某个提议,该提议即被视为“确定”(chosen)。


一致性核心约束

为了实现“只确定一个值”,Paxos 引入了一系列约束条件:

  • P2:一旦某个值被确定,系统中所有后续被确定的值必须相同。

实现这一目标并不简单。acceptor 和 proposer 都需要遵循以下规则:

对 acceptor 的要求:

P2a:若某个值 v 已被确定,acceptor 之后只接受值为 v 的提议。

为了实现 P2a,需对 proposer 的行为作出进一步限制:

对 proposer 的要求:

P2b:若某值 v 已被确定,则后续 proposer 只能发起值为 v 的提议。

再深入一步,我们得到 Basic Paxos 的核心规则:

P2c:proposer 在发起编号为 n 的提议前,需从多数派 acceptor 获取其最近接受的提议(编号最大的那个);若存在,新的提议值必须与该值一致;若不存在,可自由选值。

上图模拟了多个 proposer 和 acceptor 之间的交互情况,不同编号的提议如何在不同 acceptor 上被接受,进而影响后续 proposer 的提议值选择。通过满足上述 P2c 规则,系统可以避免两个不同值同时被确定,从而保障一致性。


Paxos 的三大约束

综合以上推导,Basic Paxos 的三条核心约束如下:

  • B1:每轮提议具有唯一编号(Proposal ID)
  • B2:一旦多数派 acceptor 接受某提议,该提议即被视为确定(Chosen)
  • B3:若 proposer 要发起提议 (n, v),其值 v 必须来自当前多数派中编号最大提议的值(若存在)

为了支持这些规则,acceptor 需要:

  1. 持久化记录已接受的最大编号提议
  2. 对于收到的新提议编号 n,若已承诺不接受更小编号,则拒绝旧编号提议(即 Promise)

Paxos 协议的两个阶段

Paxos 的交互过程被分为两个阶段:

1. Prepare 阶段

  • proposer 发送 prepare(n) 请求
  • acceptor 回复其已接受的最大编号提议(如有),并承诺不再接受编号小于 n 的提议

2. Accept 阶段

  • proposer 根据多数回复选择值并发送 accept(n, v)
  • acceptor 若仍未违反 promise,则接受该提议


避免活锁:引入 Leader

若多个 proposer 同时发起提议,不断相互打断对方的流程,系统可能陷入“活锁”(livelock)状态。为提高效率和达成率,通常会选举一个 leader,由其独占发起提议,其他 proposer 放弃主动权。只有在 leader 宕机后,才会触发重新选主。


Learner 的引入

Paxos 还引入了 learner 角色,用于接收已确定的提议结果,维持各个节点之间的状态一致性。即使部分 acceptor 在提议过程中宕机,也可在恢复后通过向其他节点“拉取”结果同步状态。


Multi Paxos

Paxos 本质上只能“确定一个值”,那如果我们要构建一个数据库、分布式日志或消息队列,显然不能只靠一个值,怎么办?

答案是:一次确定一个值,重复执行即可。


实例化:将“值”编上序号

将每一次提议看作一个独立的实例(instance),每个实例有自己的编号与独立状态机,就可以实现一个按顺序推进的提议序列,构建出具备全序关系的系统状态。

多个节点(如 A/B/C)分别执行相同提议实例的状态转换逻辑,即使节点间物理隔离,也能最终保持逻辑一致性。


Leader 提升性能

在 Multi Paxos 中,Leader 的角色尤为重要。一旦选定 leader 后,后续的提议可以跳过 prepare 阶段,直接发起 accept 请求,极大减少了消息交互次数,提高系统性能。只有在 leader 宕机时,才重新执行 prepare 阶段,完成主节点迁移。


小结

Paxos 是实现分布式一致性的经典协议,其推导过程虽然复杂,但核心思想清晰:通过编号控制和多数派机制,确保系统中只会有一个值被确定

在 Basic Paxos 的基础上,Multi Paxos 通过实例化和 Leader 优化,成功实现了高性能、高一致性的分布式状态机复制方案。

Paxos 的理论坚实,但真正将其落地在工程中并不容易。微信团队曾实现并开源了基于 Paxos 的多机状态同步库 PhxPaxos,经过实战验证,已广泛应用于后台系统的状态同步中。


本文涉及的核心概念包括:一致性、多数派机制、提议编号、状态机复制、活锁控制等,掌握这些内容将为你后续深入学习 Raft、ZAB 等协议打下坚实基础。


本文由博客一文多发平台 OpenWrite 发布!

吾日三省吾码
25 声望4 粉丝