想象一群老朋友在群里商量周末聚餐:有人想吃火锅,有人想吃日料,有人正坐地铁没信号。如果大家各说各话、消息又有快有慢,最后怎么保证所有人都走进同一家店?Paxos 协议就是解决这类难题的“聚会规则”——它保证不管消息多乱、参与者多磨蹭,系统最终会一致选出一个大家都认同的决定,而且绝不会出现“一半人去了火锅店、一半人去了日料店”的荒诞局面。这套规则不靠某个人发号施令,而是靠一套精巧的编号机制和两阶段投票流程。本文就从这场“聚餐选店”出发,拆解 Paxos 的角色分工、提案编号、两阶段协商、协议推导、工程实践,以及它在数据库、配置中心等真实系统中的落地方式。

岗位关联

掌握 Paxos 是理解分布式一致性的基石,也是数据库、云原生、分布式 AI 平台从业者做架构设计与面试通关的核心技能。

目录
  1. 可视化演示
  2. 起源与背景
  3. 核心角色
  4. 提案编号
  5. 准备阶段
  6. 接受阶段
  7. 协议推导
  8. 工程实践
  9. 应用案例
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

起源与背景

一群朋友在群里讨论周末聚餐,消息有快有慢,有人半天不回复,还有人的手机在电梯里没了信号。如果非要等所有人都表态才动身,这顿饭可能永远约不成。于是大家形成一种默契:只要有超过一半的人回话并同意,就按这个方案走,没看到消息的人事后看到群公告再跟上。这个默契,就是“多数派原则”的雏形。

分布式系统也一样。多台服务器就像一群朋友,一条“写请求”就是一个聚餐提议,节点之间的网络就像微信消息:会延迟、会丢失、某个节点还会直接宕机“失联”。Paxos 要解决的,正是在这种混乱环境下让所有正常节点就同一个值达成一致,这就是分布式领域的“共识问题”。值得一提的是,计算机科学家 Leslie Lamport 最初提出 Paxos 时,背景设定源自“拜占庭将军问题”——但 Paxos 解决的是简化版:将军们不会叛变,只会联系不上或迟到,即只崩溃、不撒谎的故障模型。

在这个模型下,系统能继续决策的底气来自一个简单的数学事实:

回到聚餐场景:5 个朋友里只要有 3 个人回了消息,地点就能定下来;另外两个人在电梯里没有信号,丝毫不影响这顿饭如期进行。多数派,就是 Paxos 世界里“联系人失联也能成事”的底气。

∣Q∣>N2\displaystyle |Q| > \frac{N}{2}
只要有超过半数的节点响应,就能形成“法定多数”(quorum),从而推动决策继续。
  1. 集合大小$|Q|$ 表示成功响应本次协商的节点个数。比如 5 个节点中有 3 个回话,则 $|Q|=3$。
    ∣Q∣=3\displaystyle |Q| = 3
  2. 节点总数$N$ 表示系统中参与者的总数。聚餐例子里 5 位朋友,所以 $N=5$。
    N=5\displaystyle N = 5
  3. 严格大于必须满足 $3 > 2.5$ 这样不取等号的不等式。恰好一半不能算多数,否则可能出现两派各占一半、互不相让的僵局。
    3>52\displaystyle 3 > \frac{5}{2}

核心角色

聚会里有三种人:抢着出方案的人、被问到时表态的人、以及压根没参与讨论、事后才听说结果的人。Paxos 同样给每个节点分配了逻辑角色,而且一个人可以同时扮演多种角色——就像你既可能主动提议“去吃火锅”,也要在别人提议时投票,最后还要把结果转发给没能到场的群友。

Paxos 定义了三个角色:Proposer(提议者)负责提出提案,并推动协商向前走;Acceptor(接受者)负责响应各种请求、记录自己的投票状态,是真正“做决定”的人;Learner(学习者)负责在值被选定后得知最终结果。工程师常把 Replica 节点同时配置成 Acceptor 和 Learner,让一个节点既投票又学习结果,这就是“角色兼任”。

整个协商过程可以浓缩成一条流水线:

角色各司其职,就像聚餐群里有人负责提方案、有人负责回应、有人等通知。而同一个人身兼数职,也正对应着现实中“一个节点既是投票者又是学习者”的常见部署。

