跳转到内容

PBFT — 让拜占庭容错从理论变成能跑的工程

是什么

PBFT(Practical Byzantine Fault Tolerance)是第一个让”拜占庭容错”在真实系统里跑得动的协议。日常类比:4 个人开会决一件事,最多允许其中 1 个人撒谎或装死,剩下 3 个人靠”多轮互相确认”仍能达成一致结论。

更具体一点:

  • 你有 N 台服务器,其中最多 f 台可能任意作恶(不仅崩溃,还可能伪造消息、串通)
  • 只要 N ≥ 3f+1,PBFT 保证所有”诚实节点”对每条命令的执行顺序达成一致
  • 1999 年第一次把这个理论吞吐做到 1000+ ops/sec,证明”BFT 不是只能写论文”

PBFT 是后面所有区块链共识协议(Tendermint / HotStuff / Diem BFT)的直系祖先。

为什么重要

不理解 PBFT,下面这些事都没法解释:

  • 为什么联盟链 / 跨机房复制状态机要 4 个节点起步——3f+1 公式里 f=1
  • 为什么 HotStuff / Tendermint 总在讲 “三阶段提交”——它们都在改良 PBFT 的 pre-prepare/prepare/commit
  • 为什么”拜占庭”和”崩溃容错”差别这么大——Paxos/Raft 只防”死机”,PBFT 防”主动撒谎”
  • 为什么 1999 年的论文今天还在被引用——它定义了”工程级 BFT”的术语和门槛

一句话:PBFT 把 Lamport 1982 年的数学定理(拜占庭将军问题)变成了可以编进生产系统的代码

核心要点

PBFT 的精髓可以拆成三步协议 + 一个备胎

  1. Pre-prepare(主节点发提案):客户端把请求发给主节点(primary),主节点给请求分配一个序号 n,广播 <pre-prepare, view, n, request> 给所有副本。类比:群里有个组织者把今天的议题贴出来,编号 #42。

  2. Prepare(副本互相确认):每个副本收到 pre-prepare 后,向其他所有副本广播 <prepare, view, n, digest>。当一个副本收到 2f 个匹配的 prepare(加自己一共 2f+1 个),就进入 “prepared” 状态。类比:群里 3 个人都说”我看到议题 #42 是 X”,你就敢确认大家说的是同一件事。

  3. Commit(确认大家都承诺了):进入 prepared 后再广播 <commit, view, n, digest>。收到 2f+1 个 commit 后,副本执行请求并把结果返回客户端。类比:不光大家看到一样的议题,还都答应”我会执行它”。

View change(备胎):如果主节点超时不发 pre-prepare 或乱发,副本投票”换主”,新主从最高 prepared 状态接着干。这一步是工程实现的复杂度集中区——新主必须证明它接管的状态是合法的,不能凭空伪造。

为什么需要 3f+1 而不是 2f+1:崩溃容错只要”过半数活着”(f+1 of 2f+1),但拜占庭节点会”装两边”,所以诚实节点要靠 2f+1 多数包围 f 个坏节点——总数最少 3f+1。

实践案例

案例 1:f=1 时的最小集群

4 个节点:R0(主)、R1、R2、R3
最多容忍 1 个拜占庭节点
每条请求要走 3 阶段,每阶段 quorum = 2f+1 = 3

如果 R3 是坏节点(伪造消息),R0/R1/R2 仍能在 prepare 阶段凑出 3 个匹配确认,正常推进。

案例 2:消息流(理想路径)

Client R0(primary) R1 R2 R3
| request -->| | | |
| pre-prepare ->|----->|----->|
| |<- prepare -->|<--->|<--->|
| |<- commit -->|<--->|<--->|
|<------ reply -----------+------+------+

客户端等到 f+1 = 2 个匹配的 reply 才接受结果——因为坏节点最多 f 个,f+1 个一致回复必有诚实节点。

案例 3:用 MAC 替代数字签名(论文最大工程贡献之一)

朴素 BFT 思路是每条消息用公钥签名(防伪造),但 1999 年公钥签名一秒只能做几十次。Castro & Liskov 改用对称密钥 MAC(每对副本一个共享密钥),快 3 个数量级。代价:MAC 不能跨副本转交证据,view change 协议要重新设计。

这是论文标题里 “Practical” 的核心来源——把签名换成 MAC,吞吐从几 ops/sec 提到 1000+ ops/sec

案例 4:checkpoint 让协议不会内存爆炸

每条请求都要保留 prepare/commit 的证据用于 view change,跑久了内存会爆。PBFT 每隔 K 条请求(论文里 K=128)做一次 checkpoint:副本计算当前状态摘要并广播 <checkpoint, n, digest>,收到 2f+1 个匹配后认为这是”稳定 checkpoint”,可以安全丢弃 n 之前的所有日志。

这一步看似小事,但少了它工业部署是不可能的——这又是 “Practical” 的体现。

