土法炼钢兴趣小组的算法知识备份

【分布式系统百科】FLP、CAP 与不可能性结果:被误读的三座里程碑

文章导航

分类入口
distributed
标签入口
#flp#cap#pacelc#impossibility#consensus#linearizability#wait-free#distributed-systems

目录

FLP、CAP 与不可能性结果:被误读的三座里程碑

你大概率在面试或技术博客里见过这两个说法:

但 Raft 跑在”异步”网络上,共识达成得好好的——etcd 集群每天处理数百万次写入,没有违反物理定律。Spanner 声称同时提供外部一致性(比线性一致性更强)和高可用性,Google 也没被理论计算机科学家找上门。

矛盾在哪?

不在定理本身。FLP 和 CAP 都是经过严格证明的数学定理,它们不可能”错”。矛盾在于:大多数工程师(包括不少写教材的人)在引用这些定理时,跳过了精确的前提条件和术语定义。“异步”到底是什么意思?“一致性”指的是哪种一致性?“可用”的标准是什么?这些细节决定了定理是否适用于你面前的系统。

这篇文章做一件事:回到原始论文,把四个不可能性结果的精确陈述、证明直觉和工程含义逐一拆清楚。不是为了背诵定理,而是为了理解分布式系统的理论边界到底画在哪里——以及工程师如何在边界内做出正确的取舍。

一、FLP 不可能定理

背景与精确陈述

1985 年,Michael Fischer、Nancy Lynch 和 Michael Paterson 发表了论文”Impossibility of Distributed Consensus with One Faulty Process”。这篇论文获得了 2001 年 Dijkstra 奖,被认为是分布式计算理论的奠基性结果之一。

FLP 定理的精确陈述需要先定义模型:

系统模型:N 个进程(Process)(N >= 2)通过异步消息传递(Asynchronous Message Passing)通信。“异步”在这里有严格含义:

故障模型:最多有 1 个进程可能发生崩溃故障(Crash Failure)——进程停止执行,不再发送消息,但不会发送错误消息(没有拜占庭行为)。

共识问题的定义:每个进程有一个输入值(0 或 1),需要决定(Decide)一个输出值,满足三个性质:

性质 含义
一致性(Agreement) 所有做出决定的正确进程,决定值相同
有效性(Validity) 决定值必须是某个进程的输入值
终止性(Termination) 每个正确的进程最终都会做出决定

FLP 定理:在上述纯异步模型中,即使最多只有 1 个进程可能崩溃,也不存在一个确定性协议能同时满足一致性、有效性和终止性。

注意每一个限定词:纯异步确定性1 个崩溃。去掉任何一个,定理就不成立。这正是 FLP 之后三十年共识研究的突破口。

证明直觉:二值性与对手调度

FLP 的证明精巧而反直觉。核心思路是构造一个”对手”(Adversary),它通过控制消息的送达顺序,让任何确定性协议永远无法做出决定。

首先定义几个概念:

配置(Configuration) 是系统在某一时刻的全局快照:所有进程的内部状态,加上所有正在传输中的消息。

步骤(Step) 是一个原子事件:某个进程收到某条消息(或者一个特殊的”空消息”表示没有新消息到达),然后根据协议规则更新自己的状态并发送新消息。

从一个配置出发,不同的步骤顺序会导致不同的后续配置。所有可达的配置形成一棵树(或者说有向无环图)。

现在看这棵树上的每个配置节点:

FLP 证明直觉:二值配置与对手调度

证明分两步:

第一步(引理 2):存在一个初始二值配置。

直觉是这样的:如果所有进程的输入都是 0,协议必须决定 0(有效性要求)。如果所有进程的输入都是 1,协议必须决定 1。从”全 0”到”全 1”,我们可以逐个翻转进程的输入值。每翻一次,决定值要么还是 0,要么变成了 1。一定存在某一次翻转是”临界点”——翻转前决定 0,翻转后决定 1。在这个临界点上,如果被翻转的那个进程恰好在第一步之前就崩溃了(它还没来得及告诉任何人自己的输入值),剩下的进程面对的局面是相同的,但协议却应该给出不同的决定。这就意味着这个初始配置必须是二值的——两种决定值都有可能。

第二步(引理 3):从任何二值配置出发,对手总能找到一步,使得系统进入另一个二值配置。

