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
2
3
4
如果发生网络分区 (P):
如何在 A 和 C 之间选择 (A/C)
否则 (Else):
如何在延迟 (L) 和一致性 (C) 之间选择 (L/C)

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 有助于我们在设计系统时不仅考虑极端的网络故障场景,也要考虑日常运行中”低延迟”与”强一致”的平衡。