Chapter 08

CAP、PACELC 与综合权衡

前面七章分别拆解了分区故障根因(01)、时序与因果(02)、一致性谱系(03)、复制机制(04)、分区路由(05)、共识算法(06)、分布式事务(07)。这一章把这些机制收束成两个决策框架——CAP 与 PACELC——再把真实系统一一对号入座,并梳理截至 2026-06 的前沿进展:哪些是定论,哪些还在演变,哪些旧做法已被取代。

本章你将建立的 schema

  • CAP 的精确表述与三大误解("三选二"误导、"CA 系统"不存在、C ≠ ACID-C)
  • PACELC 把"正常态"下延迟/一致的取舍也纳入框架,补上 CAP 的盲区
  • etcd / Cassandra / Spanner 各自如何映射到 CP / AP / PC/EC,以及背后用到了哪几章的机制
  • 截至 2026-06:哪些定论二十年不变、哪些近两年在动、哪些旧做法已被取代

8.1CAP 定理:精确表述与三大误解

当网络发生分区时,系统无法同时保证线性一致(C)与完全可用(A)——分区是环境事实,不是可选项。

为什么需要理解它

工程师在选型时常把"我需要 CA"写进 ADR,然后被面试官或同事追问"CA 系统是什么意思"时语塞。CAP 被误读的程度与它被引用的频率几乎等比——不精确地理解它,反而比不知道它更危险,因为它会产生错误的设计信心。

精确表述

Eric Brewer 2000 年在 PODC 提出猜想;2002 年 Seth Gilbert 与 Nancy Lynch 给出形式证明。定理的准确表述是:在一个异步网络模型中,若节点间可能发生消息丢失(分区),则不存在任何算法能同时保证线性一致性(Linearizability)与全可用(Every non-failing node returns a response)。

这里的 C 是 线性一致性(linearizability):任何读操作返回的值,必须是最近一次完成写操作之后的最新值,且所有操作的效果看起来仿佛在某个全局时间点瞬间发生(与第 03 章一致性谱系的最高档对应)。这不是 ACID 里的 C(Consistency),ACID-C 指数据满足应用约束,是应用语义层面的概念。

三大误解

陷阱 1 · "三选二"误导

"从 C、A、P 里选两个"的表述把分区(P)当作可以主动放弃的属性。实际上分区是网络环境的客观事实——节点无法区分对端节点是宕机还是网络包丢失(01 章根因)。真正的取舍是:当分区发生时,系统选择保线性一致还是保可用。

陷阱 2 · "CA 系统"不是分布式主张

单机 RDBMS(如单节点 PostgreSQL)在 CAP 意义上确实是 CA——它不需要处理网络分区。但一旦部署为分布式,节点间的网络就引入了分区可能性,"CA"的前提瓦解。所以"分布式 CA 系统"在 CAP 框架下没有意义——它只是一个回避了分布式属性的单节点系统。

陷阱 3 · CAP-C ≠ ACID-C

CAP 的 C 是线性一致(最强一致);ACID 的 C 是"事务执行后数据满足约束"(外键、唯一键等应用层不变量)。把两者混用会导致"我用了支持 ACID 事务的 MySQL 集群,所以我有 CAP 的 C"——这个推断是错误的,集群 MySQL 在分区时仍然要在可用性与线性一致之间取舍。

Brewer 本人在 2012 年的 CAP Twelve Years Later(IEEE Computer)中指出,取舍是细粒度的:系统可以按操作类型、甚至按子系统独立做 C vs A 决策,而不必全库统一。Cassandra 的可调一致性正是这个思路的工程实现。

收到写 / 读请求 检测到 网络分区? 否 正常服务 C + A 均满足 是 选择优先级 C vs A 保 C 拒绝请求 返回错误 保 A 返回响应 可能是旧值
图 8.1分区期间的 C vs A 决策分支。注意:无分区时 C 与 A 可同时满足;分区是触发取舍的条件,不是系统属性。
想一想

一个系统在分区时选择返回可能过时的数据(保 A),分区恢复后才做冲突解决——这是在 CAP 框架下选了什么?对比 ZooKeeper 在丢失多数派时拒绝所有写请求,又是选了什么?