这是证明的核心。假设 C 是一个二值配置,e 是某个待处理的事件(某个进程即将收到的消息)。对手考虑所有可能的调度顺序。如果不管怎么调度,应用 e 之后都进入单值配置,那么必定存在两个”相邻”的配置(只差一步),一个是 0-valent,一个是 1-valent。但在异步模型中,这两个配置之间的差异只取决于一个进程的一步操作。如果这个进程恰好崩溃了,剩下的进程无法区分这两种情况——一个应该决定 0,一个应该决定 1,矛盾。所以假设不成立,对手一定能找到一条通往二值配置的路径。

把两步合在一起:从初始二值配置开始,对手可以无限地让系统停留在二值状态,永远不做出决定。终止性被违反了。

这个证明有一个精妙之处:对手不需要做任何”恶意”的事情。它只是合法地延迟消息——在异步模型中,任意长的延迟都是允许的。对手利用的正是”异步”这个假设。

FLP 之后:共识为什么没有死

FLP 发表时,很多人以为共识问题已经被判了死刑。但实际上,FLP 做的是划出一条精确的边界线,而工程师的工作就是在边界线的另一边找到立足点。三条路线分别放松了 FLP 的一个前提假设:

路线一:部分同步模型(Partial Synchrony)。 Dwork、Lynch 和 Stockmeyer 在 1988 年提出了部分同步模型:存在一个未知的全局稳定时间(Global Stabilization Time,GST),GST 之后,所有消息都会在有界延迟 Delta 内送达。在 GST 之前,系统表现得像纯异步——消息可以任意延迟。

Paxos 和 Raft 都工作在部分同步模型中。它们保证安全性(Agreement + Validity)在任何情况下都成立——即使网络完全异步。但终止性(Liveness)只在 GST 之后才保证:如果网络长时间无法送达消息,Raft 的选举会反复超时,系统停滞,但不会做出错误的决定。

这就回答了开头的问题:Raft 没有违反 FLP,因为 FLP 说的是纯异步模型。Raft 的 election timeout 把系统从纯异步拉到了部分同步——它假设网络最终会恢复到消息能在有限时间内送达的状态。在纯异步的极端情况下(消息永远不送达),Raft 确实不保证终止。这不是 bug,是设计。

路线二:随机化。 1983 年,Michael Ben-Or 证明了:如果允许进程抛硬币(使用随机数生成器),共识可以在异步系统中以概率 1 终止。协议不再是确定性的——FLP 只排除了确定性协议。随机化共识的期望轮次数虽然可能很高,但终止概率随轮次趋近于 1。

路线三:故障检测器(Failure Detector)。 1996 年,Chandra 和 Toueg 提出了故障检测器抽象。故障检测器是一个”预言机”(Oracle),它告诉进程”谁可能崩溃了”。关键在于,故障检测器不需要完美——它可以误报(把活着的进程报告为崩溃),也可以漏报(没检测到真正崩溃的进程),只要最终能收敛到正确的判断就行。

Chandra-Toueg 的核心结果:一个叫 Diamond-P(最终完美故障检测器)的故障检测器,加上异步消息传递,就足以解决共识问题。Diamond-P 的要求是:最终(从某个时间点开始),它不再误报,也不再漏报。

工程上的超时机制——“如果 500ms 没收到心跳就认为对方挂了”——就是一个不完美的故障检测器。它可能误判(网络抖动时),但在网络稳定后最终会变准确。这和 Diamond-P 的假设吻合。

值得深入理解的是故障检测器如何从形式上绕过 FLP。FLP 证明了在纯异步模型中——没有任何故障检测能力——共识不可能达成。Chandra 和 Toueg(1996)的关键洞察在于:如果我们用一个外部的故障检测器预言机来增强异步模型,共识就变得可解。故障检测器不需要嵌入系统模型本身,它是一个独立的抽象层,为进程提供关于其他进程存活状态的(可能不准确的)信息。这种分离使得我们可以精确地刻画”解决共识到底需要多强的故障检测能力”。

Chandra、Hadzilacos 和 Toueg 建立了一个故障检测器的层级结构,按检测能力从强到弱排列:

