Lesson 0009 · 系统设计 · Phase 3 权衡

CAP、PACELC 与一致性模型

⏱ 预计 30 分钟 🎯 把「一致性」从玄学变成一张可以选的菜单 📖 前置:Lesson 0004 · Lesson 0008
与你的 Mission 的关系

「你的系统要什么一致性」是资深面试官区分背题者与思考者的终极问题。本课给你两样东西:一张一致性等级菜单(Jepsen 的分类法[3])和「业务读旧数据会死人吗」这个唯一判断标准

§1 · CAP 的正确读法

CAP 定理(Gilbert & Lynch 证明[1]):分布式系统具有三个性质——

定理说三者最多取二。但关键是正确读法(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 · 本周行动

行动任务(约 40 分钟)

① 把你公司系统的每个存储标注一致性等级(主库?从库读?Redis?ES?——它们不一样!);
② 找一处「代码假设了强一致、但实际跑在弱一致存储上」的逻辑(先查后写竞态是高发区);
③ 对「订单状态」这一个数据项,用「读旧数据会死人吗」走一遍:哪个状态跃迁需要强一致?

§7 · 延伸资源

💬 你公司的某个数据项拿不准该选哪级一致性?报给我,一起走一遍「读旧数据会死人吗」。