CAP 与 BASE
2026/10/11大约 5 分钟
CAP 与 BASE
「一致性、可用性、分区容错三选二」是被误传最广的口号。CAP 真正说的是:当网络分区发生时,你必须在一致性和可用性之间二选一。而 BASE 是大规模系统给出的工程退让。
1. 先厘清三个字母
| 字母 | 全称 | 含义 |
|---|---|---|
| C | Consistency(一致性) | 所有节点在同一时刻看到同一份最新数据,等价于线性一致性 |
| A | Availability(可用性) | 每个到达非故障节点的请求,都能得到非错误的响应(不保证是最新数据) |
| P | Partition tolerance(分区容错) | 网络分区(节点之间消息丢失或延迟)时系统仍能继续运行 |
关键点在于 P 不是可选项。在真实网络里,分区一定发生——交换机故障、跨机房抖动、GC 停顿都会造成节点间「失联」。既然 P 必须选,真正的问题就变成:分区发生的那一刻,你放弃 C 还是放弃 A?
- 放弃 A 保 C → CP:宁可不响应,也要保证不返回过期数据。
- 放弃 C 保 A → AP:宁可返回可能过期的数据,也要保证有响应。
一句话记忆
CAP 不是「三选二」,而是「P 必选,然后在 C 和 A 之间二选一」。而且这个取舍只在分区期间成立——没分区时,系统可以同时提供一致性和可用性。
2. 一致性到底是什么
很多人把「强一致」和「能读到最新值」划等号,其实现代系统的一致性是一把梯子,越强越贵:
| 级别 | 含义 | 典型场景 |
|---|---|---|
| 线性一致(Linearizable) | 所有操作看起来在单一时间点原子发生,全局有序 | 分布式锁、选主、元数据 |
| 顺序一致(Sequential) | 所有进程看到同一操作顺序,但不要求与真实时间对齐 | 部分协调服务 |
| 因果一致(Causal) | 有因果关系的操作顺序被保留,无因果的可乱序 | 社交评论、协作编辑 |
| 最终一致(Eventual) | 停止写入后,最终所有副本收敛到同一值 | 缓存、搜索索引、计数 |
选型时的正确问法不是「要不要强一致」,而是「这个数据到底需要哪一级」。商品库存要接近线性一致,商品详情页的浏览量用最终一致即可。
3. PACELC:把分区之外的代价也补上
CAP 只描述了「分区时」的取舍。分区没有发生时呢?系统仍然要在延迟(Latency)和一致性(Consistency)之间权衡——要强一致就得多等几个副本确认,延迟升高;要低延迟就可能读到一个暂时落后的副本。
这被总结为 PACELC:
如果有 P(分区),在 A 和 C 之间选;Else(否则),在 L(延迟)和 C 之间选。
这提醒我们:即使网络一切正常,强一致也有成本——它体现在延迟上,而不是「能不能用」上。
4. 常见系统的倾向
| 系统 / 组件 | 倾向 | 说明 |
|---|---|---|
| ZooKeeper / etcd | CP | 用于协调、选主、配置,分区时可能短暂不可用以保证元数据一致 |
| 传统 RDBMS 主从强同步 | CP | 主机确认加从库同步,牺牲部分可用性换取不丢数据 |
| Eureka(注册中心) | AP | 宁可返回可能过期的服务列表,也不让注册中心不可用 |
| Cassandra / DynamoDB | AP(可调) | 通过一致性级别(如 QUORUM)在 C/A 之间滑动 |
| DNS | AP | 最终一致可接受,可用性优先 |
| Redis 主从(默认异步复制) | AP | 主库故障切换可能丢失极少量写入 |
没有绝对的好方案
同一个系统里,不同数据可以有不同的取舍:账户余额走 CP,用户昵称走 AP。按数据分级,而不是按系统一刀切。
5. BASE:强一致的工程替代
强一致(ACID)在大规模分布式里代价高昂,BASE 是与之相对的一组妥协原则:
- Basically Available(基本可用):允许损失部分可用性——比如降级、限流、返回兜底数据,但核心功能可用。
- Soft State(软状态):允许系统存在中间态,不要求任何时刻都一致。
- Eventually Consistent(最终一致):在没有新写入的前提下,数据最终会收敛到一致。
BASE 不是「放弃正确性」,而是把「瞬时一致」换成了「最终一致 + 可修复」。它必须配套一整套机制,否则「最终」会变成「永远不」:
| 配套机制 | 作用 |
|---|---|
| 幂等 | 保证重复投递/重试不会造成重复扣减 |
| 重试与退避 | 让暂时失败的操作有机会成功 |
| 对账任务 | 周期性扫描,发现不一致并告警/修复 |
| 状态机 | 用明确的状态迁移描述流程,便于补偿与追踪 |
| 异步化(消息/事件) | 解耦生产与消费,削峰填谷 |
6. 实践建议
- 先写清业务一致性需求,再选组件。把「这个数据晚 1 秒一致会不会出问题」问清楚。
- 不要给所有数据一刀切强一致。一刀切的结果通常是:该快的慢了,该准的没准。
- 最终一致必须回答三个问题:多久能一致?如何发现不一致?发现后如何修复?答不上来,就是给自己埋雷。
- 分区要演练。用混沌工程主动注入网络分区,验证系统在 CP/AP 取舍下的真实表现,而不是等它自然发生。
7. 小结
- P 必选,CAP 的取舍是分区期间在 C 与 A 之间二选一,不是三选二。
- 一致性是一把梯子(线性 → 顺序 → 因果 → 最终),按数据分级选用。
- PACELC 补充了「无分区时在延迟与一致性之间取舍」这一维度。
- BASE(基本可用、软状态、最终一致)是强一致的工程替代,但必须配套幂等、对账与补偿。
- 能用简单方案解决的,就不要用 CAP 的取舍去为难自己。