CAP、PACELC 与一致性模型
「你的系统要什么一致性」是资深面试官区分背题者与思考者的终极问题。本课给你两样东西:一张一致性等级菜单(Jepsen 的分类法[3])和「业务读旧数据会死人吗」这个唯一判断标准。
§1 · CAP 的正确读法
CAP 定理(Gilbert & Lynch 证明[1]):分布式系统具有三个性质——
- Consistency:所有节点同一时刻看到相同数据;
- Availability:每个请求都能得到(非错误)响应;
- Partition tolerance:网络分区发生时系统照常工作。
定理说三者最多取二。但关键是正确读法(Brewer 本人的回顾文章[2]):
① P 不是可选项。跨机器的网络分区(机器失联)迟早发生,「放弃 P」意味着放弃分布式,回到单机——所以真实的取舍只发生在分区发生时:要 C(拒绝请求保一致)还是要 A(继续服务保可用)。
② 「我们系统是 CA 的」不成立。单机数据库没有分区问题,谈不上 CA;两台机器之间就必然面对 P。
面试标准句式:「分区发生时,本场景拒绝写、保一致性(CP),还是继续服务、接受不一致(AP)?」——比如金融扣款偏 CP,社交点赞偏 AP。
§2 · PACELC没有分区时也有代价
CAP 只讲了分区时的取舍,日常(无分区)的取舍被 PACELC 补全(Abadi 提出[4]):
分区发生时: PA / PC(CAP 的取舍)
没有分区时: EL / EC —— 要低延迟(Latency)还是要一致(Consistency)?
为什么日常也有取舍?因为强一致需要等副本确认:写入要等所有(或多数)副本点头,读要拿最新副本——每一步都是额外 RTT(Lesson 0002 的数字开始干活了)。Dynamo 类系统用 quorum 让你在两者之间拧旋钮:N 个副本,写 w 个确认、读 r 个确认,w + r > N 即可读到最新。r、w 越大越一致也越慢。
§3 · 一致性等级菜单
从强到弱(Jepsen 的谱系是业界地图[3]):
| 等级 | 保证 | 适用场景举例 |
|---|---|---|
| 线性一致 Linearizability | 操作像在单机上一个接一个发生,读永远最新 | 库存扣减、分布式锁、选主(用 Raft/共识实现[5]) |
| 顺序一致 Sequential | 所有节点看到的操作顺序一致(不要求实时) | 日志复制、配置分发 |
| 因果一致 Causal | 有因果关系的操作全节点同序(回复出现在提问之后) | 评论区(回复不能先于被回复出现) |
| 读己之写 Read-your-writes | 至少能读到自己刚写的数据 | 改完资料立刻可见(L4 的复制延迟解法) |
| 最终一致 Eventual | 停止写入后,副本最终收敛到同值 | 点赞数、转发数、feed 流、DNS、L8 的短码复制 |
对每个数据项问:「读到几秒前的旧数据,业务会死人吗?」——余额差 1 秒:可能死(双花);库存差 1 秒:会超卖(死);点赞数差 1 秒:没人知道。逐项回答,而不是给整个系统贴一个标签。按数据项选一致性,才是资深工程师的做法。
§4 · 随堂检测
§5 · 检索练习
凭记忆做两件事:① 默写一致性五级菜单,每级配一个业务例子;② 写出 PACELC 的完整展开(分区时 / 无分区时各选什么)。
核对参考答案
① 线性一致(库存扣减)→ 顺序一致(日志复制)→ 因果一致(评论回复)→ 读己之写(改资料立即可见)→ 最终一致(点赞数)。② 分区时:PA(保可用)/ PC(保一致);无分区时:EL(保低延迟)/ EC(保一致)——quorum 的 r、w 就是这个旋钮。
§6 · 本周行动
① 把你公司系统的每个存储标注一致性等级(主库?从库读?Redis?ES?——它们不一样!);
② 找一处「代码假设了强一致、但实际跑在弱一致存储上」的逻辑(先查后写竞态是高发区);
③ 对「订单状态」这一个数据项,用「读旧数据会死人吗」走一遍:哪个状态跃迁需要强一致?
§7 · 延伸资源
- 首选精读:Jepsen: Consistency Models——把本课菜单展开成完整地图,配上「能容忍什么异常」的描述[3]
- Brewer《CAP Twelve Years Later》——定理作者的修正版解读[2]
- Raft 可视化:亲手看强一致是怎么「选主 + 多数派确认」换来的[5]
- 下一课 → Lesson 0010 限流、熔断、降级