Paxos协议
目录
Paxos 是什么(What)
Paxos 的目的(Why)
角色与职责(Who)
基本流程(How)
常见问题与对策
什么是多数派(Quorum)
Paxos vs Raft 异同点
Paxos 是什么(What)
核心问题:在节点可能宕机、网络可能乱序/丢失的环境里,让副本对一个值达成一致(共识),并保证安全性:系统绝不会最终选出两个不同的值;在条件稳定时还要有活性:最终能选出一个值。
Safety(安全性):永远不会发生坏事。在共识里指不会选出两个不同的值、不会破坏不变量。
Liveness(活性):好事最终会发生。只要条件稳定(如有多数派、网络稳定),最终会选出一个值。
Single-Decree Paxos:只为一次决议选择一个值(例如第 k 个位置的值是什么)。它证明:一旦某值被多数派接受,这个值就是全局唯一的被选定值。
Multi-Paxos:把单次决议按槽位/索引重复,形成一条复制日志(slot 0、1、2…)。实践里通常选出一个稳定 Leader:第一步先做一次准备(Phase 1),随后大量槽位直接走接受阶段(Phase 2),从而把消息轮次降到近似两个来回/条目。
与 2PC 的关系:两阶段提交(2PC)假定可靠协调者,一旦协调者崩溃就可能阻塞;Paxos 则通过多数派 + 可抢占编号 + 持久化承诺/接受来保证崩溃容错下的安全性(即使协调者样的角色失败,也不会选出两个值),在网络稳定时还能继续前进。
槽位/索引(slot/index):Multi-Paxos 中每一次决议对应的位置
可抢占编号:谁的排队号大,谁就能接着推进
持久化承诺 / 接受:说过的话、同意的事,要写在纸上存好,不能反悔。也就是会存到硬盘里
用一段话区分共识(决定一个值)与复制日志(决定很多值)
共识(决定一个值)关注的是对某一个槽位最终选哪个值,确保系统在任何时刻都不会出现两个不同的被选定值;达成一次就结束。复制日志(决定很多值)则把对单个槽位的共识按序多次执行,为每个槽位各自达成一次共识,进而得到一条全体副本顺序一致的操作序列;只要状态机是确定性的,把这条日志在各副本重放,就能得到同样的状态与输出。因此,共识是原子“砖块”,复制日志是把许多砖块按顺序砌成墙;Multi-Paxos 是用 Paxos 砖块去砌这堵一致的日志之墙。
状态机是确定性的:同样的初始状态 + 同样的指令顺序,一定会得到同样的结果和最终状态
Paxos 的目的(Why)
目标
Safety(安全性)永远成立:协议在任何时刻都不会让同一槽位产生两个不同的被选定值。Liveness(活性)在良好条件下成立:出现稳定时期、有可达多数派、且竞争趋缓/稳定 Leader时,最终会选出一个值。
可达的意思是指节点之间能够正常通信
非目标
不承诺最短/固定时间内完成决定(无有界终止时间保证)
在强竞争(多主互抢)、网络分区或不到多数派时可能无进展,但不会出错(Safety 仍保留)
角色与职责(Who)
Proposer(提议者)
生成提案(编号 n,值 v),发起两阶段;在 Multi-Paxos 中常由Leader担任,负责连续多个槽位(日志索引)
Acceptor(接受者)
作为“法官”投票:对较大的 n 做承诺(Promise),并在不违背承诺的前提下接受(Accept)某个 (n, v)。安全性核心在它。
Learner(学习者)
收集“Accepted”证据,当获知多数派接受同一 (n, v) 即学习/提交该值;不参与仲裁。
Distinguished Proposer / Leader(特殊提议者 / 领导者)(工程常见)
通过选主把并发冲突降到最低;稳定后可在多数派上一次 Phase-1,多次 Phase-2(Multi-Paxos)
Acceptor 必须落盘保证安全;Proposer/Learner 可不落盘,只影响活性与恢复体验(工程上常做适度持久化更稳定)
如果leader被替换,acceptor又接受了这个leader的提案怎么办?
如果 Leader 被替换,Acceptor 也会把自己曾经接受过的提案报告给新 Leader,新 Leader 必须继承这些值;因此 Paxos 保证:旧 Leader 已经多数派接受的值不会丢,没形成多数的值可以被覆盖,否则会破坏 Safety。
基本流程(How)
Phase 1|Prepare/Promise
Proposer 发送 Prepare(n);任何接到的 Acceptor 若 n > promised_n,则:
将 promised_n ← n(持久化),承诺不再接受 < n 的提案
用 Promise 回应,并携带自己已接受过的最高对 (accepted_n, accepted_value)(如果有)
Phase 2|Accept/Accepted
Proposer 收到多数 Promise 后:
若看到任何已接受值,则取编号最高的那个值 v;否则可用自己的值
发送 Accept(n, v);Acceptor 若不违背承诺(n ≥ promised_n)则:
accepted_n ← n,accepted_value ← v(持久化),并回 Accepted(n, v)
决议/学习
当多数 Acceptor 对同一 (n, v) 回 Accepted,该值 v 被选定;Learner 收敛/提交
常见问题与对策
1. 多主竞争导致活锁
现象:多个 Proposer 同时用不同编号发起 Prepare/Accept,互相抢占,提案不断被更大编号打断,迟迟难以完成一次决议。
对策:选主(Leader)集中出提案;或加退避/随机化与编号跃迁策略,减少碰撞。
退避
现象:多个 Proposer 同时冲突 → 都收不到多数 → 继续发更大编号提案 → 无限抢占 → 活锁。
退避策略:当 Proposer 发现自己提案被抢占(比如收到了更大编号的 Promise),就不要立刻重试,而是等待一段时间再试。
意义:给对方机会先跑完一轮,避免无限抢占循环。
随机化
问题:如果大家都用同样的退避时间,可能同时醒来 → 再次冲突。
随机化策略:把等待时间加点随机抖动,例如退避时间 = 基础延迟 + 随机数。
效果:减少同步碰撞,提升协议最终达成的概率。
编号跃迁
现象:一个 Proposer收到更大编号的 Prepare/Promise,说明自己落后。
编号跃迁:它可以直接把自己下一次提案编号调得远远更大(而不是简单 +1),确保下一次不会再次被眼前的竞争者压制。
效果:快速超车,减少多次小幅度冲突。工程里常设计为 <term, proposerId> 形式,保证全局有序。
2. 网络分区 / 少数派可达
现象:无法触达多数派时,协议无法前进,但不会产出冲突决定。
对策:维持 CP 取舍(牺牲部分可用性换一致性),等待多数派恢复再推进。
3. 崩溃与恢复
现象:节点重启若丢失承诺/已接受状态,会破坏历史约束。
对策:Acceptor 必须落盘 promised_n / accepted_n / accepted_value,恢复后严格遵守已承诺语义。
为什么竞争只影响活性而不破坏安全?
1. Paxos 的安全性建立在多数派交集 + 承诺单调 + 值继承三件套上,这些约束与消息时序无关,因此永远成立。
2. 即使多个 Proposer 并发竞争、频繁抢占编号,Acceptor 仍旧遵守承诺后不再接受小编号这一不可回退规则。
3. 新一轮 Proposer 在进入 Phase 2 前必须继承在多数派回复中观测到的最高编号已接受值,因此无法绕过历史去提出相反的值。
4. 由于任意两个多数派集合必有交集,任何已被多数接受过的值都会被后继提案看见,从而被延续而非被覆盖。
5. 于是,并发竞争所造成的只是不断被更大编号打断,表现为延迟变大/无进展(活性受损),但不会产生两个不同的被选定值。
6. 在网络分区或只触达少数派的情况下,协议选择不前进而不是各自决定,因此宁停不乱,安全不失。
7. 崩溃恢复后,Acceptor 通过持久化状态继续履行既有承诺,保证历史不被遗忘,也就不可能因为重启而“选出另一个值”。
什么是多数派(Quorum)
定义:在 N 个 Acceptor 中,每次需要一个法定集合同意才能推进;若法定集合大小取 > N/2,则任意两个法定集合必有交集(至少一个共同成员)
意义:交集节点会把自己已接受过的最高编号值报告给后续 Proposer,使后者必须继承历史值,从而维持一致性。
任意两个多数派集合必有交集,交集的作用是:
假设某个值 v 已经在多数派 A 被接受(chosen 的候选)
后续任何新 Proposer 都必须再从另一个多数派 B收集 Promise
因为 A ∩ B ≠ ∅,所以至少有一个 Acceptor 会记得 v
新 Proposer 必须继承这个历史值 v(规则:继承已接受的最高编号的值)
因此 Paxos 能保证一旦某个值可能被多数派选中,之后所有被选定的值都必须与它一致
为什么后续任何新 Proposer 都必须再从另一个多数派 B收集 Promise?
因为不知道历史上的多数派是哪一组,为了保证能看见那段历史,必须向多数派 B 收集Promise,这样可保证 B 与多数派 A必有交集。
一旦两组都是多数派,就有 A∩B≠∅。交集里的某个 Acceptor 会把自己已接受的最高对 (n_a, v_a) 报告给Proposer ,Proposer 就被迫继承该值,安全性因此成立。
5 句自然语言证明多数派交集不会选出两个不同的值
1. 假设某值 v 已在一个法定集合 Q1内被多数 Acceptor 接受。
2. 之后任何新的 Proposer 想要继续推进,必须从另一个法定集合 Q2收集承诺。
3. 因为法定集合都是多数,故 Q1 与 Q2 必有交集,存在至少一个共同的 Acceptor。
4. 该交集 Acceptor 会按规则报告它已接受过的最高编号值,于是新 Proposer 必须继承该值进入 Phase 2。
5. 因此,任何后来被选定的值都与 v 一致,不可能再选出与 v 不同的第二个值,故多数派交集不会选出两个不同的值。
Paxos vs Raft 异同点
相同点
目标一致:都要实现崩溃容错的复制状态机
依赖条件:需要多数派可用,节点维护持久化元数据(承诺/日志/任期)才能保证崩溃恢复后 Safety。
结果保证:在部分同步网络中,Safety 永远成立,Liveness 在稳定时期成立。
不同点(工程视角)
可理解性
Paxos:抽象层次高,核心论文偏“数学证明”;需要额外补充选主、多槽位日志等细节才能变成可用系统。
Raft:设计目标就是易于理解。明确提出了 Leader-based 流程:任期、心跳、日志匹配、选主、成员变更。
日志与成员变更
Paxos:基本论文只解决单次决议,Multi-Paxos + 工程补丁才形成日志复制;成员变更没有标准化方案。
Raft:把日志复制、任期切换、Joint Consensus(联合共识的配置变更)都标准化为协议的一部分。
实现生态
工业界常见的 Multi-Paxos 实现 ≈ Leader 驱动复制,体验上和 Raft 很像,但实现复杂度高。
Raft 的落地实现有完整生态;Paxos 系统更多是历史遗产或大厂定制。
若从零做复制,为什么可能更偏向 Raft?
因为 Raft 在设计时就把 Leader 选举、日志复制、任期、配置变更全部纳入协议核心,流程直观、易实现、社区支持丰富;对一个新项目来说,可以快速实现一个可维护的高可用系统。相比之下,Paxos 虽然理论完备,但要从论文到工程落地,还需要自己拼接 Multi-Paxos、Leader 选主、重配置等模块,复杂度高。
若接手已有 Paxos 系统,我需要重点关注什么?
必须清楚它是基于 Multi-Paxos 的哪个变体(是否有稳定 Leader、是否支持批量/流水线);明确 Acceptor 的持久化语义;确认系统是否已经实现了重配置机制(例如 Joint Consensus 或自研方案);同时要评估其冲突处理和活性优化手段(退避、编号跃迁、Leader 心跳)。只有弄清这些工程化补丁,才能确保 Paxos 系统在实际环境里安全且有足够活性。