CAP 定理是什么?BASE 理论和最终一致性怎么理解?
一句话回答
CAP 说的是:分布式系统发生网络分区(P)时,一致性(C)和可用性(A)只能保一个。分区在真实网络里一定会发生,所以 P 不是可选项,真正的选择是"分区时选 C 还是选 A":选 C 就拒绝一部分请求,选 A 就可能返回旧数据。etcd、ZooKeeper 这类协调服务是 CP;Cassandra、Eureka 这类偏 AP。BASE(基本可用、软状态、最终一致)是选择 A 之后的工程思路:允许短暂不一致,但保证没有新写入后,各副本最终会收敛到同一个值。
详细解析
C、A、P 的准确含义
| 字母 | 含义 | 容易误解成 |
|---|---|---|
| C(Consistency) | 线性一致性:所有读都能读到最近一次完成的写,整个系统看起来像只有一份数据 | 数据库 ACID 里的 C(满足约束),两者不是一回事 |
| A(Availability) | 每个没有故障的节点收到请求后,都必须在有限时间内给出非错误的响应 | "99.99% 的可用率",CAP 里的 A 是一个更极端的定义 |
| P(Partition tolerance) | 节点之间的消息可能丢失或无限延迟,系统仍要继续工作 | "可以选择不容忍分区" |
CAP 由 Eric Brewer 在 2000 年提出,2002 年 Gilbert 和 Lynch 给出了形式化证明。
为什么不是"三选二"
分区发生
节点 1 ──X── 节点 2
x = 2 x = 1(还没同步)
客户端向节点 2 读 x:
选 C:节点 2 拒绝请求或等待(牺牲 A)
选 A:节点 2 返回 x = 1(牺牲 C)
网络分区不是你能"不选"的东西,交换机故障、GC 停顿、跨机房链路抖动都会造成分区。所以 CA 系统在分布式场景下基本不存在,单机数据库才谈得上 CA。
另外两点:
- 没有分区时 C 和 A 可以兼得。CAP 只约束分区期间的行为,不是说系统平时就要放弃什么
- 选择可以细到操作级别。同一个系统里,下单走强一致,商品浏览量走最终一致,很常见
常见系统怎么选
| 类型 | 例子 | 分区时的行为 |
|---|---|---|
| CP | etcd、ZooKeeper、Consul | 基于多数派共识,少数派一侧的节点不能提供写服务 |
| AP | Cassandra、Eureka、DNS | 各分区继续读写,恢复后再合并或修复数据 |
| 可调 | Cassandra 的读写一致性级别、MongoDB 的 readConcern/writeConcern | 按请求选择强弱 |
CP 系统靠 Raft 这类共识算法实现。Redis 主从是异步复制,主节点确认过的写可能还没同步到从节点,切换后就丢了,所以它不提供 CP 的保证,常被归为偏 AP(严格说它也不满足 CAP 定义里的 A),这也是 Redis 分布式锁 在主从切换时会丢锁的原因。
BASE 和最终一致性
BASE 是对 ACID 的反向取舍:
- 基本可用(Basically Available):出故障时允许损失部分功能或性能,比如降级、响应变慢,但核心功能可用
- 软状态(Soft state):允许存在中间状态,比如"支付中",副本之间允许暂时不一致
- 最终一致(Eventually consistent):没有新的更新后,经过一段时间,所有副本会达到一致
业务里最常见的落地是:本地事务 + 消息异步通知其他服务,配合重试和对账,见 分布式事务方案。
一致性模型从强到弱
| 模型 | 保证 |
|---|---|
| 线性一致性 | 读到最新写入,所有操作有一个全局顺序且符合真实时间 |
| 顺序一致性 | 所有节点看到相同的操作顺序,但不要求符合真实时间 |
| 因果一致性 | 有因果关系的操作(先看到帖子才回复)顺序一致,无关的操作可以乱序 |
| 读己之写、单调读 | 面向会话:自己写的自己能读到;读过新值后不会再读到旧值 |
| 最终一致性 | 只保证最终收敛,中间读到什么都有可能 |
PACELC 是对 CAP 的补充:有分区(P)时在 A 和 C 之间取舍;没分区(Else)时在延迟(L)和一致性(C)之间取舍。同步复制到多数派更一致但更慢,这才是系统平时真正面对的权衡。
面试官可能追问
ZooKeeper 是 CP,那它的读一定是最新的吗?
不一定。ZooKeeper 的写经过 Leader 和多数派确认,是线性一致的;但读请求由客户端连接的那个节点直接返回,这个节点可能还没同步到最新数据。官方文档的保证是顺序一致性,并不承诺不同客户端在同一时刻看到相同的数据。需要读较新的值时,可以先调用 sync 让这个节点追上 Leader 再读。etcd 默认的读是线性一致读(要经过 Raft 确认),也可以指定 serializable 读,换取更低延迟,代价是可能读到旧值。
注册中心应该选 CP 还是 AP?
多数人倾向 AP。注册中心的数据短暂不一致,最多是调用到一个刚下线的实例,客户端重试就行;但如果因为分区拒绝服务,所有服务都拿不到地址列表,影响面大得多。Eureka 就是这个思路。用 ZooKeeper 做注册中心的系统,客户端通常会缓存服务列表来弥补。
最终一致的"最终"是多久?
没有理论上限,取决于复制延迟、重试间隔和故障恢复时间。工程上要做两件事:监控复制延迟或消息积压,让"最终"可观测;用定时对账发现长时间没有收敛的数据,再人工或自动修复。
易错点
- 把 CAP 理解成"三个里随便选两个",实际是分区发生时在 C 和 A 之间选
- CAP 的 C 是线性一致性,和 ACID 的 C 不是一个概念
- CAP 的 A 要求每个非故障节点都能响应,不等于平时说的"高可用"
- 说某个系统是 CP 或 AP 往往过于简化,很多系统的一致性级别可以按操作配置
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。