展开答案(先停 10 秒)

前者选 A(可用):分区期间继续服务,牺牲线性一致,依赖后续反熵/冲突合并修复(Cassandra/Dynamo 的做法)。后者选 C(线性一致):拒绝写以维护"leader 拥有最新状态"的不变量(ZooKeeper、etcd 的做法)。设计洞察:选 A 的系统必须有冲突解决机制(LWW、CRDT、Saga补偿等),这些成本在分区结束后才支付。

8.2PACELC:别忘了"平时"

分区时取 A vs C;无分区正常态下取 Latency vs Consistency——PACELC 把这两段都写进框架。

为什么需要它

CAP 只描述分区期间的取舍,但分区是低概率事件。系统 99.9% 的时间运行在正常态,这段时间里同步等待多副本确认(高一致)还是异步返回(低延迟)才是日常性能的决定因素。只看 CAP 会让工程师忽视正常态的代价。

框架定义

Daniel Abadi 在 2012 年提出 PACELC(发音 "pass-elk"):

  • if Partition → A vs C(与 CAP 相同)
  • else(无分区)→ Latency vs Consistency

"else"分支的机制是:要在多副本上写入并等待确认,则延迟上升但一致性更强;异步复制则延迟低但副本之间会有短暂不同步(第 04 章复制机制的直接体现)。换言之,正常态下延迟与一致是同一枚硬币的两面:强一致的代价是至少等待网络往返时间 × 复制因子。

PACELC 系统分类
系统 分区时 正常态 PACELC 标记 本教程对应机制
Dynamo / Cassandra 选 A(继续响应) 选 L(异步复制,低延迟) PA/EL 04 无主 + 05 一致性哈希 + LWW
Riak(默认) 选 A 选 L PA/EL 04 quorum + sloppy quorum
Spanner / CockroachDB 选 C(拒绝无多数派分区) 选 C(同步复制 + commit-wait) PC/EC 06 Paxos/Raft + 07 2PC + 02 HLC/TrueTime
HBase / ZooKeeper 选 C 选 C PC/EC 06 Raft(etcd 作为协调服务)
Cosmos DB 可调 可调(五档一致性) PA/EL 到 PC/EC 03 一致性谱系全覆盖
MySQL(主从,半同步) 选 C(主宕时停写) 选 L(异步 / 半同步可选) PC/EL 04 单主复制
类比 · 带边界

PACELC 像在 CAP 的"分区应急预案"之上加了一份"日常 SLA 合同":应急预案决定灾时怎么做,日常合同决定平时付多少延迟换多少一致。边界在于:PACELC 仍是定性框架,它不量化"多少毫秒换多少一致"——这个量化需要具体的延迟测量与 SLO 设计。

想一想

Cassandra 设置 CONSISTENCY QUORUM(R + W > N)时,它的 PACELC 标记从 PA/EL 变成了什么?为什么延迟上升了?

展开答案(先停 10 秒)

QUORUM 要求写入多数节点后才返回,正常态下从 EL 切到 EC(选一致而非低延迟)。延迟上升因为写请求需要等待 ⌈N/2⌉+1 个副本确认,多了至少一次网络往返。分区时因为 Cassandra 基于 gossip 而非强共识,仍然可以在多数派可达时工作,但若分区导致多数派不可达则写失败——此时它实际上也在保 C(在该分区内)。注意这与 etcd 的 CP 不同:etcd 用 Raft 的 leader 选举,失去多数派立即停写;Cassandra QUORUM 的"多数派"是客户端动态计算的,没有全局 leader。

8.3真实系统映射

CP 系统(etcd、HBase、Spanner)与 AP 系统(Cassandra、Dynamo)的底层机制恰好对应前六章的具体内容。

为什么需要映射

CAP/PACELC 标签本身不能告诉工程师"为什么"——etcd 为什么是 CP?答案在 Raft 的多数派提交规则(06 章)。Cassandra 为什么能可调?答案在无主 quorum(04)+ 一致性哈希(05)+ LWW(02/04)。把标签与机制绑定,才能做有依据的系统选型。

CP 系阵营

