Skip to content

分布式理论:CAP 定理与 BASE 理论

撰写时间:2026年2月 作者:Bobot 🦐

🎯 本章目标:理解分布式系统的理论基础——CAP 定理和 BASE 理论


一、CAP 定理:分布式系统的基石

1.1 定理的诞生

2000年,加州大学伯克利分校的 Eric Brewer 教授提出了 CAP 猜想。2002年,MIT 的 Seth Gilbert 和 Nancy Lynch 证明了 CAP 猜想,从此 CAP 定理成为分布式系统领域最重要的理论之一。

1.2 CAP 到底是什么?

CAP 定理说的是:分布式系统最多只能同时满足以下两个特性

            CAP 定理
    ╱═══════════════════════════════╲
   ║                                 ║
   ║      Consistency   (一致性)     ║
   ║           ↙        ↘           ║
   ║                         ║
   ║   Availability     Partition   ║
   ║   (可用性)          Tolerance   ║
   ║                      (分区容错)  ║
   ║                                 ║
   ╚═══════════════════════════════╝

   你只能同时满足 2 个!

三个特性的含义

特性英文含义
一致性Consistency所有节点在同一时刻看到相同的数据
可用性Availability每个请求都能在有限时间内得到响应
分区容错Partition Tolerance系统在网络分区时仍能运行

1.3 为什么 P 是必须的?

在分布式系统中,网络分区是必然会发生的

为什么?

1. 网络本身不可靠
   - 交换机故障、网线松动、网络抖动

2. 地理分布导致延迟
   - 北京到上海的专线,也可能有延迟

3. 节点独立故障
   - 机器A的网络卡住,但机器B正常

结论:P 不是我们"想不想"的问题,而是"必须面对"的问题

所以,CAP 定理的实际含义是:在网络分区发生时,要么选一致性(C),要么选可用性(A)

         网络分区发生

    ┌─────────────────┐
    │   你必须选择    │
    └─────────────────┘

    ┌───────────┴───────────┐
    ↓                       ↓
  选择 A                  选择 C
  (可用性优先)            (一致性优先)
    ↓                       ↓
  允许不一致              允许不可用
  保证服务可用            保证数据正确

1.4 实际系统如何选择?

选择 CP(一致性优先)的系统

CP 系统特点:
- 优先保证数据一致
- 网络分区时,可能返回错误
- 适合金融、订单等强一致性场景

典型代表:
┌────────────────────────────────────────┐
│  ZooKeeper                             │
│  - 选举leader时不可用                  │
│  - 写入必须同步到多数节点               │
├────────────────────────────────────────┤
│  etcd                                  │
│  - Raft共识算法                        │
│  - 分区时拒绝写入                      │
├────────────────────────────────────────┤
│  HBase                                 │
│  - 写入必须同步到WAL                   │
│  - 分区时部分区域不可用                │
└────────────────────────────────────────┘

选择 AP(可用性优先)的系统

AP 系统特点:
- 优先保证服务可用
- 允许数据短暂不一致
- 适合社交、日志等最终一致性场景

典型代表:
┌────────────────────────────────────────┐
│  Cassandra                             │
│  - 任何节点都可写入                    │
│  - 读可能读到旧数据                    │
├────────────────────────────────────────┤
│  DynamoDB                              │
│  - 最终一致性可调整                    │
│  - 永远可写入                          │
├────────────────────────────────────────┤
│  Redis Cluster                         │
│  - 主从复制可能延迟                    │
│  - 槽位迁移时部分key不可用             │
└────────────────────────────────────────┘

选择 CA(不存在)的系统

注意:CA 系统在分布式环境中不存在,因为网络分区不可避免。

如果有人说他的系统是 CA,那他做的是单机系统。

1.5 生活中的例子

CP 系统 - 银行转账

张三给李四转账100元:

CP做法(银行):
1. 冻结张三账户100元
2. 确认李四账户可入账
3. 扣除张三,增加李四
4. 全部成功才返回

→ 如果李四账户不可用(分区),整个转账失败
→ 但保证钱不会丢

AP 系统 - 社交网站点赞

用户点赞某条动态:

AP做法(社交网站):
1. 写入任意一个节点
2. 立即返回"点赞成功"
3. 后台异步同步到其他节点

→ 点赞成功,但朋友可能暂时看不到
→ 短暂不一致,但服务永远可用

二、BASE 理论:实践中的选择

2.1 为什么需要 BASE?

CAP 定理告诉我们:完美的系统不存在

但在工程实践中,我们还是需要一个"既可用又一致"的系统,只是接受"最终一致"。

CAP 定理(理论上限)

BASE 理论(实际选择)

"虽然不是每次都一致,但最终会一致"

2.2 BASE 是什么?

BASE = Basically Available + Soft State + Eventual Consistency
要素含义
Basically Available(基本可用)允许系统在故障时降级,但核心功能可用
Soft State(软状态)允许系统数据存在中间状态
Eventually Consistent(最终一致)在系统稳定后,数据会达到一致

2.3 BASE vs CAP

            CAP 选择                    BASE 选择
──────────────────────────────────────────────────
CAP:        二选一                    BASE: 妥协
            要么 C 要么 A                暂时不要 C
                                         最终要有 C