踩过的坑

  1. 节点数门槛硬:要容忍 1 个坏节点,最少要 4 台机器;容忍 2 个就要 7 台。私有部署还行,公有链要几百节点时通信复杂度就爆了。

  2. O(n²) 通信:prepare 和 commit 阶段每个副本都要广播给所有其他副本,节点数 n 大了带宽是平方级增长。HotStuff(2019)改成线性聚合签名才解决。

  3. MAC 不可转交:因为 MAC 用对称密钥,副本 A 收到的 prepare 没法证明给副本 B 看(B 不信 A 的密钥)。view change 时这导致协议复杂度高。后续协议改回聚合签名(BLS)补救。

  4. view change 是 bug 王国:实现里大量 corner case——新主选哪个状态接续?老主复活后怎么办?2017 年 Tendermint 团队公开承认 view change 部分被重写过 3 次。

  5. 客户端也要懂协议:客户端不能只信任一个副本的回复,必须等 f+1 个匹配 reply。这让”接入 PBFT”不像接 SQL 那样透明。

  6. timestamp / 重试要小心:客户端重试请求要带同一个 timestamp,否则副本会当成新请求执行两次。这是早期实现里被忽视的安全洞——一个粗心的重试逻辑能让转账被执行两次。

  7. 不能容忍”局部网络分区”:PBFT 假设 f 个故障节点是任意的,但如果是网络分区导致诚实节点暂时分成两半,每半都不到 2f+1,整个系统会停在 prepare 阶段。可用性在这种场景上不如 Raft 灵敏。

适用 vs 不适用场景

适用

  • 联盟链 / 跨机构共识(节点数 < 100,身份已知)—— Hyperledger Fabric / Tendermint
  • 高安全要求的复制状态机(金融、军事系统)
  • 需要”瞬时最终性”的场景——commit 后立刻确定,不像 PoW 要等 6 个块

不适用

  • 公有链动辄上千上万节点 —— O(n²) 通信吃不消,要用 PoW / PoS / DAG
  • 简单崩溃容错就够 —— Paxos / Raft 足够,门槛 2f+1 而不是 3f+1
  • 需要匿名 / 开放参与 —— PBFT 假设节点身份固定且互相已知
  • 极低延迟要求(< 10ms)—— 三阶段 + 多轮广播会到 50-200ms

历史小故事(可跳过)

  • 1982 年:Lamport / Shostak / Pease 发表拜占庭将军问题论文,证明 3f+1 下界。但只有数学,没人能跑。
  • 1990s 初:Rampart / SecureRing 等学术原型出现,每秒只能做几个操作,工业界看了直摇头。
  • 1999 年:Castro 在 MIT 跟 Liskov 做博士,用 MAC 替代签名 + 优化通信路径,把吞吐拉到接近非 BFT 系统的 60%。OSDI 接收,标题特意强调 “Practical”。
  • 2014 年起:区块链热潮把 PBFT 又翻出来——Tendermint 2014、HotStuff 2019、Diem 2020 全是它的徒孙。

学到什么

  1. 理论下界 vs 工程上界:3f+1 是数学下界(绕不开),但工程做不做得动取决于”每条消息要花多少 CPU”——把签名换成 MAC 是关键
  2. 三阶段协议的本质:pre-prepare 定顺序,prepare 让多数派看见同一件事,commit 让多数派承诺执行——三步缺一不可
  3. “Practical” 是个标题级判断:协议复杂度 / 通信开销 / 实现难度三方妥协,没有”完美 BFT”,只有”够用 BFT”
  4. 拜占庭 ≠ 崩溃:写分布式代码前先想清楚故障模型——多 1 个 f 就要多 1 个 f,节点数翻倍
  5. 学术原型 → 工业系统的距离:1982 到 1999 隔了 17 年才有 “Practical” 实现,而且关键突破不是新数学,是工程取舍(MAC、checkpoint、批处理)——值得每个学算法的人记住

延伸阅读

关联

  • lamport-byzantine-generals —— 1982 年提出 3f+1 下界,PBFT 给出能跑的协议
  • paxos —— 同时代的崩溃容错共识,门槛更低但不防作恶
  • raft —— Paxos 的可读重述版,工业界主力
  • hotstuff —— PBFT 的线性通信改良,区块链时代主流
  • tendermint —— PBFT 在公链场景的工程化版本
  • fischer-lynch-paterson —— FLP 不可能性定理告诉你”完全异步下没有任何确定性共识”,PBFT 假设部分同步绕过它

反向链接

  • hotstuff-2019 —— HotStuff — 让换领导也只花线性消息的 BFT 共识
  • narwhal-tusk-2022 —— Narwhal & Tusk — 把 BFT 共识拆成『谁说过』和『谁先说』两件事
  • paxos —— Paxos — 分布式共识算法
  • raft —— Raft — 易理解的共识算法