graph TD
    P["P(完美故障检测器)<br/>完备 + 准确<br/>仅同步系统可实现"]
    DP["◇P(最终完美故障检测器)<br/>最终完备 + 最终准确<br/>可能暂时犯错"]
    DS["◇S(最终强故障检测器)<br/>最终完备 + 最终存在不被怀疑的正确进程"]
    OM["Omega(最终领导者预言机)<br/>最终所有正确进程同意同一个领导者<br/>解决共识的最弱充分条件"]

    P -->|"放松准确性<br/>允许暂时误报"| DP
    DP -->|"放松准确性<br/>只需一个不被怀疑"| DS
    DS -->|"进一步抽象<br/>只关心领导者选举"| OM

    style P fill:#e8f4f8,stroke:#2c3e50,stroke-width:2px
    style DP fill:#e8f4f8,stroke:#2c3e50,stroke-width:2px
    style DS fill:#e8f4f8,stroke:#2c3e50,stroke-width:2px
    style OM fill:#fdebd0,stroke:#e67e22,stroke-width:2px

这个层级从上到下逐步放松对故障检测准确性的要求。关键结论是:Omega 是能够解决共识问题的最弱故障检测器类别(Chandra、Hadzilacos、Toueg,1996)。这意味着共识问题在故障检测器的意义上与领导者选举”等价”——任何能解决共识的故障检测器都至少和 Omega 一样强。从工程角度看,Raft 的领导者选举机制本质上就是在实现 Omega:当网络稳定之后(即超过全局稳定时间 GST),所有 follower 通过超时和投票机制最终同意同一个 leader——这恰恰是 Omega 所提供的保证。

工程含义:不是”不可能”,而是”必须取舍”

FLP 对工程师的真正信息不是”共识不可能”,而是:

在异步系统中,确定性共识协议不可能同时保证安全性和活性。你必须在两者之间做出选择。

几乎所有实际的共识系统都选择了同一侧:永远保证安全性,在网络条件允许时提供活性。 这意味着:

etcd 的行为就是这样:少数派分区里的节点停止接受写入,等待重新加入多数派。数据安全,但该分区内的客户端在分区期间无法写入。这是 FLP 告诉我们的工程代价,不是 Raft 的实现缺陷。

FLP 定理的精确条件也暗示了另一个工程判断:如果你的系统部署在一个网络延迟有实际上界的环境中(比如同一个数据中心、同一个机架),那么”纯异步”的假设过于悲观。你面对的更接近部分同步模型,共识的终止性有更强的保障。反过来,如果你的系统需要跨越不可靠的广域网(海底光缆可能被切断),FLP 的警告就更值得认真对待。

二、CAP 定理

Brewer 猜想(2000)与 Gilbert-Lynch 证明(2002)

2000 年,Eric Brewer 在 PODC 会议的主题演讲中提出了一个猜想:分布式系统不可能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition Tolerance)三个性质——最多只能满足其中两个。

这就是广为流传的”三选二”。

两年后,Seth Gilbert 和 Nancy Lynch 在论文”Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services”中给出了形式化证明。但 Gilbert-Lynch 的证明和 Brewer 的演讲说的不是同一件事——证明中的每个术语都有精确的数学定义,而 Brewer 的猜想是用自然语言表述的,留下了大量解释空间。

工程师社区记住了 Brewer 的”三选二”口号,但很少回去读 Gilbert-Lynch 的精确定义。这是 CAP 被大规模误读的根源。

精确陈述

Gilbert-Lynch 证明中的三个性质定义如下:

一致性(Consistency):这里的 C 不是数据库 ACID 里的 C(事务一致性),也不是”最终一致性”的反义词。Gilbert-Lynch 的 C 是线性一致性(Linearizability)——也称为原子一致性(Atomic Consistency)。线性一致性要求:对一个读写寄存器的所有操作,存在一个全局的线性顺序,这个顺序和每个操作的实际时间区间相容,并且每次读操作返回最近一次写操作的值。

这是一个非常强的一致性模型。大多数被称为”一致”的系统并不提供线性一致性——它们可能提供顺序一致性(Sequential Consistency)、因果一致性(Causal Consistency)或会话保证(Session Guarantees)。CAP 的 C 不涵盖这些较弱的模型。

可用性(Availability):每一个发到非故障节点的请求,都必须收到一个(非错误的)响应。注意两个关键点:第一,“每一个”——不是 99.99%,是 100%。第二,没有时间限制——响应可以慢,但必须最终到来。

这比工程师通常理解的”高可用”严格得多。如果一个系统在分区期间让某些节点返回错误或超时,按 CAP 的定义,它就不”可用”——即使它的 SLA 还是 99.99%。