提案(n,v)→多数派接受选定\displaystyle \text{提案}(n, v) \xrightarrow{\text{多数派接受}} \text{选定}
提案由“编号 + 值”组成,编号定优先级,值才是最终要达成一致的内容;只有多数派点头,提案才升级为“选定”。
  1. 提案 (n, v)一个完整的提案由编号 $n$ 和值 $v$ 绑定。编号相当于号码牌,值就是聚餐地点这类实际内容。
    提案=(n,v)\displaystyle \text{提案} = (n, v)
  2. 多数派接受超过半数的 Acceptor 回复“接受”,箭头上方的条件成立,这是从“提议”到“定案”的唯一通行证。
    多数派接受  ⟺  ∣Q∣>N2\displaystyle \text{多数派接受} \iff |Q| > \frac{N}{2}
  3. 选定箭头指向的终点,意味着这个值成为系统中唯一的官方结论,Learner 们从此只能学习它。
    选定=不可推翻的唯一结果\displaystyle \text{选定} = \text{不可推翻的唯一结果}

提案编号

两个朋友同时抢着说话时,主持人会发号码牌:谁号码大,谁先讲。Paxos 里的提案也需要这样的“话语权标尺”——提案编号。它必须满足两个性质:全局唯一(不存在两个编号相同的提案)和单调递增(越晚发起的提案编号越大)。

工程上最常用的编号生成策略是“轮次 + 节点 ID”拼接:每一轮协商用一个递增值,再乘以节点总数,加上发起者的节点 ID。这样即使多个节点在同一轮同时发起提案,也不会撞号,而且后来者天然拥有更大的话语权。

号码牌越大,话语权越大——这就是编号的全部秘密。正如聚会中 7 号客人开口后,6 号及以前的提议都要让路,Paxos 里编号较小的提案天然处于弱势地位。

n=轮次×节点数+节点 ID\displaystyle n = \text{轮次} \times \text{节点数} + \text{节点 ID}
编号不是随便写的数字,它决定了“谁说了算”:Acceptor 只搭理比当前已承诺编号更大的请求。
  1. 轮次每次发起新一轮协商时递增,保证“发起越晚、编号越大”。
    轮次:r,r+1,r+2,…\displaystyle \text{轮次}: r, r+1, r+2, \dots
  2. 节点数乘以参与者总数 $N$,把编号空间按轮次切成互不重叠的区间,避免不同轮的编号混淆。
    区间宽度=N\displaystyle \text{区间宽度} = N
  3. 节点 ID在同一轮内用节点 ID 区分不同发起者,确保全局唯一。
    nnode∈{0,1,…,N−1}\displaystyle n_{\text{node}} \in \{0, 1, \dots, N-1\}

准备阶段

正式表决之前,聪明的提议者会先做两件事:探一探大家的口风,顺便“锁定投票权”。就像你挨个打电话问:“如果我说去这家店,你们答应考虑吗?顺便告诉我你们现在最倾向于哪家。”这样一问,既知道大家目前的倾向,又让朋友们承诺“在你给出正式方案前,不再考虑更小的提议”。

在 Paxos 里,这个探口风的动作叫 Prepare 阶段。提议者向多数派发送 Prepare(n),带上自己的编号。Acceptor 收到后,如果 $n$ 大于自己已承诺过的编号 $n_{\text{promise}}$,就回复 Promise(n_promise, v_max)——既承诺“此后不再接受编号小于 $n$ 的提案”,又把自己接受过的编号最大的提案值 $v_{\text{max}}$ 一并交还。如果编号不够大,就拒绝或直接忽略。

探完口风,提议者心里有了底:既确认了自己能否拉到多数派,也知道了“历史上有没有人已经接近选定某个值”。这就像你问完一圈发现三个人都倾向日料店——那你接下来的正式提议,自然要顺着这个方向走,而不是逆着来。

Promise(npromise,vmax)如果n>npromise\displaystyle \text{Promise}(n_{\text{promise}}, v_{\text{max}}) \quad \text{如果} \quad n > n_{\text{promise}}
Prepare 阶段不产生最终决定,它只做两件事:收集“旧值情报”和锁定“未来投票权”。
  1. 编号比较 $n > n_{\text{promise}}$只认更大的编号,这是 Paxos 中所有“让位”逻辑的地基。
    nnew>nold\displaystyle n_{\text{new}} > n_{\text{old}}
  2. $n_{\text{promise}}$Acceptor 记忆里“话语权最大的编号”,是它答应让位的上限,之后所有更小编号的请求统统不理会。
    npromise=max⁡{n∣已承诺过的编号}\displaystyle n_{\text{promise}} = \max\{n \mid \text{已承诺过的编号}\}
  3. $v_{\text{max}}$Acceptor 已接受过的编号最大的提案值,随 Promise 一起给提议者,这是“防止翻案”的关键情报。
    vmax=argmax(n,v) acceptedn\displaystyle v_{\text{max}} = \text{argmax}_{(n, v) \text{ accepted}} n

