通用内功第一课必须从 CAP 定理开始——它是分布式数据库一切设计取舍的母法则。第 2 章出现的"AP 倾向""CP 倾向"说法,本节给出精确含义;第 4、5 章所有高可用机制的配置项,都会回到这里找到理论坐标。
阅读完本节,你应当能够:
先精确措辞,再谈理解。
一致性(Consistency):这里指线性一致性——任何读操作都能读到最近一次写入的值,仿佛全系统只有一份数据。注意它不是数据库事务里的 C(那指约束不被破坏),也不是常说的 ACID 一致性。
可用性(Availability):每个收到的请求最终都能收到响应(可以不是最新数据),不保证响应的节点是非故障节点。注意"响应错误"不算可用,超时不响应更不算。
分区容错(Partition Tolerance):节点间的网络可以任意丢失消息(被切成若干孤岛),系统仍能继续运转。
最常见的误读是"三选二 = 随便挑两个"。实际上分区容错不是可选项:在多节点网络上,交换机故障、光缆被挖断、网卡丢包是物理现实,任何声称不容忍分区的系统在分区发生时直接不可用,等于没有答案。所以 CAP 的准确表述是:当网络分区发生时,一致性与可用性只能保住一个。系统设计者的选择空间在于分区发生那一刻,系统把哪边放进牺牲名单——拒绝写入保数据一致(CP),还是照常服务保业务在线(AP)。
CAP 只描述分区发生时的极端时刻,但分区是小概率事件,系统绝大多数时间在"无分区(Else)"状态运行,此时依然存在取舍:延迟与一致性不可兼得。追求强一致就要等副本确认(延迟高),追求低延迟就要异步复制(副本可能落后)。这就是 PACELC 的含义:分区时在 A 与 C 间选,平时在 L(延迟)与 C 间选。
这个推广让很多产品行为变得可解释。DynamoDB 可配置强一致读但收费更高、延迟更高,是典型的 Else 分支选择;MongoDB 的写关注可以要求多数节点确认才返回,也是拿延迟换一致。
背景:同一张电商系统里有两个服务:商品详情浏览与下单扣库存,大促期间机房级网络故障出现了 30 秒。
操作:分别推演两种倾向下的系统行为。商品详情走 AP 倾向的缓存与副本:分区期间旧价格、旧库存展示照常,用户能继续浏览下单入口。下单扣库存走 CP 倾向:库存服务在无法与多数副本通信时拒绝写入,返回"系统繁忙请重试"。
结果:30 秒恢复后,商品详情的旧数据经短暂追平收敛到一致;下单链路没有出现超卖,但丢失了分区窗口内的部分订单请求。
解读:两种选择都对,因为两种业务对"错"的定义不同——浏览页容忍旧数据但不能白屏,库存扣减容忍拒绝请求但不能超卖。CAP 不是用来贴标签的("我们是 AP 系统"),而是用来给每个业务操作定行为的。
变式:若业务改成"库存是虚拟商品且允许事后补货",扣减也可放松为 AP,用补偿流程兜底少数超卖。可见倾向是业务决策,不是技术偏好。
三个高频误读值得集中澄清。误读一:CAP 说明 NoSQL 必然不可靠。恰恰相反,它说明"既强一致又全可用还不怕分区"的免费午餐不存在,关系型数据库的分布式方案同样逃不脱,只是把选择藏在配置里。误读二:CP 系统分区时完全不可用。CP 通常只是拒绝写入或部分写入,读服务可能照常。误读三:AP 系统数据会永久不一致。AP 的配套承诺是最终一致——分区愈合后副本收敛,3.3 节展开这个承诺的细节。
CAP 常被人误读成"三选二",更准确的说法是:当网络分区(P)发生时,你只能在一致性(C)与可用性(A)之间选一个。分区不发生的时候,系统可以同时满足 C 与 A。
| 场景 | 分区时的选择 | 具体表现 | 适用数据 |
|---|---|---|---|
| 银行转账 | 保 C,牺牲 A | 无法确认对端状态时拒绝写入,宁可报错也不给错数 | 账务、库存、配额 |
| 社交点赞 | 保 A,牺牲 C | 两侧都接受写入,恢复后合并,短暂计数偏少 | 点赞、浏览数、动态流 |
| 商品详情页 | 保 A,牺牲 C | 展示稍旧的商品信息,允许几秒延迟 | 目录、配置、内容 |
| 秒杀库存 | 保 C,牺牲 A | 库存扣减走强一致路径,超卖零容忍 | 库存、优惠券发放 |
假设三个节点(N1、N2、N3)组成一个集群,N1 与另外两个节点之间网络中断,形成"少数派 N1"与"多数派 N2+N3"两个分区。此时客户端仍在向两边写入同一个用户的昵称。
保一致性的做法:多数派继续服务(它仍能与多数节点确认),少数派 N1 拒绝写入。客户端在 N1 侧收到错误,需要重试到多数派。代价是 N1 分区期间该用户无法修改资料;收益是不存在冲突版本,恢复后无需合并。
保可用性的做法:两边都接受写入,N1 记录"昵称改为 A",多数派记录"昵称改为 B"。分区恢复后系统必须解决冲突——常见策略有"最后写入胜利"(按时间戳取新,依赖时钟可靠)、"保留多版本交应用层处理"(如购物车合并)、"按业务规则自动合并"(如计数取最大值)。代价是恢复逻辑复杂,且可能丢失用户感知上已经"成功"的写入。
这个演练揭示了 CAP 的真实含义:选择发生在分区期间,代价兑现于分区恢复之后。保可用不是没有代价,只是把代价从"报错"变成了"事后合并"。因此选型时真正要回答的问题是——这类数据,你更受不了"暂时不能用"还是"暂时不对"?
CAP 定理判了强一致的"刑",BASE 理论则是接受判决后的生活指南。