CAP 定理
1.1 定义与历史
CAP 定理由 Eric Brewer 于 2000 年提出,后经 Seth Gilbert 和 Nancy Lynch 在 2002 年形式化证明,是分布式系统领域最基础也是最著名的定理之一。CAP 是以下三个属性的首字母缩写:
- Consistency(一致性):所有节点在同一时刻看到相同的数据。注意这里的”一致性”与 ACID 中的 C 不同——CAP 中的 C 近似于”强一致性”或”线性一致性”,即写操作完成后,所有后续的读操作都能读到最新写入的值。
- Availability(可用性):每个非故障节点在合理时间内都能返回一个非错误的响应。注意这并不意味着返回的数据是”最新”的,只要求服务能响应。
- Partition Tolerance(分区容错性):当网络分区(节点之间通信中断)发生时,系统仍然能够继续运行。
1.2 为什么不能同时满足
理解 CAP 的关键在于:网络分区是不可避免的。在分布式系统中,节点间的网络通信可能随时中断,这不是一个可选项——它会发生。因此 P(分区容错性)在实际系统中是一个必须满足的条件。
当网络分区发生时,系统面临一个关键抉择:是选择一致性(C),阻塞或拒绝请求直到分区恢复;还是选择可用性(A),允许各分区独立响应请求,接受数据不一致?
以双节点主从复制为例:主节点负责写,从节点同步数据。当网络断开后:
- 如果继续让从节点处理读请求 → 牺牲一致性(从节点数据可能过期)
- 如果拒绝从节点的读请求 → 牺牲可用性(从节点不可用,尽管自身正常运行)
1.3 CA / CP / AP 取舍
| 类型 | 选择 | 典型场景 | 代表系统 |
|---|---|---|---|
| CP | 一致性 + 分区容错 | 金融转账、库存扣减 | ZooKeeper, etcd, Consul |
| AP | 可用性 + 分区容错 | 社交动态、用户信息 | Eureka, Cassandra, DynamoDB |
| CA | 一致性 + 可用性 | 无网络分区(单机) | 传统关系型数据库(单机) |
关键的认知转变:早期很多系统声称自己是 CA 系统,但这其实是一个伪命题。在真实分布式环境中,CA 意味着系统在分区发生时直接不可用——因为既不选择 C 也不选择 A。实际上,CA 只在单机系统或局域网无故障的理想条件下才成立。真正生产级的分布式系统必须在 CP 和 AP 之间做权衡。
1.4 实际系统中的权衡
Eureka 的 CP → AP 演化:Spring Cloud 生态中,Eureka 最初设计强调分区容错和可用性,牺牲了强一致性。当 Eureka Server 集群出现网络分区时,各节点仍然可以接受服务注册和查询请求,即使数据存在短暂不一致。这是因为服务发现的容忍度较高——“宁可返回一个可能宕机的服务节点,也不拒绝所有请求”。
Nacos 的 AP + CP 混合模式:Nacos 默认采用 AP 模式,通过 Distro 协议实现最终一致性服务注册;同时支持切换到 CP 模式(基于 Raft),适用于对一致性要求较高的配置管理场景。这种”同一系统、两种模式”的设计打破了 CAP 二选一的刻板印象,实际上 CAP 指的是在分区发生时的一致性/可用性选择,而非整个系统只能取其一。
现实中的 CAP 并非二元对立:
- 系统可以在正常情况下同时提供 C 和 A
- 仅在网络分区时才需要在 C 和 A 之间做取舍
- 不同业务模块可以有不同选择(Nacos 配置中心选 CP,注册中心选 AP)
- 可以通过”概率性 CAP”理解:将延迟超过某个阈值视为一种轻度分区,此时系统仍需做选择
1.5 PACELC 扩展
PACELC 是对 CAP 的重要补充,由 Daniel J. Abadi 在 2010 年提出:
1 | 如果发生网络分区 (P): |
PACELC 指出,即使在正常运行(无分区)的情况下,系统设计也面临延迟与一致性的权衡,因为强一致性(如同步复制)必然带来更高的响应延迟。
| 系统 | 有分区时 | 无分区时 | 分类 |
|---|---|---|---|
| ZooKeeper | C | C | PC/EC |
| Cassandra | A | L | PA/EL |
| DynamoDB | A | L | PA/EL |
| MongoDB(默认) | C | L | PC/EL |
| CockroachDB | C | L | PC/EL |
理解 PACELC 有助于我们在设计系统时不仅考虑极端的网络故障场景,也要考虑日常运行中”低延迟”与”强一致”的平衡。