分区容错性(Partition Tolerance):网络可以丢失任意多的消息——也就是说,任意两个节点之间的通信可能被切断。

CAP 定理:在异步网络模型中,不存在一个读写存储系统能同时保证线性一致性和可用性(在可能发生网络分区的前提下)。

“三选二”的三重误读

“三选二”这个口号流行了二十年,但它至少在三个地方误导了工程师。

误读一:分区是一个可以”选择”的选项。

“三选二”暗示你可以选 CA(一致性 + 可用性,放弃分区容错)、CP(一致性 + 分区容错)或 AP(可用性 + 分区容错)。但网络分区不是你选择的——它是发生在你身上的事情。光缆被挖断、交换机故障、路由表错误——这些不是设计决策。

在分布式环境中(进程运行在不同的机器上),分区是必然会发生的。所谓”CA 系统”只在单机或严格不分区的网络中才有意义。一旦你把数据放到多台机器上,P 就不是可选项,而是前提条件。

真正的问题是:当分区发生时,你牺牲 C 还是 A?

误读二:CAP 的 C 代表”一致性”。

很多文章在讨论 CAP 时,把 C 等同于笼统的”一致性”。这导致了诸如”Cassandra 是 AP 系统所以不一致”的说法。实际上,Cassandra 在没有分区时可以提供因果一致性或 quorum 读的强一致性——这些只是不满足线性一致性这一个特定模型。

如果你的系统需要的是因果一致性而不是线性一致性,CAP 定理根本没有限制你。它画的那条线,比很多人以为的要窄得多。

误读三:CAP 的 A 是”系统大部分时间能用”。

CAP 中的可用性是一个极端定义:所有非故障节点的所有请求都必须收到响应。如果你的系统在分区期间让少数派分区的节点拒绝服务(像 Raft 那样),按 CAP 的定义它就不可用——尽管多数派分区内的客户端还能正常读写。

工程上的可用性(SLA、可用百分比、P99 延迟)和 CAP 的可用性是不同的概念。Spanner 的”高可用”是工程意义上的:Google 的专用网络让分区极其罕见,所以 Spanner 在实践中几乎总是可用。但按 CAP 的严格定义,Spanner 在分区发生时会牺牲可用性(某些请求会超时),它是 CP 系统。Spanner 没有违反 CAP,它只是让 P 几乎不发生。

CAP 不是三角形——分区是条件,不是选项

Brewer 本人在 2012 年发表了”CAP Twelve Years Later: How the ‘Rules’ Have Changed”一文,承认”三选二”的表述具有误导性。他指出,CAP 的实际含义更接近:在分区持续的时间窗口内,系统需要在一致性和可用性之间做出权衡;分区结束后,系统需要恢复到一致状态。这是一个动态的、有时间维度的权衡,不是一个静态的”三选二”。

关于 CAP 的更深入讨论,可以参考 CAP 的谎言与真相

PACELC:更实用的权衡框架

CAP 有一个明显的盲区:它只讨论分区发生时的取舍,但现实中大多数时间网络是正常的。正常运行时,系统的设计选择是什么?

Daniel Abadi 在 2012 年提出了 PACELC 框架来填补这个空白:

PACELC 比 CAP 更接近工程现实,因为它承认了两个事实:第一,分区是偶发事件,不是常态;第二,即使没有分区,一致性也是有代价的——代价就是延迟。提供线性一致性的系统(例如 Spanner)需要跨节点协调,这不可避免地增加延迟。提供最终一致性的系统(例如 Dynamo)可以本地响应,延迟更低。

用 PACELC 框架来分类常见系统:

系统 分区时(P) 正常时(E) 分类
Dynamo 选可用性(A) 选低延迟(L) PA/EL
Cassandra(默认) 选可用性(A) 选低延迟(L) PA/EL
Spanner 选一致性(C) 选一致性(C) PC/EC
HBase 选一致性(C) 选一致性(C) PC/EC
MongoDB(majority) 选一致性(C) 选低延迟(L) PC/EL

PACELC 不是定理,而是分类框架。它的价值在于:迫使设计者回答两个问题,而不是一个。仅回答”分区时怎么办”是不够的——正常运行时的延迟/一致性取舍,才是影响日常用户体验的主要因素。

三、共识数与等待自由层级

Herlihy 1991:同步原语的能力边界

