分布式系统学习笔记(一):CAP 与一致性

写在前面

本文是分布式系统系列第一篇。分布式系统的所有设计都绕不开一个理论:CAP 定理。它解释了为什么没有完美的分布式系统、为什么必须在一致性和可用性间取舍。


一、CAP 定理

1.1 三个性质

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
C — Consistency(一致性)
  所有节点在同一时刻看到相同数据
  读操作总能读到最新写入
  (严格一致性 / 线性一致性)

A — Availability(可用性)
  每个请求都能收到非错误响应(不保证是最新数据)
  系统一直可用,不拒绝服务

P — Partition tolerance(分区容忍)
  网络分区(节点间断连)时系统仍能运作
  消息丢失、延迟、节点宕机不影响整体

CAP 定理:分布式系统最多同时满足三个中的两个

1.2 为什么是三选二

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
关键认知:P(分区容忍)不是可选的!

  网络一定会分区(光纤断、交换机故障、节点宕机)
  这是物理现实,无法避免
  所以 P 必须保证

  于是真正的取舍是:C 和 A 二选一
  当分区发生时:
    选 C → 拒绝服务(保证一致性,牺牲可用性)
    选 A → 继续服务(可能返回旧数据,牺牲一致性)

  所以实际是 CP 还是 AP 之争

二、CP vs AP 系统

2.1 CP 系统(强一致性)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
分区时优先保证一致性,可能拒绝服务

代表:
  Zookeeper    — 强一致(ZAB 协议),写入需要多数节点同意
  etcd         — 强一致(Raft),K8s 用它存关键配置
  HBase        — 强一致
  MongoDB      — 单主,强一致
  关系型数据库  — 主从复制时主写从读可能不一致,但单机内强一致

特点:
  ✓ 数据强一致,不会读到旧值
  ✗ 分区时部分请求失败(不可用)
  ✗ 性能/延迟通常更高(要协调多数节点)

2.2 AP 系统(高可用)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
分区时优先保证可用性,允许数据暂时不一致(最终一致)

代表:
  Cassandra   — 可调一致性,默认高可用
  DynamoDB    — 高可用
  CouchDB     — 最终一致
  Redis 集群  — 主从异步复制,故障切换可能丢少量数据(偏 AP)
  Eureka      — 服务注册,AP

特点:
  ✓ 始终可用,不拒绝请求
  ✓ 性能高、延迟低(不需协调多数)
  ✗ 可能读到旧数据(最终一致)
  ✗ 需要解决冲突(Vector Clock、最后写入获胜)
1
2
3
CA 系统(没有 P):
  单机数据库(MySQL 单机)—— 不分布式,无分区问题
  一旦分布式,P 不可选,退化成 CP 或 AP

三、BASE 理论

CAP 的 AP 取舍的实践指导:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
B — Basically Available(基本可用)
  故障时允许损失部分可用性(降级、响应慢),保证核心可用

S — Soft state(软状态)
  允许数据存在中间状态(不一致),不要求时刻强一致

E — Eventually consistent(最终一致性)
  系统保证最终数据会一致,但中间可以有窗口

  BASE = 对 AP 的工程化诠释
  大型互联网系统(电商、社交)多采用 BASE + 最终一致

四、一致性模型

一致性有强弱之分,不只是"强一致 vs 不一致"。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
强一致性(线性一致性 Linearizability)
  所有操作有全局顺序,读总能看到最新写
  最严格,实现成本最高(CP 系统)

顺序一致性(Sequential Consistency)
  所有节点看到操作顺序一致,但不一定是实时顺序
  比线性一致弱(不要求按实时顺序)

因果一致性(Causal Consistency)
  有因果关系的操作保序,无因果的可乱序

读己之所写(Read Your Writes)
  你自己写入的数据,你自己后续一定读得到

单调读(Monotonic Reads)
  不会读到比之前更旧的数据

最终一致性(Eventual Consistency)
  停止写入后,最终所有节点一致(BASE 的核心)
1
2
3
4
5
6
强 ←────────────────────────────────────→ 弱
线性一致  顺序一致  因果一致  读己写  最终一致

  越强越易用、越难实现、性能越差
  越弱越快、越可用、但需要处理不一致
  实际系统按业务选合适的级别

五、实际系统怎么选

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
场景                          推荐
──────────────────────────────────────────────────
金融账户、库存扣减             强一致(CP)— 宁可不可用也不能错
配置中心、元数据               强一致(CP)— etcd/Zookeeper
用户资料、社交动态             最终一致(AP)— 可用优先
搜索、推荐、日志               最终一致(AP)
购物车、点赞、计数             最终一致(AP)
分布式锁、选主                 强一致(CP)

  核心交易 → 强一致
  社交/内容 → 最终一致
  两者结合 → 不同模块不同策略

六、常见误解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
误解1:CAP 是"任何时候三选二"
  正解:只在「分区发生时」才二选一,平时可以既 C 又 A

误解2:AP 就是不要一致性
  正解:AP 是「最终一致」,不是不要,只是不要求时刻强一致

误解3:强一致一定比最终一致好
  正解:强一致成本高、可用性低,很多场景最终一致更合适

误解4:MySQL 是 CA(没有 P)
  正解:单机 MySQL 不涉及分区;主从/集群 MySQL 是分布式的,有分区问题

七、小结

  • CAP:一致性、可用性、分区容忍三选二;P 不可避免,实际是 CP vs AP
  • CP(Zookeeper/etcd/HBase):强一致,分区时可能不可用
  • AP(Cassandra/DynamoDB/Redis 集群):高可用,最终一致
  • BASE:基本可用 + 软状态 + 最终一致,AP 的工程实践
  • 一致性模型:从线性一致到最终一致,有多个级别,按业务选
  • 选择:核心交易强一致,社交/内容最终一致

下一篇讲共识算法 Raft——CP 系统如何达成强一致。