接受阶段

探完口风,就该正式表决了。Paxos 的 Accept 阶段:提议者从所有 Promise 中挑出编号最大的那个已接受值 $v_{\text{max}}$;如果多数派从未接受过任何值,就用自己最初想定的值 $v_{\text{self}}$。然后向这些 Acceptor 发送 Accept(n, v)。

收到 Accept 的 Acceptor 会检查:只要自己还没承诺过更大的编号,就接受并回复。当超过半数的 Acceptor 都回复接受时,值就被正式选定。这条“旧值优先、新值兜底”的规则,是整个协议防止“两个值同时胜出”的最后一道闸门。

就像你打电话发现三个人都已经倾向日料店,于是正式提议“大家去吃这家日料”,三人同意,聚餐地点就此确定。没看消息的两位朋友后来看到群公告,也会跟进到同一家店——没人会提出第二套地点方案,因为新方案必须沿用已被多数派认可的值。

vpropose={vmax若多数派中有已接受值vself否则\displaystyle v_{\text{propose}} = \begin{cases} v_{\text{max}} & \text{若多数派中有已接受值} \\ v_{\text{self}} & \text{否则} \end{cases}
值的选择规则是 Paxos 安全的核心:有旧值必须沿用旧值,没旧值才允许提出新值。
  1. $v_{\text{max}}$(有旧值用旧值)如果 Promise 里带回了一些已接受值,必须选编号最大的那个,确保新提案“继承”前人已经接近完成的共识。
    vmax←max⁡(n,v){n∣(n,v)∈Promises}\displaystyle v_{\text{max}} \leftarrow \max_{(n, v)} \{ n \mid (n, v) \in \text{Promises} \}
  2. $v_{\text{self}}$(没旧值用新值)如果所有 Promise 都表明“从未接受过任何值”,说明系统是张白纸,提议者可以填入自己最初想定的值。
    vpropose=vself\displaystyle v_{\text{propose}} = v_{\text{self}}
  3. 分段选择整个公式是一个“二选一”的分支结构,它保证无论系统处于什么历史状态,新提案都不会与旧共识冲突。
    vpropose=f(vmax,vself)\displaystyle v_{\text{propose}} = f(v_{\text{max}}, v_{\text{self}})

协议推导

Paxos 的规则看起来绕,其实是从一条底线反推出来的:绝对不能出现两个不同的值都被选为共识。这条底线在数学上叫安全性(Safety)。围绕它,Lamport 一步步加约束,像给房子层层加固承重梁。

首先是最基本的 P1:Acceptor 必须接受它收到的第一个提案。没有这条,大家都不表态,系统永远无法开始。但 P1 不够——两个提议者可能各自拉到一半人,选出一半赞成火锅、一半赞成日料。于是加上 P2:一旦值 $v$ 被选定,任何编号更大的提案也必须携带值 $v$。P2 又需要可操作的形式,最终收敛为 P2c:通过 Prepare 阶段“收集旧值”来落实这条约束。

Paxos 的每一处巧妙设计,都指向同一个目标:让“已选定的值永不改变”成为一条物理定律。聚餐规则不是拍脑袋定的,而是从“最终只能有一家店”这条底线一层层推出来的。

P2c:一旦值 v 被选定,任何编号更大的提案都必须携带值 v\displaystyle P2^c: \text{一旦值 } v \text{ 被选定,任何编号更大的提案都必须携带值 } v
P2c 是 Paxos 安全性的数学化身,两阶段协议本质上就是它在工程上的可执行版本。
  1. “一旦…被选定”只要有一个多数派确认了 $v$,这条约束从那一刻起立即生效,没有例外窗口。
    chosen(v)⇒约束生效\displaystyle \text{chosen}(v) \Rightarrow \text{约束生效}
  2. “任何编号更大的提案”无论未来谁来提议、编号有多大,都不能“翻案”,因为编号大只代表话语权大,不代表能改结果。
    ∀n′>n:v′=v\displaystyle \forall n' > n: v' = v
  3. “都必须携带值 $v$”系统中只允许存在一个共识值,这就是安全性的数学表达——多个提案可以不同,但一旦选定,全体殊途同归。
    v′=v恒成立\displaystyle v' = v \enspace \text{恒成立}

工程实践

理论完美的协议,放到真实世界会遇到一个尴尬场景:两个提议者轮流用更大的编号抢占话语权,结果谁也凑不齐多数派,系统陷入“活锁”——像两个朋友抢着说话,一个说“我要讲”,另一个说“我编号更大先讲”,吵到天黑也没定下餐厅。经典 Paxos 只保证安全,不保证活性,即不保证“一定能选出来”。

工程上的破局之道有三板斧:超时重试(A 没等到响应就换更大编号再来)、随机退避(失败后随机等待一段时间,避免两人又同时抢)、以及最关键的 领导者选举(Leader Election)——先通过一轮 Paxos 选出一个固定 Leader,此后只允许 Leader 发起提案。Leader 稳定后,Multi-Paxos 还能进一步优化:跳过 Prepare 阶段,直接发 Accept,把两轮消息压缩为一轮。

聚会选出一个“主策划”之后,大家不再七嘴八舌地抢话语权,而是等主策划直接说“今天吃这家”,快速表决。省去了反复试探的客套,聚餐效率一下子高了起来——这就是 Multi-Paxos 在生产系统中的日常。

Accept(v)→Leader 稳定且多数派确认选定\displaystyle \text{Accept}(v) \xrightarrow{\text{Leader 稳定且多数派确认}} \text{选定}
Multi-Paxos 是生产环境最常用的形态:选主定于一尊,后续协商直接从第二阶段开始。
  1. Leader 稳定系统选出一个公认的主策划,其余节点让出提议权,从“群雄逐鹿”变成“一锤定音”。
    ∃!Leader:只有 Leader 可发起新提案\displaystyle \exists! \text{Leader}: \text{只有 Leader 可发起新提案}
  2. 直接 Accept跳过 Prepare 的消息往返,把两轮协商压缩为一轮,吞吐几乎翻倍。
    消息轮数:2→1\displaystyle \text{消息轮数}: 2 \rightarrow 1
  3. 多数派确认Leader 的提案仍要过“过半接受”这一关,安全底线并没有因为优化而放松。
    ∣Qaccept∣>N2\displaystyle |Q_{\text{accept}}| > \frac{N}{2}

应用案例

这套“聚餐规则”已经被无数关键系统默默使用。最典型的场景是数据库选主:主库宕机后,多个备库通过共识协议选出新主库,保证业务不中断;配置中心则用共识协议保证所有服务读到同一个配置值,不会出现一半服务用旧配置、一半用新配置的“精神分裂”。

etcd、ZooKeeper 这类协调服务本质上都在实现 Paxos 的思想——Raft 就是把它工程化、易理解化的变体,核心精神完全一致。那么问题来了:为什么“多数派”这个看似简单的机制,能支撑起这么强的正确性保证?答案是一个数学事实:任意两个多数派必然有交集。第一次协商的多数派和第二次协商的多数派至少共享一个节点,这个“传话人”确保后一次协商一定能了解到前一次的结果。

就像聚餐确认后,没看到消息的两位朋友后来看群公告,也能准时走进同一家店——一切归功于“多数派必有交集”这条数学铁律。Paxos 的优雅之处正在于此:用一条简单的集合性质,撑起整个分布式世界的一致性承诺。

Q1∩Q2≠∅,∀Q1,Q2:∣Qi∣>N2\displaystyle Q_1 \cap Q_2 \neq \varnothing, \quad \forall Q_1, Q_2: |Q_i| > \frac{N}{2}
多数派交集不变量是 Paxos 正确性的根基,它保证了任何两次决策之间都有一条“信息桥梁”。
  1. 任意两个多数派 $Q_1, Q_2$两次协商各自动员起来的响应集合,它们不需要完全相同,只要都超过半数。
    ∣Q1∣>N2,∣Q2∣>N2\displaystyle |Q_1| > \frac{N}{2}, \quad |Q_2| > \frac{N}{2}
  2. 交集非空 $Q_1 \cap Q_2 \neq \varnothing$两个超过半数的集合必然至少共享一个节点,这个节点把旧会议的结论“带”进新会议。
    ∃节点 c:c∈Q1∧c∈Q2\displaystyle \exists \text{节点 } c: c \in Q_1 \wedge c \in Q_2
  3. 正确性的根基正是这条不变量,让 Paxos 在任何消息乱序、节点延迟的条件下都不可能选出两个不同的值。
    Safety  ⟺  Q1∩Q2≠∅\displaystyle \text{Safety} \iff Q_1 \cap Q_2 \neq \varnothing

AI 应用场景

场景一:AI 训练平台元数据高可用

阶段:分布式系统基础设施 / 平台架构

解决的问题:训练任务的元数据(模型路径、超参数、训练状态)通常存在数据库中,如果主库单点故障,整个调度系统就会瘫痪。传统做法是人工切换主库,慢且容易出错;用 Paxos 类共识协议选主,多数派节点自动确认新主,写入不丢失。

具体案例:某 MLOps 平台用基于 Paxos 思想的 etcd 存储任务状态,5 节点集群即使挂掉 2 台,仍能正常读写、继续调度训练任务。

场景二:训练任务调度器选主

阶段:任务调度与容错

解决的问题:训练集群的调度器如果多副本同时运行,会重复下发任务、争抢 GPU 资源。需要通过共识机制选出一个 Leader,保证同一时刻只有一个调度器在写状态。

具体案例:Kubernetes 控制面通过 etcd 的租约机制选主,确保调度器和控制器管理器始终只有一个活跃副本,其余副本 standby 待命。

场景三:模型灰度发布配置一致性

阶段:模型部署与配置管理

解决的问题:模型做 A/B 测试时,所有推理节点必须读到同一个“流量切分比例”。如果某些节点读到旧值、某些读到新值,流量会被重复或漏算。

具体案例:某推理平台把流量比例写入配置中心,所有推理副本通过 Paxos 类协议读到一致的最新值,避免“50% 和 70% 两个版本并存”的混乱。

Python 演示

python63 行
import random  class Acceptor:    def __init__(self, name):        self.name = name        self.promised = 0        self.accepted_n = 0        self.accepted_v = None     def prepare(self, n):        if n > self.promised:            self.promised = n            return ("promise", self.accepted_n, self.accepted_v)        return ("refuse", None, None)     def accept(self, n, v):        if n >= self.promised:            self.promised = n            self.accepted_n = n            self.accepted_v = v            return "ok"        return "no"  class Proposer:    def __init__(self, value):        self.value = value        self.n = random.randint(1, 100)     def run(self, acceptors):        promises = []        for a in acceptors:            r = a.prepare(self.n)            if r[0] == "promise":                promises.append(r)        if len(promises) <= len(acceptors) // 2:            return "提案未获多数派承诺, 请增大编号重试"         chosen = [r for r in promises if r[1] > 0]        if chosen:            self.value = max(chosen, key=lambda r: r[1])[2]         ok_count = 0        for a in acceptors:            if a.accept(self.n, self.value) == "ok":                ok_count += 1        if ok_count > len(acceptors) // 2:            return "值" + str(self.value) + "被选定, 编号:" + str(self.n)        return "接受票数不足, 需要重试"  def main():    acceptors = [Acceptor("A1"), Acceptor("A2"), Acceptor("A3")]    proposer = Proposer("hotpot")    print(proposer.run(acceptors))    for a in acceptors:        print(a.name + ": accepted_n=" + str(a.accepted_n) +              ", accepted_v=" + str(a.accepted_v))  if __name__ == "__main__":    main()
目的:用三个 Acceptor 和一个 Proposer 模拟单值 Paxos 的两阶段协商,运行后可以看到 Prepare 收集承诺、Accept 形成多数派选定的完整过程。
  1. class Acceptor:接受者节点,维护两个状态:已承诺编号 promised、已接受提案 (accepted_n, accepted_v)。
  2. def prepare(self, n):接受者的“探口风”反应:判断新编号是否比已承诺的更大,相当于“这个号码牌我认不认”。
  3. if n > self.promised:编号比较是 Paxos 所有决策的地基,只有更大的编号才有权覆盖旧承诺。
  4. return ("promise", self.accepted_n, self.accepted_v)把已接受的最大编号提案随 Promise 带回,正是 Prepare 阶段“收集旧值”的动作。
  5. if r[0] == "promise":提议者统计有多少节点愿意承诺,少于半数说明话语权不够,要换更大编号重来。
  6. self.value = max(chosen, key=lambda r: r[1])[2]按编号取最大旧值,让新提案“继承”前人的选择,绝不覆盖共识。
  7. if ok_count > len(acceptors) // 2:接受数超过半数(这里 3 个中超过 1 个即 2 个以上,严格应超过半数),值正式被选定。

常见误区

误区“Paxos 不就是大家举手投票、超过一半就赢吗?这和普通的会议表决有什么区别?”

正解普通投票只约定“结果怎么算”,没约定“发言顺序”和“旧决定怎么办”。Paxos 的核心是多了一套编号约束和两阶段流程:先通过 Prepare 确认话语权并收集旧值,再 Accept 正式表决。这两个机制保证即使出现两个同时举手的人,系统也不会选出两个矛盾的结果。就像聚会里两个人同时喊出不同餐厅,最后也只会有一家店胜出。

为何常见:因为 Paxos 的结果确实表现为“过半即通过”,表面看起来与简单投票无异,容易让人忽略两阶段流程才是协议的灵魂。

误区“Prepare 阶段大家回复了承诺,此时值不是已经确定了吗?”

正解Prepare 只做两件事:锁定投票权和侦察旧值。真正的值由 Accept 阶段决定。Acceptor 的 Promise 只是“暂不考虑更小编号的提案”,不是“我选这个值”。顺序搞反,会对“为什么 Promise 要带旧值”完全理解错误——旧值不是投票结果,而是给提议者参考的历史情报。

为何常见:因为 Prepare 阶段消息最多、存在感最强,初学者容易把“收集信息”误判为“最终决策”。

误区“Paxos 这么严谨,是不是任何时候都能快速达成一致?”

正解Paxos 保证的是安全性(Safety)——绝不产生矛盾结果;但不保证活性(Liveness)——两个提议者轮流用更大编号抢占时,会出现“活锁”,谁也赢不了。工程上必须靠选 Leader、超时重试、随机退避等手段来保证最终能选定。就像两个人抢着说话,规则保证“只会有一个结论”,但不保证“你们能吵完”。

为何常见:因为协议文档往往先讲安全证明,活性问题散落在工程讨论里,容易让人误以为协议会自动收敛。

误区“Learner 不是 Paxos 的正式流程吗?为什么有些实现里看不到它?”

正解Learner 是“结果通知”的接收方,协议只保证值被选定后,Learner 能通过查询某个 Acceptor 得知结果。它既不参与两阶段协商,也不参与投票。工程上可以独立部署 Learner,甚至不显式广播学习结果,让客户端直接读取确认即可。它是观众,不是演员。

为何常见:因为角色图常把 Learner 画在流程末尾,容易误以为它是协议的第三个阶段。

误区“拜占庭将军问题都叫拜占庭了,Paxos 应该也能防叛变吧?”

正解Paxos 针对的是“崩溃故障模型”——节点会宕机、消息会丢、响应会慢,但节点会老老实实按协议执行,不会撒谎。恶意节点需要 PBFT 等拜占庭容错算法。把 Paxos 当作防欺骗工具,是概念错位。就像聚会中你假设朋友都诚实,只是有人会迟到,而不是假设有人故意放烟雾弹。

为何常见:拜占庭将军问题常与 Paxos 出现在同一章节,初学者容易把两种故障模型混为一谈。

面试题

Q1. Paxos 为什么要求“多数派”而不是“全体一致”?

单选题 · easy

  • A.方便少数服从多数
  • B.任意多数派必有交集← 正确答案
  • C.响应速度通常更快
  • D.避免消息被延迟

答案:B。多数派的核心价值在于“任意两个多数派必然有交集”,这个交集节点能把前一次协商的结果带给后一次协商,从而防止两个值同时胜出。其余选项要么是附加好处,要么只是表象,不是数学上的根本原因。

Q2. Acceptor 收到编号不大于已承诺编号的 Prepare 时,正确做法是?

单选题 · easy

  • A.立即接受该提案
  • B.返回自己的旧值
  • C.拒绝或忽略该请求← 正确答案
  • D.把编号加一重试

答案:C。编号不比已承诺编号大,说明话语权不够,Acceptor 应当拒绝或忽略,以维护“只认更大编号”的承诺。返回旧值是承诺成功之后的行为,编号加一重试是提议者的事,接受该提案则直接违背承诺。

Q3. 以下哪个不是 Paxos 的经典角色?

单选题 · easy

  • A.提议者角色
  • B.接受者角色
  • C.学习者角色
  • D.观察者角色← 正确答案

答案:D。Paxos 只有 Proposer、Acceptor、Learner 三种角色。“观察者”是分布式系统里的通用说法,不是 Paxos 协议定义的经典角色。就像聚会里只有“提方案的人”“回应的人”“听结果的人”,没有“看热闹的人”这种正式身份。

Q4. 在 Prepare 阶段,Acceptor 回复 Promise 时需要附带什么信息?

单选题 · mid

  • A.自己接受过的全部历史值
  • B.编号最大的已接受提案值← 正确答案
  • C.当前系统中最新的日志
  • D.自己节点上的时间戳

答案:B。Promise 只需要携带“已接受过的编号最大的提案值”,让提议者判断系统里是否已有接近选定的值。全部历史值冗余且浪费带宽,日志和时间戳都不是协议要求的字段。这就像探口风时只要告诉大家你最倾向哪家店,不必把整个聊天记录都翻出来。

Q5. 提议者收到多数派 Promise 且其中含多个旧值时,应选择哪个值?

单选题 · mid

  • A.编号最大的那个旧值← 正确答案
  • B.最先到达的那个旧值
  • C.自己最初提出的新值
  • D.任意一个旧值即可

答案:A。必须选编号最大的旧值,因为编号越大越接近最终选定状态,选它才能满足“更高编号提案必须携带已选定值”的安全约束。选最先到达或任意值都可能覆盖更接近共识的结果,选自己的新值则可能推翻已有共识。

Q6. Multi-Paxos 在 Leader 稳定后最大的优化是什么?

单选题 · mid

  • A.跳过重复的 Prepare← 正确答案
  • B.不再需要提案编号
  • C.取消多数派判定
  • D.允许角色互相转换

答案:A。Leader 稳定后只有它一人发起提案,不存在编号竞争,因此可以省略 Prepare 阶段,直接从 Accept 开始,消息轮数由两轮降为一轮。但编号、多数派判定依然需要,角色转换也不是优化点。就像聚会选了主策划后,他直接说方案即可,不必每次重新探口风。

Q7. P2c 不变量的核心意思是什么?

单选题 · hard

  • A.编号必须从零开始递增
  • B.选定后更高编号须同值← 正确答案
  • C.每个节点只接受一次
  • D.提案必须由主节点发起

答案:B。P2c 规定:一旦值 v 被选定,任何编号更大的提案也必须携带值 v。这是 Paxos 安全性的数学核心,通过 Prepare 收集旧值来实现。编号起止、接受次数、Leader 约束都是实现细节,不是不变量本身。

Q8. 关于 Paxos 的角色与运行,下列说法正确的有?

多选题 · mid

  • A.节点可同时担任提议与接受← 正确答案
  • B.同节点也可作为学习者← 正确答案
  • C.请求被忽略时应增大编号重试← 正确答案
  • D.学习者必须参加投票环节

答案:ABC。Paxos 角色是逻辑概念,物理上一节点可兼任 Proposer 和 Acceptor,也可同时作为 Learner 学习结果;Prepare 被忽略说明编号不够大,应增大编号重试。学习者只是被动接收结果,不参与投票,D 错误。

Q9. 经典 Paxos 的“活锁”问题可以采取哪些手段缓解?

多选题 · hard

  • A.选举一个临时的领导者← 正确答案
  • B.失败的请求随机退避后再试← 正确答案
  • C.全局约定重试的固定间隔
  • D.提高法定多数派的比例

答案:AB。选 Leader 让提议权归一,随机退避避免两人同时抢号,这两者是经典解法。固定间隔重试会让两个提议者反复“撞车”,反而加剧活锁;提高多数派比例只会让达成共识更难,无助于活性。

Q10. 关于 Paxos 安全性的推导与实现,正确的有?

多选题 · extreme

  • A.任意两个多数派必有共同节点← 正确答案
  • B.Prepare 收集旧值以满足 P2c← 正确答案
  • C.编号只需全序且可比较大小← 正确答案
  • D.所有消息都必须按序到达

答案:ABC。多数派交集是安全性的根基;Prepare 收集旧值正是 P2c 的工程实现;编号只需满足全序关系、能比较大小,不需要连续或从零开始。Paxos 恰恰是设计来容忍消息乱序的,D 错误。