CAP 理论与系统设计
分布式系统有三盏灯,但只能亮两盏。
这就是 CAP 理论告诉我们的:一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance),你最多只能同时满足两个。
等等,分区容错性怎么能不选呢?
简单来说:网络分区是必然的。你的服务器可能跨机房、跨机房甚至跨地域,光纤可能被挖断,路由器可能抽风。在分布式系统中,P 不是可选项,是必选项。
所以,CAP 理论本质上是在问:C 和 A,你选哪个?
一致性 vs 可用性:没有标准答案
CP 系统:牺牲可用性换一致性
典型代表:ZooKeeper、etcd、HBase
想象银行的转账系统:你的账户余额是 100,转给朋友 50。如果系统不一致,你可能付两次 50 都成功——这叫「双花」,是灾难性的。
// ZooKeeper 的写操作是强一致的
// 如果 leader 宕机,写操作会失败(不可用)
// 但一旦返回成功,数据一定是一致的
public class ZKExample {
public void write(Data data) {
// 写入需要多数节点确认
// 如果网络分区,部分请求会失败
}
}适用场景:金融交易、库存管理、分布式锁
AP 系统:牺牲一致性换可用性
典型代表:Cassandra、DynamoDB、Redis Cluster
想象微博的时间线:少刷到一条微博,用户感知不强;但如果服务器挂了,用户打开白屏,那才是灾难。
// Cassandra 采用最终一致性模型
public class CassandraExample {
public void write(String key, String value) {
// 写入本地节点即可返回成功
// 数据会异步复制到其他节点
// 短暂不一致,但最终一致
}
public String read(String key) {
// 读请求可能返回旧数据
// 但系统保证可用
}
}适用场景:社交 feed、评论系统、日志收集
你真的理解「一致性」吗?
很多人在面试中说「我要保证强一致性」,但追问下去就懵了。
一致性的三个层次:
| 级别 | 说明 | 例子 |
|---|---|---|
| 强一致性 | 写入后立即可读 | 同步复制 |
| 弱一致性 | 写入后可能读到旧值 | 异步复制 |
| 最终一致性 | 写入后最终能读到 | DNS、 Cassandra |
实际工程中:几乎没有人用强一致性,成本太高。大多数系统用的是「最终一致性 + 补偿机制」。
跨时代的 BASE 理论
CAP 理论太理论化,实际落地需要具体方法论。BASE 理论就是 CAP 中 AP 的工程实践:
- Basically Available:基本可用,允许偶尔失败
- Soft state:软状态,数据可以是中间状态
- Eventually consistent:最终一致性,允许延迟但最终一致
// BASE 思想下的订单服务
public class OrderService {
// 1. 先标记「处理中」
public void createOrder(Order order) {
order.setStatus(OrderStatus.PROCESSING);
orderDao.save(order); // 写入即可用
// 2. 异步处理实际业务
messageQueue.send(order);
// 3. 最终状态由消费者更新
// 这个过程可能有延迟,但最终一致
}
}面试中的回答套路
面试官问 CAP,不是想听你背定义,而是想看你能不能结合具体场景做决策。
错误回答:
「CAP 理论说一致性、可用性、分区容错性只能满足两个,我们要根据场景选择。」
这种回答等于没说。
正确回答:
「对于短链接系统,我选择 AP 模型。原因有三:
- 用户点击短链接,系统必须高可用,卡一下用户就跑了
- 点击统计允许短暂不一致,差个几十条数据不影响业务
- 通过消息队列做异步补偿,可以保证最终一致性
但对于账户余额这类场景,我会选择 CP。」
追问:
- 「如果你的 AP 系统出现数据冲突怎么办?」
- 「怎么设计补偿机制?」
- 「如何让用户感知不到不一致?」
这些问题没有标准答案,考的是你对一致性的深层理解。
总结
CAP 理论不是教条,是思考框架:
- P 是必选的:网络分区必然发生
- C 和 A 看场景:金融选 C,社交选 A
- 大部分系统是 AP + 最终一致性:BASE 理论是工程实践
- 一致性有层次:强一致成本高,弱一致更实用
下次被问到 CAP,别急着回答「我选 AP」或「我选 CP」。
先问自己:这个系统里,什么数据是一致性优先的,什么数据是可用性优先的?
答案可能让你意外:同一个系统,C 和 A 可以并存——只需要分清哪些数据走 CP,哪些走 AP。