etcd / ZooKeeper:使用 Raft(etcd)或 ZAB(ZooKeeper)共识算法(06 章)。leader 持有最新日志;follower 收到 AppendEntries 后才更新状态机。失去多数派时 leader 选举无法完成,系统停止接受写请求——这是在保线性一致(CP)。etcd 是 Kubernetes 的控制面存储,强一致对集群状态管理不可妥协。

HBase:写操作走 WAL + MemStore,RegionServer 宕机时 ZooKeeper 检测(01 章故障检测)并触发 Region 迁移;分区期间 ZooKeeper 自身 CP 保证了 Region 元数据的一致性,因此 HBase 整体也是 CP。

Spanner:每个 Paxos 分组覆盖一个数据分片(06 章 Paxos);跨分片事务用 2PC 协调(07 章);全局外部一致时间戳靠 TrueTime(02 章 HLC 对应)。三层机制叠加,使 Spanner 在全球范围内维持 PC/EC——分区时拒绝写,正常态付 commit-wait 延迟换全局线性一致。

AP 系阵营

Cassandra / Dynamo:无主架构,数据用一致性哈希分布到环上的虚拟节点(05 章),副本写入用 quorum 控制,但 quorum 是软约束——分区时降级到 sloppy quorum(04 章)继续写入 hinted handoff 节点,分区恢复后反熵(04 章)同步差异,冲突用 LWW 或向量时钟(02 章)解决。整个流程保了 A,牺牲了短暂的线性一致。

Riak:与 Dynamo 同源设计,支持 CRDT(03 章最终一致)作为内置数据类型,避免 LWW 的"后写者赢但早写者丢"问题。

可调系统

Cassandra(QUORUM / LOCAL_QUORUM / ONE):一致性级别是客户端每次请求时指定的——同一个集群,不同操作可以选不同的 C vs A 权重。这正是 Brewer 2012 年说的"细粒度取舍"。

Azure Cosmos DB:提供五档一致性(强一致 → 有界过期 → 会话 → 一致前缀 → 最终),覆盖 03 章一致性谱系的全部档位,且可按容器设置。

CP AP 可调 / 折中 etcd / ZooKeeper Raft/ZAB (§06) Spanner Paxos+2PC+TrueTime HBase ZK协调+WAL (§04) CockroachDB Raft+HLC (§06,§02) Cassandra quorum可调(§04,§05) Cosmos DB 五档一致性 (§03) Dynamo / Riak sloppy quorum+反熵 Aurora DSQL HLC近似TrueTime(§02)
图 8.3真实系统在 CP↔AP 谱上的位置及核心机制标注(§ 指本教程对应章节)。注意:Cassandra 与 Cosmos DB 位于中间——它们不是"两边都要",而是"可以按请求选边站"。

8.4现状速览与前沿(截至 2026-06)

分布式系统理论核心二十年稳定;近两年的变化在实现层:更好的时钟、CRDT 主流化、旧算法复兴、租约 bug 批量暴露。

为什么这一节值得深读

DDIA(2017)是工程师最常引用的参考,但它对 Spanner、CRDT、HLC 的描述已与 2025 年的现实有显著差距。搞清楚"哪些定论、哪些在动、哪些被取代",可以避免把已淘汰的设计模式写进新系统。

STABLE — 定论(二十年不变)

理论核心稳定:Paxos(1998/2001 发表)、CAP(2000/2002 证明)、Raft(2014)三篇论文构成分布式系统理论脊梁,不会被推翻,只会被精化。

Spanner + TrueTime(2012,已 GA 超十年):Spanner 论文(OSDI 2012)把全球外部一致(External Consistency)事务做成了工程现实——这与 2017 年 DDIA 写作时"Spanner 只有 Google 能做"的语气不同,今天它已作为 Cloud Spanner 公开商用。TrueTime 的核心思路是:把时钟不确定性**显式暴露**为区间 [earliest, latest],而不是假装时钟精确。commit-wait 机制等待 2ε(ε 是当前不确定区间的上界,Google 数据中心实测约 7ms),确保提交时间戳在全球所有节点看来都是单调递增的。2025 年,Spanner/TrueTime 获 ACM SIGMOD Systems Award,是该领域最高系统荣誉之一。