1991 年,Maurice Herlihy 发表了论文”Wait-Free Synchronization”,提出了一个根本性的问题:不同的共享对象(Shared Object),在构建并发数据结构时的能力有没有本质差异?

答案是有,而且差异是不可逾越的。

等待自由(Wait-free) 是并发算法的一种进度保证:每个进程在有限步内完成操作,无论其他进程的执行速度如何——即使其他进程全部停滞。这是最强的进度保证,比无锁(Lock-free)更强。

共识数(Consensus Number) 的定义:一个共享对象的共识数是 n,如果用这种对象(加上原子读写寄存器)可以为 n 个进程实现等待自由的共识,但不能为 n+1 个进程实现。

Herlihy 证明了一个层级结构:

共识数 对象
1 原子读写寄存器(Atomic Register)
2 Test-and-Set、Swap、Fetch-and-Add、队列、栈
2n-2 n-寄存器赋值(n-Register Assignment,n >= 2)
无穷大 比较并交换 CAS(Compare-and-Swap)、LL/SC、Memory-to-Memory Swap

这个层级是严格的:共识数为 n 的对象不能为 n+1 个进程实现等待自由共识,无论你多聪明都不行。这不是工程限制,而是数学证明。

用具体例子来感受这个层级的含义:

读写寄存器(共识数 1):假设两个进程 A 和 B 试图仅用原子读写操作达成共识。A 写入 0,B 写入 1。无论谁最后读,都能看到对方的值,但问题在于——没有原子的方式来”判定胜负”。最后一个写入者覆盖了前一个的值,而”输家”无法分辨自己是否输了,因为读和写是两个独立的步骤,中间可能被其他操作插入。对于两个进程的共识问题,读写寄存器就已经无能为力。

队列(共识数 2):两个进程可以用一个 FIFO 队列解决共识。协议很简单:两个进程各自将自己的提议值入队(enqueue),然后各自出队(dequeue)。第一个被出队的值就是共识决定——因为 FIFO 保证了全局顺序,两个进程出队的第一个值必然相同。但这个方法无法扩展到三个进程:第三个进程无法仅通过队列操作确定前两个进程的操作的相对顺序,因为它看到的出队序列取决于它自己入队的时机。

比较并交换 CAS(共识数无穷大):CAS 可以为任意数量的进程解决共识。每个进程执行 CAS(shared_var, initial_value, my_proposal)。恰好有一个进程成功(第一个执行 CAS 的),其余所有进程的 CAS 失败并读到胜者的值。成功者知道自己赢了,失败者知道自己输了并且知道决定值是什么——这是一个通用的共识对象。

这个层级是严格的且经过数学证明的:没有任何算法上的巧妙设计能让共识数为 1 的对象解决两个进程的共识问题。这是计算的基本限制,不是工程能力的不足。

CAS 的无穷共识数意味着什么

比较并交换(Compare-and-Swap,CAS)的共识数是无穷大——它可以为任意数量的进程实现等待自由共识。这使得 CAS 成为一个通用(Universal) 的同步原语:任何共享对象都可以用 CAS 实现等待自由版本。

这就是为什么现代 CPU 架构(x86 的 CMPXCHG、ARM 的 LDXR/STXR 即 LL/SC)都提供 CAS 或等价的原子操作。不是因为 CAS 方便,而是因为没有它,很多并发数据结构在理论上就无法实现。

工程上的体现随处可见:

反过来看:如果你只有原子读写寄存器(共识数 1),连两个进程的共识都实现不了。这就是为什么纯粹基于读写操作的并发算法(比如 Peterson 算法)只能处理两个进程的互斥,而不能扩展到 n 个进程的共识。

Herlihy 的结果和 FLP 有一个有趣的对照:FLP 讲的是消息传递模型中的不可能性,Herlihy 讲的是共享内存模型中的不可能性。两者从不同角度刻画了分布式计算的能力边界。消息传递模型中,瓶颈是异步性和故障;共享内存模型中,瓶颈是同步原语的强弱。

四、收割与产出

从二元到连续

1999 年,Armando Fox 和 Eric Brewer(对,就是 CAP 的 Brewer)发表了”Harvest, Yield, and Scalable Tolerant Systems”。这篇论文比 CAP 猜想早一年,却提出了一个在工程上更实用的视角:可用性和一致性不是全有全无的,而是可以在一个连续光谱上调节的。

两个核心概念:

产出(Yield):请求被成功完成的概率。接近于工程上的可用性百分比,但更侧重于从用户请求的角度看——发出的请求有多大比例得到了完整响应?

收割(Harvest):响应的数据完整性。如果一个查询应该检索 100 个分片的数据,但有 2 个分片不可达,系统返回了 98 个分片的结果,那么 harvest = 98%。

CAP 把可用性看作二元的(可用或不可用)。Fox-Brewer 的框架把它拆成了两个连续维度:你的系统在多大概率上能响应(yield),以及响应的数据有多完整(harvest)。

现代系统在光谱上的位置

这个框架的实用性在于:大多数系统的故障应对策略不是”整体不可用”或”返回错误数据”,而是在 harvest 和 yield 之间做局部交换。

搜索引擎是典型例子。Google 搜索的某个索引分片挂了,搜索服务不会返回错误——它返回剩余分片的结果。用户拿到的结果可能不完整(harvest 降低),但请求被成功响应了(yield 维持)。大多数用户甚至不会注意到少了几条结果。

购物车是另一个例子。Amazon 的 Dynamo 论文描述了这种场景:网络分区时,购物车服务允许在两个分区中分别接受写入(高 yield),分区恢复后合并冲突。合并过程可能导致已删除的商品重新出现(harvest 临时降低),但 Amazon 认为”多加一件商品”比”购物车不可用”的代价小得多。

对比 CAP 和 harvest/yield 的视角:

维度 CAP Harvest/Yield
可用性 二元:可用或不可用 连续:yield 是一个百分比
一致性 二元:线性一致或不 连续:harvest 是数据完整度
决策粒度 整个系统 可以按功能、按请求类型、按数据分区分别决策
工程指导性 “选 CP 还是 AP” “这个功能需要多高的 harvest,可以接受多少 yield 损失”

从工程设计的角度,harvest/yield 框架比 CAP 更有操作性。它促使设计者问正确的问题:不是”我的系统是 CP 还是 AP”,而是”对于这个具体的功能,在故障场景下,我愿意牺牲多少数据完整性来换取多少可用性?”

五、四个结果的工程综合

回到开头的两个矛盾。

Raft 跑在”异步网络”上但共识达成得好好的——因为 Raft 不在纯异步模型中工作。它通过 election timeout 引入了时间假设,把系统模型从纯异步推到了部分同步。在这个模型中,FLP 不适用。代价是:如果网络真的长时间不可用(纯异步的极端情况),Raft 停止服务。安全性不丢,活性暂停。

Spanner 声称兼得一致性和可用性——因为 Spanner 的”可用”是工程意义上的(SLA 99.999%),不是 CAP 定义的”所有非故障节点 100% 响应”。Spanner 在分区发生时确实会牺牲可用性。Google 的做法是让分区几乎不发生(专用网络、冗余链路),而不是绕过 CAP。

四个不可能性结果画出了分布式系统的理论边界。对工程师来说,它们的价值不在于告诉你”什么做不到”,而在于告诉你”做到这个目标的代价是什么”:

理论边界是固定的——数学证明不会因为工程需求而改变。但边界内的设计空间是巨大的。理解这些定理的精确条件,就是理解这个设计空间的边界在哪里。不多,不少。

参考资料

论文

演讲


上一篇:分布式系统模型 | 下一篇:故障的分类学

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-13 · distributed

【分布式系统百科】分布式系统模型:你的假设决定你的命运

分布式系统的正确性证明和协议设计都建立在系统模型之上。同步还是异步?崩溃还是拜占庭?这些看似学术的分类,直接决定了你能用什么协议、不能用什么协议。本文拆解通信模型、故障模型和进程模型三个维度,把 Paxos、Raft、PBFT、Bitcoin 放回它们各自的模型空间。

2026-04-13 · distributed

【分布式系统百科】Raft 深度重写:从论文的 18 页到 etcd 的 15000 行

Raft 论文 18 页就能读完,但 etcd/raft 用了 15000 行 Go 才把它变成能在生产环境跑的代码。这篇文章从论文的每一个核心机制出发,逐一拆解工程实现中论文没说的东西:PreVote、ReadIndex、LeaderTransfer、ConfChange V2、流水线复制、Async Apply,以及 TiKV 的 Multi-Raft 实践。最后做一次精确的 Paxos 对比,并坦诚讨论 Raft 的已知缺陷。


By .