大家好,这里是架构资源栈!点击上方关注,添加“星标”,一起学习大厂前沿架构!
引言
在构建分布式系统时,实现多个节点之间的一致性是一项核心挑战。无论是微服务架构、分布式缓存,还是多副本数据库系统,都绕不开一致性协议的支撑。
相比于早期的两阶段提交(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 需要:
- 持久化记录已接受的最大编号提议
- 对于收到的新提议编号
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 发布!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。