HLC(Hybrid Logical Clocks):CockroachDB 与 YugabyteDB 使用 HLC(02 章已介绍)实现近似 TrueTime 的语义,免去原子钟硬件。HLC 在物理时钟不回退时提供单调递增的因果时间戳,是普通数据中心的实用替代。

FoundationDB(2018 开源):FoundationDB 的招牌是确定性模拟测试(DST, Deterministic Simulation Testing)——整个分布式系统在单进程内运行,网络、磁盘均为可控的模拟实现,注入故障后系统行为完全可重放。这使测试覆盖了生产环境中极难复现的竞态条件,是分布式系统测试工程的里程碑。

Redis Enterprise CRDT(Active-Active Geo-Replication):Redis Enterprise 的多主地理复制基于 CRDT,允许多个区域同时写入同一 key,通过内置 CRDT 语义(计数器、集合、排序集等)自动合并,不产生冲突异常。这是 CRDT 从学术走向主流企业产品的代表。

IN FLUX — 近 1–2 年活跃演变(每条带日期)

① TigerBeetle 与 VSR 复兴(2025-06):TigerBeetle 是一款专为金融账务设计的高性能数据库,使用 1988 年的 Viewstamped Replication(VSR,Liskov & Oki)而非 Raft 作为共识层。VSR 的主要差异:选主不依赖随机超时,而是基于 view change 协议的确定性选主,减少了 split-brain 窗口。2025-06,Jepsen 对 TigerBeetle 0.16.11 完成测试并验证其达到严格可串行化(Strict Serializability)。这标志着 VSR——一个在 Raft 流行后几乎被遗忘的协议——在性能优先场景下的复兴。与 DDIA 2017 心智模型的差异:DDIA 几乎未提 VSR;2025 年它已通过了工业级 Jepsen 验证。

② Amazon Aurora DSQL(2024-12 GA):Aurora DSQL 是 AWS 2024 年 12 月正式发布的无服务器分布式 SQL 数据库,目标是在不使用 Google 原子钟硬件的前提下接近 Spanner 级别的全球一致性。实现路径:使用 EC2 精密硬件时钟(精度约百微秒)结合 HLC 构造有界时钟不确定区间,commit-wait 窗口相应更短。与 DDIA 2017 心智模型的差异:2017 年认为 Spanner 级全球一致需要原子钟,Aurora DSQL 证明高精度硬件时钟 + HLC 已可工程化替代。

③ CRDT 主流化:Automerge 3.0 + Yjs(2025-05):Automerge 3.0(2025-05 发布)将底层切换到 Rust 实现并编译到 WASM,内存占用相比 2.x 降低约 10 倍,使其在浏览器端实际可用。Yjs 已成为实时协作编辑的事实标准(VS Code Live Share、Hocuspocus 等均基于它)。local-first 运动(Ink & Switch 等研究团队主导)推动 CRDT 从"数据库内部机制"扩展到"应用层数据同步协议"。与 DDIA 2017 心智模型的差异:2017 年 CRDT 是"最终一致存储的高级选项",2025 年它是前端实时协作的标准库。

④ Raft 租约 bug 批量暴露:LeaseGuard(arXiv 2025-12):论文 LeaseGuard: Lease-based Distributed Systems are Broken(arXiv 2025-12)系统记录了 etcd、HashiCorp Raft、TiDB 等主流实现中普遍存在的租约(lease)相关 bug——核心问题是:Raft 的 leader lease 依赖物理时钟的单调性,而 NTP 调整或虚拟机时钟漂移会破坏这一假设,导致旧 leader 在 lease 未过期时继续提供陈旧读。这是 02 章"物理时钟不可靠"在真实系统中的集中体现。与 DDIA 2017 心智模型的差异:2017 年租约被视为有效的线性一致读优化;2025 年的测量表明大多数实现都有潜在的正确性漏洞。

SUPERSEDED — 旧做法已被取代

纯 NTP 物理时钟给事务定序:早期分布式数据库(如早期 MySQL 集群)用 NTP 时间戳作为全局事务顺序的依据。NTP 精度约 1–100ms,在跨节点并发写入时会产生静默的顺序颠倒——写时间戳更大的事务实际先到,被错误地排在后面。今天的做法是 HLC(免原子钟)、TrueTime(有界不确定 + commit-wait)或向量时钟(纯逻辑)。

