CAP 理论是什么?实际系统如何取舍?
简化版
CAP 指分布式系统的三个特性:一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。它真正表达的是:网络分区发生时,系统无法同时保证强一致和可用,只能在 CP 与 AP 之间取舍。因为分布式系统无法避免网络分区,所以 P 不是可选项,面试里要答成“分区时 C 和 A 的取舍”。
详细版
CAP 的三个含义要讲准确:
| 特性 | 含义 | 关键点 |
|---|---|---|
| C 一致性 | 所有节点对外表现得像一份数据 | 这里通常指强一致,读到最新写入 |
| A 可用性 | 每个非故障节点都能在有限时间响应 | 响应可以成功或明确失败,但不能无限等待 |
| P 分区容错性 | 网络把节点隔开时系统仍能处理请求 | 跨机器通信必须考虑分区 |
分布式系统里,网络故障、机房隔离、交换机异常、丢包超时都可能造成分区。分区出现后,如果继续让两个分区都读写,就可能产生不一致;如果为了不产生不一致而拒绝某些请求,就牺牲了可用性。所以实际取舍是:
- CP:分区时宁可拒绝服务,也要保证数据一致,常见于 ZooKeeper、etcd、强一致元数据系统。
- AP:分区时尽量继续服务,允许短暂不一致,后续靠同步、冲突解决、补偿达到最终一致,常见于很多缓存、注册中心、社交类系统。
面试要避免把 CAP 简单说成“三选二”。更准确的表达是:没有分区时 C 和 A 可以同时满足;分区发生时,P 已经摆在面前,系统必须在 C 和 A 之间选一边倾斜。
完整版教学
一、先把 CAP 放进一个真实场景
假设订单服务有两个副本,A 在上海机房,B 在北京机房。正常情况下,用户扣库存写到 A,数据同步到 B,两个机房都能读到同样的库存。现在两个机房之间网络断了,A 和 B 互相不知道对方的最新状态,这就是网络分区。
此时北京用户访问 B,如果 B 继续扣库存,系统可用性很好,但 A 和 B 可能同时卖出最后一件商品,库存就不一致了。如果 B 为了保证不超卖而拒绝写请求,就保护了一致性,但北京用户看到的是服务不可用。CAP 的矛盾就出现在这一刻:不是平时不能一致又可用,而是分区时无法同时做到“继续服务”和“绝不产生分歧”。
二、为什么 P 不是你想不想选的问题
很多初学者会问:我能不能选 CA,不要 P?在分布式系统里这基本没有意义。只要服务跨机器、跨网络、跨机房,分区就可能发生。你可以说“我暂时不处理分区,一分区就整体不可用”,但这相当于系统没有分区容错能力,不是一个可靠的分布式设计。
所以工程上不会问“要不要 P”,而是问:“当 P 发生时,业务更怕什么?”如果更怕脏数据、重复扣款、超卖,就偏 CP;如果更怕服务不可用、用户无法浏览、服务发现完全瘫痪,就偏 AP。
三、CP 系统牺牲的不是全部可用,而是部分请求
CP 不等于整个系统挂掉。它的做法通常是让无法确认多数派、无法确认主节点身份、无法确认最新数据的节点停止对外写入,甚至停止提供强一致读。比如 etcd/Raft 集群中,如果某个少数派分区没有 Leader,它就不能接受写请求,因为它无法保证这个写会被集群承认。
这样做的代价是:一部分节点明明还活着,却不能响应某些请求。好处是:系统不会产生两个权威结果,不会出现两个 Leader 同时写配置、两个库存中心同时扣库存这样的灾难。
四、AP 系统牺牲的不是永远一致,而是实时一致
AP 也不是“数据随便乱”。AP 的核心是先保服务,允许副本在一段时间内不一致,等网络恢复后通过同步、版本比较、冲突合并、补偿任务让数据收敛。比如用户点赞数、浏览量、推荐候选集、服务注册表,短时间旧一点通常可以接受。
AP 系统真正难的是冲突处理。两个分区都写了同一份数据,恢复后谁覆盖谁?常见策略有最后写入胜出、版本号比较、向量时钟、业务合并、人工介入。AP 的成本不是没有成本,而是把成本从“请求当场等待一致”转移到“后台修复和冲突解决”。
五、CAP 与 PACELC 的关系
CAP 只讲分区时的取舍,但系统大部分时间没有分区。PACELC 把问题补完整:如果发生 Partition,就在 Availability 和 Consistency 之间取舍;Else 没有分区时,也要在 Latency 和 Consistency 之间取舍。强一致读写通常要等待复制确认,延迟更高;最终一致通常延迟更低,但可能读到旧数据。
面试答到 PACELC,会显得你不是背概念,而是在做系统设计。真实系统往往是:核心链路局部 CP,外围链路偏 AP;写链路更强一致,读链路通过缓存和副本降低延迟。
六、面试追问怎么接
如果面试官问“Redis、MySQL、ZooKeeper 是 CP 还是 AP”,不要机械贴标签。要说明具体模式和场景:ZooKeeper/etcd 的一致性协议偏 CP;Redis 主从默认异步复制,故障切换时可能丢数据,更偏可用和低延迟;MySQL 单主强一致事务在单库内成立,跨机房复制通常又涉及延迟和一致性取舍。CAP 是分析框架,不是给产品永久贴一个字母标签。
七、常见误区与追问
这道题不能只背概念,要把「CAP 定理」放回真实分布式系统里解释:谁发起、谁协调、状态如何变化、失败后怎么兜底,以及它和性能、可用性、一致性的取舍。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心结论 | CAP 说网络分区发生时,一致性 C 和可用性 A 不能同时完美满足,P 是分布式系统必须面对的前提 | 不要停在名词解释 |
| 流程机制 | 出现网络分区 -> 判断是否继续响应请求 -> 若继续响应可能读写旧数据 -> 若拒绝响应保持一致但不可用 -> 结合业务选择 CP 或 AP | 说明触发方、参与方、状态变化和兜底 |
| 工程取舍 | 3 节点系统若 1 个节点与另外 2 个节点网络隔离,继续两边都写会破坏 C,拒绝一边写会牺牲 A | 分布式基础题不能只背概念,必须落到网络不可靠、节点会故障、数据有副本这些前提 |
CAP 定理 面试拆解:
1. 出现网络分区
2. 判断是否继续响应请求
3. 若继续响应可能读写旧数据
4. 若拒绝响应保持一致但不可用
5. 结合业务选择 CP 或 AP
记忆钩子:先定义问题,再说明一致性、可用性、分区、复制、时钟和故障模型的取舍;回答时要紧扣「CAP 定理」这道题,不要把相邻概念混成一段泛泛的分布式套话。
- 误区:CAP 是 C、A、P 三选二。 严格说分布式系统必须容忍 P,分区发生时才在 C 和 A 之间取舍。
- 误区:牺牲一致性就是数据错误。 AP 系统通常牺牲的是强一致,仍会通过同步、重试和修复达到最终一致。
- 误区:数据库强一致就不用考虑 CAP。 跨节点复制和网络分区仍然存在,强一致会以可用性或延迟为代价。
- 追问:注册中心为什么常说选 AP? 因为服务发现更怕完全不可用,短暂旧地址可由客户端重试和健康检查兜底。
- 追问:什么时候更偏 CP? 库存、余额、配置元数据等不能接受旧值写入的场景更偏 CP。
- 追问:CAP 和 BASE 有什么关系? BASE 是在 AP/最终一致方向上的工程思想,接受软状态换取可用性。
八、加强记忆
CAP 要记成一句工程话:分布式必须面对网络分区,分区发生时,如果继续服务就可能不一致,如果保证强一致就必须拒绝部分请求。所以真正选择是 CP 还是 AP,不是简单“三选二”。钱、库存、锁、元数据通常偏 CP;点赞、浏览、推荐、服务发现常常偏 AP;更完整的设计还要用 PACELC 思考平时的一致性与延迟权衡。