跳转到内容

故障模型与 CAP

CAP 定理是被误读最多的分布式定理。本章先讲故障模型的谱系(崩溃、遗漏、拜占庭),再讲 FLP 不可能性,最后把 CAP 的准确表述与常见误读一次讲清,补上 PACELC。

系统对故障的假设决定算法的设计空间(越强的模型越"诚实"越好处理,越弱的越难):

模型故障形态难度应对
崩溃故障(crash)节点停机,不撒谎低超时 + 共识(Raft)
遗漏故障(omission)丢消息、慢响应中重试 + 超时
拜占庭故障(Byzantine)任意行为(撒谎、伪造)高需要 3f+13f+1 节点(PBFT)
  • 数据中心内:假设崩溃故障就够——机器不会撒谎,只停机;Raft、ZooKeeper 都在此假设下设计(→ 共识:Paxos 与 Raft);
  • 跨组织/区块链:必须假设拜占庭——节点可能任意作恶;PBFT 类需要 3f+13f+1 节点容忍 ff 个拜占庭(vs 崩溃模型的 2f+12f+1)。

遗漏与拜占庭之间的现实:网络丢包、消息乱序、时钟漂移——生产系统的故障谱在崩溃与拜占庭之间,算法要对这两类都健壮(重试、超时、校验)。

FLP 定理(Fischer, Lynch, Paterson, 1985):在异步系统中(消息延迟无上界),不存在确定性的共识算法能同时保证终止性——一个节点崩溃就可能让共识永不终止。

这是理论上的不可能性,实践的解法都是破坏它的前提:

  • 部分同步:假设延迟有上界(只是未知)——用超时检测"疑似失败",Paxos/Raft 都靠超时;
  • 随机化:非确定性的共识(Ben-Or)以概率终止。

FLP:异步系统中确定性共识不可能,实践靠超时——这句话的含义是:共识算法的"活性"(终止性)依赖对故障检测的假设,而故障检测的依据(超时)本身可能误判(进程只是慢,不是死了)——误判会导致领导者频繁更换(抖动)。

CAP 定理(Gilbert & Lynch 2002 形式化):网络分区(partition)发生时,系统不能同时保证:

  • C(一致性):线性一致性——每个读看到最近写入;
  • A(可用性):每个请求都得到(非错误)响应;
  • P(分区容忍):网络分区时系统仍工作。

分区发生时,C 与 A 二选一:

  • 选 C(CP):分区期间拒绝请求(等多数派)——ZooKeeper/etcd 的写、HBase;
  • 选 A(AP):分区期间继续服务,副本可能分叉——Cassandra、Dynamo 风格。

"CAP 三选二"是误读——准确的表述是:

  • P 不是选项:分区是必然的(网络一定会断),不能"放弃 P"——能选的只是分区期间C 与 A 之一;
  • 没有分区时(系统正常时),C 与 A 都能要——选择只在分区期间;
  • C 的含义是线性一致,不是"数据最终一致"(最终一致的 AP 系统也"一致"——只是弱得多);
  • A 的含义是"每个请求得到响应",不是"快速响应"。

PACELC 补充了无分区的一半:Else(无分区时)在 Latency 与 Consistency 之间权衡——同步复制(低延迟换一致性弱)与同步强一致复制(一致性换延迟)的选择永远存在:

  • PA/EL:分区选可用、无分区选低延迟(Cassandra);
  • PC/EC:分区选一致、无分区选一致(Spanner、ZooKeeper)。

PACELC 把"延迟 vs 一致性"变成第一等问题——多数生产系统的取舍发生在无分区时(复制策略的选择),不是分区时。

  • 分区会发生(跨机房、交换机故障、GC 停顿造成的"疑似分区")——设计时假设分区常态化(Jepsen 测试的教训);
  • 分区期间选 C 还是 A 是业务问题:余额(CP)vs 点赞数(AP);
  • 无分区时,延迟 vs 一致性的取舍在复制策略(同步/异步、多数派/一副本)里。
  • 故障模型决定算法:数据中心假设崩溃故障(2f+12f+1),拜占庭需要 3f+13f+1
  • FLP:异步系统中确定性共识不可能,实践靠超时(部分同步假设)
  • CAP 的准确表述:分区期间在 C(线性一致)与 A(每个请求有响应)之间选
  • 分区是必然的,选择只在分区期间;"三选二"是误读
  • PACELC:无分区时在延迟与一致性之间权衡——多数取舍发生在这里