16.7 一致性模型谱系图

一句话

一致性模型不是「强弱排行榜」,而是几组正交的约束(实时序、全序、事务原子性、客户端会话);把它们画成谱系,选型就变成「业务需要哪几条约束、愿意为哪几条付 RTT 与可用性」。

谱系图:单对象的强弱链

严格一致(不可实现)        物理时间 + 瞬时全局可见
   │  削弱:物理时间 → 实时先后 + 逻辑全序
线性一致(16.2)            实时顺序 + 全序 + 单对象原子
   │  削弱:去掉实时顺序
顺序一致(16.3)            全序 + 程序顺序
   │  削弱:全序 → 仅因果顺序
因果一致(16.4,+ 收敛)    只约束 happened-before
   │  削弱:连因果顺序也不要
最终一致(16.5)            只承诺最终收敛

三条横向的补充轴,不在这条主链上:

轴 内容 说明
事务轴 可串行化 / 严格可串行化 约束的是「一组操作」而非「单个操作」
客户端轴 会话保证:16.6 只约束一个客户端会话,可与任意数据层组合
拓扑轴 单主 / 多主 / 无主、同步 / 异步 决定「怎么实现」,不直接等于某个模型(18.1 复制模型:单主 / 多主 / 无主)

包含关系:谁能推出谁

关系 成立? 理由 / 反例
严格一致 ⇒ 线性一致 ✅ 物理时间排序是实时顺序的特例
线性一致 ⇒ 顺序一致 ✅ 实时顺序的全序必然尊重程序顺序
顺序一致 ⇒ 因果一致 ✅ 全序是因果序的线性扩展(单对象)
因果一致 ⇒ 最终一致 ✅(加可靠投递 + 收敛) 所有写最终可见,且并发写需确定性合并
线性一致 ⇒ 严格一致 ❌ 并发写可被排成任意顺序,不按物理时间(16.1)
顺序一致 ⇒ 线性一致 ❌ 写完成后的读仍可读到旧值(H2)
因果一致 ⇒ 顺序一致 ❌ 并发写在副本间顺序不同(R2 的 c1 在 a1 前)
最终一致 ⇒ 因果一致 ❌ 允许「评论先于帖子」的因果气泡

⚠️ 上表的「顺序一致 ⇒ 因果一致」限定在单个对象/单一广播域。跨对象时顺序一致本身不可组合(16.3 的 X/Y 反例),谱系图不能直接套到「多个对象拼起来」的系统上。

一张表验证「严格包含」

模型 实时序 全序 因果序 分区期间可用 可实现
严格一致 ✅(物理时间) ✅ ✅ ❌ ❌
线性一致 ✅ ✅ ✅ ❌(CP) ✅
顺序一致 ❌ ✅ ✅ ⚠️(写不可用,读可陈旧) ✅
因果一致 ❌ ❌ ✅ ✅ ✅
最终一致 ❌ ❌ ❌ ✅ ✅

「分区期间可用」这一列是 17.3 分区期间的取舍 的内容——这里只看结论:越往下越可用。

另一个轴:单对象 vs 事务

把「是否要求实时顺序」与「约束单个操作还是整组事务」交叉,得到四象限:

单个对象/操作 一组事务
不要求实时 顺序一致 可串行化
要求实时 线性一致 严格可串行化

四个格子的含义:

模型 一句话 典型问题
顺序一致 所有操作有全序,但可以落后于现实 读到旧值
线性一致 单对象看起来像单副本,且尊重实时 跨 key 不一致
可串行化 事务等价于某个串行顺序,但不尊重实时 事务被排到后面,读到「未来」
严格可串行化 可串行化 + 事务间实时顺序 跨地域提交延迟(commit-wait)

最容易混的两组:

  • 线性一致 ≠ 可串行化:前者是单对象原子性,后者是事务隔离;
  • 严格可串行化 ≠ 严格一致:前者可实现(Spanner 用 TrueTime),后者不可实现。

决策表:从业务不变量出发

业务不变量 需要的最弱模型 典型实现
余额不能透支、转账不能凭空多钱 严格可串行化(或线性一致 + 幂等) Spanner、单主事务库 + 幂等(25.4 幂等设计与去重)
库存不能超卖 线性一致 CAS / 事务 单主 + 条件更新、分布式锁(48.3 分布式锁)
配置/元数据读到的必须是最新已提交 线性一致读 etcd 默认读、ZooKeeper + sync
选主、租约、分布式锁 线性一致 共识组(21.5 Raft:选主)
跨对象的业务规则(订单 + 库存 + 账务) 严格可串行化 分布式事务/单库事务(24.9 事务模型选型)
评论不能先于帖子、回复不能先于原消息 因果一致 因果广播/会话令牌(16.4)
用户刚保存的资料刷新后还在 会话保证(RYW) 会话令牌/写后读主(16.6)
点赞数、播放量最终准确即可 最终一致(CRDT) G-Counter + 反熵
购物车、收藏夹 最终一致 + 会话保证 OR-Set/多值合并
日志、分析、推荐特征 最终一致 异步管道

🔑 选型顺序:先写业务不变量 → 再找能保证它的最弱模型 → 最后才看系统能不能实现。反过来(先选技术栈,再解释它能给什么一致性)是绝大多数一致性事故的起点。

常见系统的定位(带前提)