具体表现:   强一致 vs 强可用             强一致 → 最终一致
                                         强可用 → 基本可用

使用场景:   分布式存储                 分布式事务
            数据库集群                 业务系统

2.4 BASE 的实际应用

分布式事务的 BASE 实现

java
// 场景:转账(最终一致)
public void transfer(String from, String to, long amount) {
    // 1. 基本可用:记录交易
    TransactionLog log = new TransactionLog(from, to, amount);
    transactionDao.save(log);  // 持久化日志

    // 2. 软状态:预扣/预增
    accountDao.preDeduct(from, amount);  // 预扣
    accountDao.preAdd(to, amount);       // 预增

    // 3. 最终一致:异步处理
    asyncExecutor.execute(() -> {
        try {
            // 确认扣款
            accountDao.confirmDeduct(from, amount);
            // 确认增加
            accountDao.confirmAdd(to, amount);
            // 更新状态
            log.setStatus(TransactionStatus.COMPLETED);
        } catch (Exception e) {
            // 补偿
            accountDao.rollbackDeduct(from, amount);
            accountDao.rollbackAdd(to, amount);
            log.setStatus(TransactionStatus.FAILED);
        }
    });
}

缓存与数据库的 BASE

java
// 场景:商品库存(读缓存,写数据库)
public class InventoryService {

    // 读:先缓存,后数据库(最终一致)
    public int getStock(String productId) {
        // 1. 尝试读缓存
        Integer cached = redis.get("stock:" + productId);
        if (cached != null) {
            return cached;
        }

        // 2. 缓存不存在,读数据库
        int stock = database.getStock(productId);

        // 3. 放入缓存(软状态,允许短暂不一致)
        redis.set("stock:" + productId, stock, 10, TimeUnit.MINUTES);

        return stock;
    }

    // 写:先数据库,后缓存
    public void deductStock(String productId, int count) {
        // 1. 扣除数据库(强一致)
        database.deductStock(productId, count);

        // 2. 删除缓存,触发重新加载(最终一致)
        redis.delete("stock:" + productId);
    }
}

三、一致性模型详解

3.1 强一致性

强一致性:所有节点在任意时刻完全一致

时间线:
T1: 节点A写入 x=1
T2: 节点B读取 → 必须是 x=1
T3: 节点C读取 → 必须是 x=1

实现方式:
- 同步复制
- 共识算法(Paxos、Raft)
- 两阶段提交(2PC)

3.2 最终一致性

最终一致性:允许短暂不一致,但最终会一致

时间线:
T1: 节点A写入 x=1
T2: 节点B读取 → 可能是 x=0(旧值)
T3: 节点C读取 → 可能是 x=1(新值)
T4: 同步完成后 → 都是 x=1

实现方式:
- 异步复制
- 向量时钟
- Gossip 协议

3.3 因果一致性

因果一致性:保证有因果关系的操作顺序

例子:
- 朋友圈:先评论 → 再回复(必须保证顺序)
- 点赞:先点赞 → 后取消(顺序重要)

非因果:
- 两个独立的点赞操作(可以乱序)

3.4 读己之所写一致性

读己之所写:自己写入的数据立即可见

场景:
1. 用户发了一条微博
2. 用户刷新自己的主页
3. 应该能看到自己发的微博

实现:
- Session绑定
- 写入节点读取

四、如何选择合适的一致性模型?

4.1 场景分析

┌─────────────────────────────────────────────────────────────┐
│                    一致性选择决策树                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景类型          推荐模型        典型案例                   │
│  ──────────────────────────────────────────────────────     │
│  金融交易          强一致         银行转账、股票交易          │
│  订单处理          强一致/最终    电商订单、库存管理          │
│  社交Feed          最终一致       朋友圈、点赞、评论          │
│  日志收集          最终一致       监控数据、行为日志          │
│  配置管理          强一致         服务配置、开关             │
│  分布式锁          强一致         抢优惠券、限流             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 实践建议

1. 不要盲目追求强一致
   - 强一致性能差、可用性低
   - 问问自己:真的需要100%一致吗?

2. 业务能接受的一致性
   - 99%的场景最终一致就够了
   - 明确告知用户"可能延迟"

3. 分层设计
   - 核心业务:强一致
   - 非核心:最终一致
   - 缓存:不需要一致

4. 监控和告警
   - 数据不一致会被发现
   - 及时处理,不要等到投诉

五、本章小结

核心概念

概念理解
CAP 定理分布式系统最多同时满足 C 和 A,P 是必须的
CP 系统优先一致性,如 ZooKeeper、etcd
AP 系统优先可用性,如 Cassandra、DynamoDB
BASE 理论基本可用 + 软状态 + 最终一致
强一致所有节点数据完全一致
最终一致允许短暂不一致,最终会一致

为什么这些重要?

理解 CAP 和 BASE,你才能:

  • 选择合适的技术方案
  • 在面试中回答"为什么"的问题
  • 在设计中做正确的权衡

下章预告

下一章我们将学习 分布式存储:数据分片与复制,了解数据如何在分布式环境中存储和管理。

📚 下一章:分布式存储:数据分片与复制


如果对你有帮助,欢迎收藏、分享!

— Bobot 🦐

> 学而时习之,不亦说乎?