Naive 3PC 作为 2PC 的容错升级:3PC 在异步网络下仍然无法解决网络分区导致的阻塞(FLP 定理,01 章),且实现复杂度远高于 Raft-based 2PC。实践中,跨分片事务的协调者故障恢复已被基于 Raft 的协调组(如 TiDB 的 TiKV + PD)或 Saga 补偿(07 章)取代。

单区域 ACID 假设下的"全球规模"设计:2017 年前,"全球一致 SQL"意味着业务层手动分区、读写分离、跨区域复制延迟容忍。今天,Spanner、CockroachDB、YugabyteDB、Aurora DSQL 均已 GA,把全球分布式 ACID 事务做成了运维友好的商业服务。架构师无需再为"强一致 vs 跨区域延迟"二选一。

定论 vs 在动 vs 已过时

理论框架(CAP/PACELC/Raft/Paxos)是定论,学完可以放心使用二十年。具体实现(租约实现、时钟精度、CRDT 库版本)是在动的——LeaseGuard 提醒工程师即使使用 etcd 这样成熟的系统,也要理解其租约的时钟依赖假设。旧做法(NTP 定序、naive 3PC)是已过时的——如果面试或设计文档里还在用这些,是知识断层的信号。

STABLE(定论) IN FLUX(近 1–2 年) SUPERSEDED(过时) Paxos 1998 CAP 2000 · Raft 2014 Spanner TrueTime 2012 SIGMOD Award 2025 HLC (CockroachDB) FoundationDB DST Redis CRDT Active-Active TigerBeetle + VSR Jepsen 2025-06 ✓ Aurora DSQL GA 2024-12 Automerge 3.0 Rust 2025-05 内存降 10× LeaseGuard etcd bug arXiv 2025-12 纯 NTP 事务定序 → HLC / TrueTime Naive 3PC → Raft 协调 + Saga 单区域 ACID 假设 → Spanner/DSQL GA
图 8.4截至 2026-06 的技术三桶分类。注意:IN FLUX 列的变化集中在实现层(时钟、租约、CRDT 库),而非理论层——理论全在 STABLE 列。
想一想

LeaseGuard(2025-12)记录了 etcd 的租约 bug,根因是什么章节的知识?修复方向是替换 NTP,还是改变 lease 的时钟依赖方式?

展开答案(先停 10 秒)

根因是 02 章"物理时钟不可靠":NTP 可能回拨或漂移,破坏 lease 依赖的单调性假设,让旧 leader 误认为自己的 lease 仍有效,提供陈旧读。修复方向不是替换 NTP(基础设施约束),而是改变 lease 的正确性依据——例如用单调时钟(CLOCK_MONOTONIC)而非壁钟(CLOCK_REALTIME),或在 lease 续期时加入 Raft log 版本检查,使 lease 有效性与 Raft term 绑定。

8.5把整张地图收起来

八章内容从一个根因出发,逐层推演到权衡框架。

01 章(根因)确立了为什么分布式系统难:节点只能通过不可靠、延迟无上界的网络互相了解,无法区分"慢"与"死"——这是所有后续机制存在的理由。02 章(时序)回答了"没有可信全局时钟,如何建立顺序":唯一客观顺序是因果序 happens-before;物理时钟用于事务定序会静默丢数据,所以需要 Lamport 时钟 / 向量时钟 / HLC。03 章(一致性谱系)把"一致性"拆成了七档,避免把线性一致与最终一致混为一谈,并引出 CRDT 作为无需协调的最终一致解法。

04 章(复制)和 05 章(分区)是"数据怎么分布"的两个维度:复制解决冗余与可用,分区解决规模与路由;两章合起来解释了 Cassandra 的架构——一致性哈希 + 虚拟节点 + quorum。06 章(共识)回答了"如何让多节点就一个值达成一致而不死锁",Raft 是工程化答案;06 章的 leader + term + 多数派是 etcd 和 HBase 的基础。07 章(事务)把共识延伸到跨分片操作:2PC 是基础,Saga 是长流程补偿,幂等是"at-least-once 下 exactly-once"的工程解法。