系统 提供什么 前提 / 注意
etcd 默认线性一致读写;serializable 读是顺序一致 跨地域写要等多数派 RTT
ZooKeeper 写线性一致、客户端 FIFO 顺序、读可能陈旧 需要新鲜读要先 sync()
Spanner 严格可串行化 TrueTime + commit-wait,提交有延迟
Cassandra 以最终一致为主;分区内 LWT 提供 CAS quorum 读不等于线性一致(16.2 的坑)
DynamoDB 最终一致读/强一致读可选;事务 API 强一致读仍受分区可用性约束
MongoDB 读/写关注可调;因果会话 因果保证限于会话
Redis 单节点单命令原子;主从异步复制 切主可能丢写,不能当线性一致用
Kafka 分区内日志顺序 + ISR 跨分区没有全局顺序

⚠️ 这张表只能当「起点」:同一个产品的不同 API、不同配置提供不同模型。宣称一致性之前,先看 API 语义与故障行为,而不是看产品名。

六个常见误解

误解 现实
「CAP 三选二」 分区发生时只能在 C 与 A 之间取舍;P 不是可选项(17.2 为什么 “三选二” 是错的)
「最终一致 = 便宜」 冲突解决、元数据、反熵、修复、监控都要钱;省的是「协调等待」,不是总成本
「线性一致 = ACID」 线性一致是单对象可见性;ACID 是事务属性,两者正交
「强一致靠 NTP 就行」 时钟有误差与回拨;线性一致靠共识/租约,不靠时钟同步(16.1)
「因果一致很弱,没什么用」 在始终可用的系统里它是能实现的最强模型(16.4)
「顺序一致 = 线性一致」 差一条实时顺序;本地读的全序广播系统是顺序一致,不是线性一致

反模式

反模式 后果
用「强一致」当需求描述 无法验收,团队各自理解不同
只看产品名,不看 API 与配置 同一个库的两种读模式,一致性差一个等级
把会话保证当全局一致 跨用户读到旧值,投诉时才发现
跨对象用线性一致对象拼事务 组合后不满足原子性(16.3 的不可组合性)
为「未来可能的需求」上严格可串行化 跨地域延迟与成本翻倍,收益为零
把最终一致当「不用设计冲突」 冲突在峰值出现,LWW 静默丢数据
忽略故障下的一致性 正常路径全绿,切主/分区后读出旧值或丢写

自检

Q1 用一张图说明:为什么「线性一致 ⇒ 顺序一致」成立,而反过来不成立?

▸ 答案:线性一致要求存在一个尊重实时顺序的全序;实时顺序包含程序顺序,所以这个全序也尊重程序顺序,满足顺序一致的定义。反过来,顺序一致的全序不要求尊重实时顺序,可以把「写完成后才发起的读」排在写之前,于是读到旧值——H2 就是反例。差别只在「实时顺序」这一条约束。

Q2 「线性一致」与「可串行化」分别在四象限的哪个位置?为什么不能互相替代?

▸ 答案:线性一致在「单对象 + 要求实时」;可串行化在「事务 + 不要求实时」。线性一致不给跨对象原子性(读 x、读 y 可能来自不同时刻);可串行化不给实时顺序(事务可以被排到实时更晚的位置)。要同时满足,选「严格可串行化」。工程上银行转账需要的是后者,单个配置读取需要的是前者。

Q3 因果一致比顺序一致弱,为什么很多全球系统反而选它?

▸ 答案:因为顺序一致要求所有副本共享同一个全序,这需要全序广播/共识;分区时少数派不能继续写,跨地域写要付 RTT。因果一致只约束有因果关系的操作,并发写各副本可以不同顺序,因此分区期间两侧都能继续读写,网络恢复后靠反熵收敛。对社交、协作、购物车这类业务,「不出现因果气泡 + 最终收敛」已经够用,且可用性高一个等级。

Q4 会话保证在谱系图的哪里?它能提升全局一致性等级吗?

▸ 答案:它不在主链上,是一条「客户端轴」:只约束一个会话内的四条性质(RYW/MR/MW/WFR),可以叠加在最终一致的数据层上。它不改变全局模型——其他客户端仍可能读到旧值,跨客户端的因果也不保证。它的价值是「让单个用户不看到自己的操作倒退」,成本远低于全局强一致。

Q5 业务说「我们要强一致」,你怎么把它翻译成可验收的规格?

▸ 答案:追问三个维度并写成 API 级承诺:① 范围:单 key 还是跨 key 事务?② 实时性:写返回后,其他节点的读是否必须立刻看到(线性一致),还是允许会话内保证即可(RYW)?③ 故障行为:分区/切主时,读是否可以返回旧值、写是否可以失败?把答案落成「某 API 在某故障模型下提供线性一致读/严格可串行化事务」,再配故障注入测试(切主、分区、时钟偏移),才能验收。

跨篇相关:谱系顶点的不可实现性见 16.1 严格一致性;实时约束与协调成本见 16.2 线性一致性;去掉实时约束见 16.3 顺序一致性;因果与可用性见 16.4 因果一致性;最终收敛与冲突见 16.5 最终一致性;客户端轴见 16.6 会话保证;CAP 与 PACELC 的完整讨论见 17.1 CAP 的由来与准确表述、17.2 为什么 “三选二” 是错的、17.4 PACELC:无分区时的延迟-一致性权衡、17.6 CAP 之后的补充理论;共识与 quorum 见 21.2 Quorum 与 W + R > N 的证明、21.5 Raft:选主;复制的同步/异步见 18.2 同步、半同步、异步;逻辑时钟与因果见 23.3 Lamport 逻辑时钟、23.4 向量时钟;事务模型选型见 24.9 事务模型选型;分布式锁见 48.3 分布式锁。