---
URL: "/zh-CN/blog/2026-01/cap.html"
LLMS_URL: "/zh-CN/blog/2026-01/cap.md"
lastUpdated: true
commentabled: true
recommended: true
title: "用 4 张图解释 CAP 到底在纠结什么"
description: "用 4 张图解释 CAP 到底在纠结什么"
date:

pageClass: "blog-page-class"
cover: "/covers/mysql.svg"
---

---
lastUpdated: true
commentabled: true
recommended: true
title: 用 4 张图解释 CAP 到底在纠结什么
description: 用 4 张图解释 CAP 到底在纠结什么
date: 2026-01-29 09:00:00
pageClass: blog-page-class
cover: /covers/mysql.svg
---

![系统分析师-CAP理论](/images/cap-20260129132842.png)

项目前几天线上又出了个事故，MySQL主从延迟导致用户看到了脏数据，开事故复盘会时老板又提起了那个老生常谈的问题："为什么不能做到既高可用又强一致？"

这让我想起刚入行时对CAP定理的困惑。当时只知道是个"三选二"的定理，但为什么要选？到底在纠结什么？直到在实际项目中踩过坑，才算真正理解。

今天就用几张图，聊聊CAP定理到底在纠结什么。

## 图1：理想世界 - 三者兼得的美好愿景 ##

```txt
┌─────────────────────────────────────────────────────────────┐
│                     理想的分布式系统                         │
│                                                             │
│    节点A ←─────────── 同步复制 ────────→ 节点B               │
│      │                                      │               │
│      │            ┌─────────────┐           │               │
│      └───────────→│  一致性保证  │←──────────┘               │
│                   └─────────────┘                           │
│                                                             │
│    ✓ 强一致性：所有节点数据完全同步                            │
│    ✓ 高可用性：任何时候都能响应请求                            │
│    ✓ 分区容错：网络故障不影响系统运行                          │
└─────────────────────────────────────────────────────────────┘
```

在理想情况下，我们希望分布式系统能够同时满足三个特性：

- **一致性**：所有节点在同一时间具有相同的数据副本
- **可用性**：系统始终保持可操作状态，能够在合理时间内响应请求
- **分区容错性**：系统能够容忍网络分区故障

但这个理想状态在实际情况下并不存在，网络分区就像墨菲定律一样——该发生的迟早会发生。

## 图2：现实困境 - 网络分区的必然性 ##

```txt
┌─────────────────────────────────────────────────────────────┐
│                   网络分区发生时                              │
│                                                             │
│    节点A                    ✗               节点B            │
│   [数据v1] ←─────── 网络中断 ──────→ [数据v1]               │
│      ↑                                      ↑               │
│      │                                      │               │
│   客户端1                                 客户端2            │
│  请求更新                                 请求更新            │
│   v1→v2                                   v1→v3              │
│                                                             │
│   面临选择：                                                  │
│   1. 拒绝服务（保证一致性，牺牲可用性）                         │
│   2. 继续服务（保证可用性，牺牲一致性）                         │
└─────────────────────────────────────────────────────────────┘
```

网络分区一发生，架构师就得做选择了。这个选择很残酷，因为无论怎么选都有代价：

**选择一致性（CP）**：

- 检测到网络分区后，停止写操作或返回错误
- 确保数据不会出现不一致状态
- 代价是系统暂时不可用

**选择可用性（AP）**：

- 继续处理读写请求，即使可能导致数据不一致
- 保证系统持续提供服务
- 代价是可能出现数据冲突

这背后其实是业务逻辑在较劲，而不是技术问题。

你是宁可让用户等会儿，也不能让数据乱？还是宁可数据暂时不准，也不能让服务停？

## 图3：CP系统 - 宁可停服，不可错乱 ##

```txt
┌─────────────────────────────────────────────────────────────┐
│                    CP系统的选择                              │
│                                                             │
│    节点A                    ✗               节点B            │
│   [数据v1] ←─────── 网络中断 ──────→ [数据v1]               │
│      ↑                                      ↑               │
│      │                                      │               │
│   客户端1                                 客户端2            │
│     │                                       │               │
│     ▼                                       ▼               │
│  ❌ 503错误                              ❌ 503错误          │
│  "服务暂不可用"                          "服务暂不可用"        │
│                                                             │
│  特点：                                                      │
│  • 强一致性保证                                              │
│  • 网络分区时部分不可用                                        │
│  • 适用场景：金融交易、库存管理                                │
└─────────────────────────────────────────────────────────────┘
```