这一章(08)是收束:CAP 框架说分区时必须选边;PACELC 补上正常态的延迟/一致取舍;真实系统的 CP/AP/可调标签对应的是前六章的具体机制组合。前沿部分告诉工程师:理论已稳定,变化在实现——时钟精度、CRDT 库、租约正确性。

第 09 章"自检与场景判别"提供跨章综合题,在给定系统约束时判别应选哪一层机制——是共识还是最终一致,是 LWW 还是 CRDT,是 2PC 还是 Saga。

自检

  1. "三选二"为什么是对 CAP 的误解?分区不可避免,真正的取舍因此是什么?
  2. PACELC 的"else"分支补上了 CAP 忽略的什么日常取舍?正常态下保高一致的代价是什么?
  3. 把 etcd、Cassandra、Spanner 各归到 CP 还是 AP,并各说出它用到了本教程哪些章的机制。
  4. 截至 2026,为什么"用纯 NTP 物理时钟给事务定序"已被取代?用什么取代了它?
展开参考答案

1."三选二"把 P 当作可主动放弃的属性,实际上分区是网络环境事实(01 章根因),无法避免。真正的取舍是:当分区发生时,系统优先保线性一致(C,拒绝请求)还是保可用(A,返回可能旧值)。

2. PACELC 的 else 分支补上了"无分区正常态下延迟 vs 一致"的取舍。正常态保高一致的代价是:写请求需要等待多副本同步确认,延迟至少增加一次跨副本网络往返(如 Spanner 的 commit-wait 约 14ms 全球延迟)。

3. etcd → CP(Raft 06章,失去多数派停写);Cassandra → AP(无主 quorum 04章 + 一致性哈希 05章 + LWW 02/04章,分区期间 sloppy quorum 继续写);Spanner → CP 且 PC/EC(Paxos 06章 + 2PC 07章 + TrueTime 02章,全球外部一致)。

4. NTP 精度约 1–100ms,在跨节点并发写入时产生静默顺序颠倒(02 章物理时钟问题)。取代方案:HLC(CockroachDB/YugabyteDB,免原子钟,单调递增因果时间戳);TrueTime + commit-wait(Spanner,有界不确定区间,付延迟换全局有序);向量时钟(纯逻辑,不依赖物理时间)。

进阶挑战 · 刚好够不着

跨区域强一致 + 低延迟:CAP/PACELC 告诉你必然要付什么代价?

一个跨区域、要求强一致事务、又想低延迟的系统,CAP/PACELC 告诉工程师必然要付什么代价?Spanner 与 Aurora DSQL 各自怎么把这个代价压到最小?

提示(卡住再展开)

这类系统是 PC/EC:分区时牺牲可用(选 C),正常态付延迟换一致(选 C 而非 L)。无法同时逃开两个 C 的代价——这是 PACELC 的数学约束,不是实现问题。Spanner 通过 TrueTime 把正常态延迟压到 commit-wait ≈ 2ε(约 14ms 跨大洲),而非等待对端确认;Aurora DSQL 通过高精度硬件时钟 + HLC 缩小不确定区间,实现类似效果而免原子钟。两者都是"承认延迟代价,然后工程上把那个代价压到尽可能小"——这是 PC/EC 系统唯一正确的优化方向。

参考文献

  • Brewer, E. "CAP Twelve Years Later: How the 'Rules' Have Changed." IEEE Computer, 2012.
  • Abadi, D. "Consistency Tradeoffs in Modern Distributed Database System Design: CAP is Only Part of the Story." IEEE Computer, 2012. (PACELC 论文)
  • Corbett, J. et al. "Spanner: Google's Globally Distributed Database." OSDI, 2012.
  • Kingsbury, K. "Jepsen: TigerBeetle 0.16.11." jepsen.io, 2025-06. (VSR 严格可串行化验证)
  • AWS. "How Aurora DSQL achieves high availability and fast transactions." AWS Database Blog, 2024-12. (Aurora DSQL 时钟机制)
  • Mao, Y. et al. "LeaseGuard: Lease-based Distributed Systems are Broken." arXiv, 2025-12. (Raft 租约 bug 系统记录)