CP系统就是那种"要么不干，要干就干对"的性格：

**MySQL主从架构**：

- 主库挂了，从库不敢接管写操作
- 数据绝对不会乱，但写服务就得等

**Zookeeper**：

- 超半数节点联系不上？直接罢工
- 配置中心的数据必须准确，哪怕暂停服务

**HBase**：

- Region在搬家时，相关的读写都得暂停
- 确保数据强一致，用户体验靠边站

这种策略特别适合金融、电商库存这些"错一分钱都要命"的场景。毕竟用户等几秒钟总比账算错了强。

## 图4：AP系统 - 宁可不准，不可不通 ##

```txt
┌─────────────────────────────────────────────────────────────┐
│                    AP系统的选择                              │
│                                                             │
│    节点A                    ✗               节点B           │
│   [数据v2] ←─────── 网络中断 ──────→ [数据v3]                │
│      ↑                                      ↑               │
│      │                                      │               │
│   客户端1                                 客户端2            │
│     │                                       │               │
│     ▼                                       ▼               │
│  ✅ 200 OK                               ✅ 200 OK         │
│  "更新成功"                               "更新成功"         │
│                                                             │
│  后续处理：                                                  │
│  • 网络恢复后进行数据同步                                     │
│  • 通过冲突解决机制处理不一致                                 │
│  • 最终一致性保证                                            │
└─────────────────────────────────────────────────────────────┘
```

AP系统的理念正好相反，"服务先跑起来，数据慢慢同步"：

**DNS**：

- 各地DNS服务器都能独立工作
- 新域名解析可能有延迟，但不影响上网
- 最终大家都会知道正确答案

**DynamoDB**：

- 网络分区？照样读写不误
- 用向量时钟等技术处理冲突
- 保证最终所有副本一致

**微博、朋友圈**：

- 你发的动态可能几分钟后别人才看到
- 点赞评论立即响应，后台慢慢同步
- 用户体验比数据实时性更重要

## 一些思考 ##

从理论到实践，CAP教会我们的不只是技术选择，更是对业务本质的理解：

### 先搞清楚业务要什么 ###

不是所有业务都需要强一致性：

- **钱的事儿不能错**：支付、库存、订单
- **用户体验更重要**：动态推送、评论点赞、搜索结果

### 分层设计，各取所需 ###

一个系统里不同数据可以有不同策略：

- **核心数据强一致**：用户余额、库存数量
- **辅助数据最终一致**：访问统计、日志数据

### P不是选择，而是必须面对的现实 ###

分布式环境下，网络分区就像感冒一样，你预防不了，只能准备好应对方案。

所以真正的选择其实是在C和A之间做权衡。

## 实战中的一些套路 ##

### 常见架构模式 ###

- **主从模式**：一个老大说了算，老大挂了大家都歇菜（CP向）
- **多主模式**：几个老大各管一摊，偶尔打架后再协商（AP向）
- **投票机制**：过半数同意才算数，少数服从多数（可配置CP/AP）

### 化解矛盾的小技巧 ###

- **数据分片**：把鸡蛋放在不同篮子里，一个篮子坏了不影响全局
- **读写分离**：读可以宽松一点（AP），写必须严格一点（CP）
- **事后补偿**：先让业务跑起来，发现问题后再想办法修复

## 写在最后 ##

CAP的纠结本质上不是技术问题，而是业务问题。就像你不可能同时要求一个人既要马儿跑，又要马儿不吃草一样。

**关键是要想清楚**：

- 你的业务最怕什么？是怕数据错乱，还是怕服务中断？
- 不同的数据是否可以有不同的策略？
- 能否在正常和异常情况下采用不同的处理方式？

技术选择没有标准答案，只有最适合当前业务场景的方案。这就是架构师的价值所在——在各种约束条件下找到最优解。
