CAP与BASE理论详解
一、知识概述
分布式系统理论是构建大规模、高可用系统的基础。CAP 定理和 BASE 理论是分布式系统设计的两大基石,它们揭示了分布式系统中一致性、可用性、分区容错性之间的权衡关系,指导着我们在不同场景下做出正确的架构决策。
本文将深入讲解 CAP 定理和 BASE 理论的核心概念、应用场景,以及如何在实际项目中根据业务特点选择合适的一致性策略。
二、CAP 定理详解
2.1 CAP 定理定义
/**
* CAP 定理(Brewer's Theorem)
*
* 在分布式系统中,以下三个特性最多只能同时满足两个:
*
* C - Consistency(一致性)
* A - Availability(可用性)
* P - Partition Tolerance(分区容错性)
*/
public class CAPTheorem {
/**
* Consistency(一致性)
*
* 定义:所有节点在同一时刻看到的数据是一致的
*
* 含义:
* - 读操作返回最近写操作的结果
* - 所有节点数据实时同步
* - 强一致性保证
*/
public static class Consistency {
/**
* 强一致性示例
*/
public class StrongConsistencyExample {
private Map<String, String> data = new ConcurrentHashMap<>();
private List<Node> nodes; // 所有节点
/**
* 写操作 - 同步到所有节点
*/
public boolean write(String key, String value) {
// 写入所有节点
for (Node node : nodes) {
boolean success = node.write(key, value);
if (!success) {
// 任一节点失败,整体失败
return false;
}
}
return true;
}
/**
* 读操作 - 从任意节点读取
*/
public String read(String key) {
// 因为所有节点数据一致,可以从任意节点读取
return nodes.get(0).read(key);
}
}
/**
* 一致性模型层级
*/
/*
强一致性(线性一致性)
↑
顺序一致性
↑
因果一致性
↑
最终一致性
↑
弱一致性
一致性强度从上到下递减,性能从上到下递增
*/
}
/**
* Availability(可用性)
*
* 定义:每个请求都能在合理时间内得到响应(不保证是最新数据)
*
* 含义:
* - 系统持续提供服务
* - 不出现请求超时或拒绝
* - 高可用性保证(如 99.99%)
*/
public static class Availability {
/**
* 高可用示例
*/
public class HighAvailabilityExample {
private List<Node> nodes;
/**
* 读操作 - 只要有一个节点可用就返回
*/
public String read(String key) {
for (Node node : nodes) {
try {
return node.read(key); // 任意节点返回即可
} catch (Exception e) {
// 节点失败,尝试下一个
continue;
}
}
throw new ServiceException("所有节点不可用");
}
/**
* 写操作 - 只需写入成功一个节点
*/
public boolean write(String key, String value) {
for (Node node : nodes) {
try {
node.write(key, value);
return true; // 任一节点成功即可
} catch (Exception e) {
continue;
}
}
return false;
}
}
/**
* 可用性指标
*/
/*
可用性等级 可用性百分比 年停机时间
────────────────────────────────────────
2个9 99% 87.6小时
3个9 99.9% 8.76小时
4个9 99.99% 52.6分钟
5个9 99.999% 5.26分钟
6个9 99.9999% 31.5秒
*/
}
/**
* Partition Tolerance(分区容错性)
*
* 定义:系统在网络分区发生时仍能继续运行
*
* 含义:
* - 网络分区是不可避免的
* - 系统在网络故障时仍能工作
* - 分布式系统必须具备的特性
*/
public static class PartitionTolerance {
/**
* 网络分区示意图
*/
/*
正常状态:
┌─────────┐ ┌─────────┐
│ Node1 │◄───────►│ Node2 │
└─────────┘ └─────────┘
▲ ▲
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ Node3 │◄───────►│ Node4 │
└─────────┘ └─────────┘
网络分区后:
┌─────────┐ ┌─────────┐
│ Node1 │ ✕ │ Node2 │
└─────────┘ └─────────┘
▲ ▲
│ 分区边界 │
▼ ▼
┌─────────┐ ┌─────────┐
│ Node3 │ ✕ │ Node4 │
└─────────┘ └─────────┘
左侧分区 右侧分区
*/
/**
* 分区容错示例
*/
public class PartitionToleranceExample {
private List<Node> partitionA; // 分区 A
private List<Node> partitionB; // 分区 B
/**
* 处理分区场景
*/
public void handlePartition() {
// 检测到网络分区
// 方案1:选择 CP - 牺牲可用性
// 停止对外服务,直到分区恢复
// 方案2:选择 AP - 牺牲一致性
// 各分区独立服务,允许数据不一致
}
}
}
}
2.2 CAP 三选二的取舍
/**
* CAP 组合分析
*/
public class CAPCombinations {
/**
* 三种组合策略
*/
/**
* 1. CP 系统(一致性 + 分区容错性)
*
* 特点:
* - 保证数据一致性
* - 网络分区时,部分节点不可用
* - 牺牲可用性
*
* 适用场景:
* - 对数据一致性要求高
* - 可以容忍短暂不可用
*
* 典型系统:
* - ZooKeeper
* - HBase
* - Redis(Sentinel 模式)
* - MongoDB(强一致性模式)
*/
public static class CPSystem {
/**
* CP 系统实现示例
*/
public class CPImplementation {
private Map<String, String> data = new ConcurrentHashMap<>();
private List<Node> nodes;
private int quorum; // 法定节点数
public CPImplementation(int totalNodes) {
this.nodes = new ArrayList<>();
this.quorum = totalNodes / 2 + 1; // 多数派
}
/**
* 写操作 - 需要 majority 确认
*/
public boolean write(String key, String value) {
int successCount = 0;
for (Node node : nodes) {
try {
node.write(key, value);
successCount++;
} catch (Exception e) {
// 节点不可达,跳过
}
}
if (successCount >= quorum) {
return true; // 写入成功
}
// 未达到多数派,回滚
throw new UnavailableException(
"无法达到一致性,系统暂时不可用");
}
/**
* 读操作 - 需要多数派响应
*/
public String read(String key) {
Map<String, Integer> valueCount = new HashMap<>();
for (Node node : nodes) {
try {
String value = node.read(key);
valueCount.merge(value, 1, Integer::sum);
} catch (Exception e) {
// 节点不可达,跳过
}
}
// 返回多数派认可的最新值
for (Map.Entry<String, Integer> entry : valueCount.entrySet()) {
if (entry.getValue() >= quorum) {
return entry.getKey();
}
}
throw new UnavailableException(
"无法确认数据一致性,系统暂时不可用");
}
}
}
/**
* 2. AP 系统(可用性 + 分区容错性)
*
* 特点:
* - 保证系统可用性
* - 网络分区时各分区独立服务
* - 牺牲一致性(允许数据不一致)
*
* 适用场景:
* - 对可用性要求高
* - 可以容忍短暂数据不一致
*
* 典型系统:
* - Cassandra
* - DynamoDB
* - CouchDB
* - Eureka
*/
public static class APSystem {
/**
* AP 系统实现示例
*/
public class APImplementation {
private List<Node> nodes;
/**
* 写操作 - 写任意可用节点
*/
public boolean write(String key, String value) {
for (Node node : nodes) {
try {
node.write(key, value);
return true; // 任一节点成功即可
} catch (Exception e) {
continue; // 失败尝试下一个
}
}
return false;
}
/**
* 读操作 - 读任意可用节点
* 可能读到旧数据
*/
public String read(String key) {
for (Node node : nodes) {
try {
return node.read(key); // 返回第一个响应
} catch (Exception e) {
continue;
}
}
throw new ServiceException("所有节点不可用");
}
/**
* 后台同步 - 最终一致性
*/
public void backgroundSync() {
// 定期同步各节点数据
// 实现最终一致性
}
}
}
/**
* 3. CA 系统(一致性 + 可用性)
*
* 特点:
* - 保证一致性和可用性
* - 不允许网络分区
*
* 现实情况:
* - 分布式系统无法避免网络分区
* - CA 只存在于单机系统
*
* 典型系统:
* - 单机数据库(MySQL 单机)
* - 传统 RDBMS
*/
public static class CASystem {
/**
* CA 系统示例(单机)
*/
public class CAImplementation {
private Map<String, String> data = new HashMap<>();
/**
* 单机事务 - 强一致且可用
*/
@Transactional
public void write(String key, String value) {
data.put(key, value);
}
public String read(String key) {
return data.get(key);
}
// 单机系统不存在网络分区问题
// 但也无法水平扩展
}
}
}
2.3 CAP 定理的局限与误解
/**
* CAP 定理的局限与常见误解
*/
public class CAPMisconceptions {
/**
* 误解1:三选二可以任意选择
*
* 事实:在分布式系统中,P(分区容错性)是必须的
* - 网络分区是不可避免的客观事实
* - 实际上只能在 CP 和 AP 之间选择
*/
/**
* 误解2:系统只能要么 CP 要么 AP
*
* 事实:可以在不同操作上选择不同策略
* - 写操作可以选择 CP
* - 读操作可以选择 AP
* - 同一系统可以同时支持强一致性和最终一致性
*/
/**
* 误解3:CAP 定理适用于所有场景
*
* 事实:CAP 定理只关注网络分区场景
* - 不考虑节点故障
* - 不考虑延迟
* - 不考虑性能
* - 实际工程中需要考虑更多因素
*/
/**
* 正确理解 CAP
*/
public class CorrectUnderstanding {
/**
* 1. 网络分区是常态
*/
// 在分布式系统中,网络分区不可避免
// 系统必须能够处理分区情况
/**
* 2. 一致性和可用性是光谱
*/
// 不是非黑即白的二选一
// 可以在不同级别上一致性和可用性之间权衡
/**
* 3. 业务场景决定选择
*/
// 银行转账 -> CP(一致性优先)
// 社交点赞 -> AP(可用性优先)
// 订单状态 -> CP
// 商品评论 -> AP
/**
* 4. 工程实践的灵活应用
*/
public class FlexibleImplementation {
/**
* 根据业务特点选择一致性级别
*/
public enum ConsistencyLevel {
STRONG, // 强一致性
EVENTUAL, // 最终一致性
CAUSAL, // 因果一致性
SESSION // 会话一致性
}
/**
* 不同业务场景的一致性选择
*/
public void chooseConsistency(String operation) {
switch (operation) {
case "transfer": // 转账
// 强一致性,防止重复转账
break;
case "inventory": // 库存
// 强一致性,防止超卖
break;
case "like": // 点赞
// 最终一致性,允许短暂不一致
break;
case "comment": // 评论
// 最终一致性,用户可接受延迟
break;
case "feed": // 信息流
// 因果一致性,保证顺序
break;
}
}
}
}
}
三、一致性模型
3.1 一致性模型分类
/**
* 分布式系统一致性模型
*/
public class ConsistencyModels {
/**
* 一致性模型层级(从强到弱)
*/
/*
┌─────────────────────────────────────────────────────────────┐
│ 线性一致性(Linearizability) │
│ 最强的一致性保证 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 顺序一致性(Sequential Consistency) │
│ 所有进程看到相同的操作顺序 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 因果一致性(Causal Consistency) │
│ 有因果关系的操作顺序一致 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 会话一致性(Session Consistency) │
│ 同一会话内看到一致顺序 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 最终一致性(Eventual Consistency) │
│ 最终所有副本趋于一致 │
└─────────────────────────────────────────────────────────────┘
*/
/**
* 1. 线性一致性(强一致性)
*/
public static class Linearizability {
/**
* 定义:
* - 所有操作看起来在某个时间点瞬时完成
* - 操作顺序与真实时间顺序一致
* - 任何时刻所有客户端看到的数据相同
*
* 特点:
* - 最强的一致性保证
* - 性能开销最大
* - 实现复杂
*/
/**
* 线性一致性示例
*/
public void linearizabilityExample() {
/*
时间线:
Client A: W(x, 1) ────────────────────►
│
│ 线性化点
▼
Client B: R(x) ───────► 返回 1
│
Client C: R(x) ───────► 返回 1
说明:
- A 写入 x=1 后,B 和 C 的读操作都必须看到 1
- 不可能出现 B 读到 1 而 C 读到旧值的情况
*/
}
/**
* 实现方式
*/
public class LinearizableSystem {
private final Object lock = new Object();
private Map<String, String> data = new HashMap<>();
/**
* 全局锁实现线性一致性
*/
public String read(String key) {
synchronized (lock) {
return data.get(key);
}
}
public void write(String key, String value) {
synchronized (lock) {
data.put(key, value);
}
}
}
}
/**
* 2. 顺序一致性
*/
public static class SequentialConsistency {
/**
* 定义:
* - 所有进程看到相同的操作顺序
* - 不要求与实时顺序一致
* - 单个进程的操作顺序保持不变
*
* 特点:
* - 比线性一致性弱
* - 不需要全局时钟
* - 性能更好
*/
public void sequentialConsistencyExample() {
/*
时间线:
Client A: W(x, 1) ────────────────────►
Client B: W(x, 2) ──────────►
Client C: R(x) ───────► 返回 2
R(x) ───────► 返回 1
说明:
- C 先读到 2 后读到 1 是允许的
- 因为全局顺序可能是:W(x,2) -> W(x,1) 或 W(x,1) -> W(x,2)
- 只要所有客户端看到相同的顺序即可
*/
}
}
/**
* 3. 因果一致性
*/
public static class CausalConsistency {
/**
* 定义:
* - 有因果关系的操作必须按顺序被看到
* - 无因果关系的操作顺序可以不同
*
* 特点:
* - 允许一定程度的并发
* - 保证逻辑顺序
* - 常见于社交网络场景
*/
public void causalConsistencyExample() {
/*
场景:社交媒体评论
用户A发帖: "今天天气很好"
用户B回复: "确实不错"
用户C回复B: "同意"
因果关系:
A的帖子 -> B的回复 -> C的回复
要求:
- 必须先看到A的帖子才能看到B的回复
- 必须先看到B的回复才能看到C的回复
但不同用户可能看到不同顺序的无关帖子
*/
}
/**
* 向量时钟实现因果一致性
*/
public class VectorClock {
private int[] clock; // 向量时钟
public VectorClock(int nodeCount) {
this.clock = new int[nodeCount];
}
/**
* 本地事件发生,增加时钟
*/
public void increment(int nodeId) {
clock[nodeId]++;
}
/**
* 接收消息,合并时钟
*/
public void merge(int[] otherClock) {
for (int i = 0; i < clock.length; i++) {
clock[i] = Math.max(clock[i], otherClock[i]);
}
}
/**
* 判断因果关系
*/
public CausalRelation compare(int[] otherClock) {
boolean before = false;
boolean after = false;
for (int i = 0; i < clock.length; i++) {
if (clock[i] < otherClock[i]) before = true;
if (clock[i] > otherClock[i]) after = true;
}
if (before && !after) return CausalRelation.BEFORE;
if (after && !before) return CausalRelation.AFTER;
if (!before && !after) return CausalRelation.EQUAL;
return CausalRelation.CONCURRENT;
}
public enum CausalRelation {
BEFORE, // 先于
AFTER, // 后于
EQUAL, // 相等
CONCURRENT // 并发(无因果关系)
}
}
}
/**
* 4. 最终一致性
*/
public static class EventualConsistency {
/**
* 定义:
* - 如果没有新的更新,最终所有副本会达到一致
* - 不保证什么时候达到一致
* - 只保证最终会一致
*
* 特点:
* - 最弱的一致性保证
* - 性能最好
* - 实现最简单
* - 应用最广泛
*/
public void eventualConsistencyExample() {
/*
场景:DNS 缓存
1. 修改域名解析记录
2. 各地 DNS 服务器逐步更新
3. 最终所有服务器都有新记录
在此期间,不同用户可能解析到不同 IP
但最终会一致
*/
}
/**
* 实现示例
*/
public class EventualConsistentSystem {
private List<Node> nodes;
private ScheduledExecutorService scheduler;
/**
* 写入本地节点
*/
public void write(String key, String value) {
// 写入本地
nodes.get(0).write(key, value);
// 异步同步到其他节点
scheduler.submit(() -> {
for (int i = 1; i < nodes.size(); i++) {
try {
nodes.get(i).write(key, value);
} catch (Exception e) {
// 重试机制
}
}
});
}
/**
* 读取可能返回旧值
*/
public String read(String key) {
return nodes.get(0).read(key);
}
}
}
}
四、BASE 理论详解
4.1 BASE 理论定义
/**
* BASE 理论
*
* Basically Available(基本可用)
* Soft State(软状态)
* Eventually Consistent(最终一致性)
*
* BASE 是对 CAP 中 AP 系统的延伸
* 通过牺牲强一致性来获得高可用性
*/
public class BASETheory {
/**
* Basically Available(基本可用)
*
* 定义:系统在出现故障时,允许损失部分可用性
*
* 体现:
* - 响应时间损失:正常 0.5s,故障时 2s
* - 功能损失:部分功能降级
*/
public static class BasicallyAvailable {
/**
* 基本可用实现示例
*/
public class BasicAvailabilityImplementation {
/**
* 降级服务
*/
public Response handleRequest(Request request) {
try {
// 正常服务
return fullService(request);
} catch (Exception e) {
// 降级服务
return degradedService(request);
}
}
/**
* 完整服务
*/
private Response fullService(Request request) {
// 完整的业务逻辑
return new Response(true, "完整数据");
}
/**
* 降级服务
*/
private Response degradedService(Request request) {
// 返回缓存数据或默认值
return new Response(true, "缓存数据(服务降级)");
}
/**
* 限流
*/
@RateLimiter(value = 100, timeout = 1)
public Response rateLimitedRequest(Request request) {
// 限制每秒 100 个请求
// 超限请求等待或拒绝
return process(request);
}
}
/**
* 常见降级策略
*/
public class DegradationStrategies {
/**
* 1. 页面降级
*/
public String renderPage() {
try {
return renderDynamicPage();
} catch (Exception e) {
return renderStaticPage(); // 静态页面
}
}
/**
* 2. 服务降级
*/
public List<Product> getProducts() {
try {
return productService.getAll(); // 完整数据
} catch (Exception e) {
return cacheService.getProducts(); // 缓存数据
}
}
/**
* 3. 延迟降级
*/
public String getData() {
try {
return dbService.getData(); // 数据库
} catch (Exception e) {
return "数据加载中,请稍后..."; // 延迟提示
}
}
}
}
/**
* Soft State(软状态)
*
* 定义:系统中的数据状态可以存在中间状态
*
* 含义:
* - 允许数据在不同节点间存在差异
* - 中间状态不影响系统可用性
* - 数据同步存在延迟
*/
public static class SoftState {
/**
* 软状态示例
*/
public class SoftStateImplementation {
/**
* 订单状态流转
*/
public enum OrderState {
CREATED, // 已创建
PAID, // 已支付(中间状态)
CONFIRMED, // 已确认
SHIPPING, // 发货中(中间状态)
DELIVERED, // 已送达
CANCELLED // 已取消
}
/**
* 允许中间状态
*/
// PAID 状态时,库存可能还未扣减
// SHIPPING 状态时,物流信息可能还在同步
// 这些中间状态是可接受的
/**
* 数据副本同步
*/
public void syncReplicas() {
/*
主库: data = "A"
从库1: data = "A" (已同步)
从库2: data = "B" (同步中,软状态)
从库2 的软状态不影响系统运行
最终会同步到 "A"
*/
}
}
/**
* 软状态管理
*/
public class StateManagement {
private Map<String, State> states = new ConcurrentHashMap<>();
/**
* 记录状态变更
*/
public void recordState(String key, State state) {
states.put(key, state);
// 异步同步状态
asyncSyncState(key, state);
}
/**
* 异步同步状态
*/
private void asyncSyncState(String key, State state) {
// 将状态变更异步同步到其他节点
// 允许短暂的不一致
}
}
}
/**
* Eventually Consistent(最终一致性)
*
* 定义:系统中所有数据副本经过一段时间后,最终能达到一致状态
*
* 特点:
* - 不保证实时一致
* - 保证最终一致
* - 时间取决于网络延迟、系统负载等
*/
public static class EventuallyConsistent {
/**
* 最终一致性实现
*/
public class EventualConsistencyImplementation {
private List<DataReplica> replicas;
/**
* 写操作
*/
public void write(String key, String value) {
// 1. 写入主副本
replicas.get(0).write(key, value);
// 2. 异步同步到其他副本
for (int i = 1; i < replicas.size(); i++) {
asyncReplicate(replicas.get(i), key, value);
}
}
/**
* 异步复制
*/
private void asyncReplicate(DataReplica replica,
String key, String value) {
CompletableFuture.runAsync(() -> {
try {
replica.write(key, value);
} catch (Exception e) {
// 重试或记录日志
scheduleRetry(replica, key, value);
}
});
}
/**
* 读操作(可能读到旧值)
*/
public String read(String key) {
return replicas.get(0).read(key);
}
}
/**
* 最终一致性的变种
*/
public class EventualConsistencyVariants {
/**
* 1. 因果最终一致性
* - 有因果关系的操作按顺序一致
*/
/**
* 2. 读己写一致性
* - 自己写入的数据,自己立即可见
*/
public class ReadYourWrites {
private Map<String, String> localCache = new ConcurrentHashMap<>();
private DataSource dataSource;
public void write(String key, String value) {
// 写入数据源
dataSource.write(key, value);
// 写入本地缓存
localCache.put(key, value);
}
public String read(String key) {
// 先读本地缓存
String cached = localCache.get(key);
if (cached != null) {
return cached; // 保证读己写
}
return dataSource.read(key);
}
}
/**
* 3. 会话一致性
* - 同一会话内看到一致的数据
*/
public class SessionConsistency {
private String sessionId;
private Map<String, String> sessionData = new HashMap<>();
public void write(String key, String value) {
// 写入数据库
db.write(key, value);
// 记录会话版本
sessionData.put(key, value);
}
public String read(String key) {
// 会话内保证一致性
return sessionData.getOrDefault(key, db.read(key));
}
}
/**
* 4. 单调读一致性
* - 如果读到新值,后续不会读到更旧的值
*/
public class MonotonicRead {
private Map<String, Long> readVersions = new ConcurrentHashMap<>();
public String read(String key) {
// 获取已读版本
Long lastVersion = readVersions.get(key);
// 读取不早于 lastVersion 的数据
DataWithVersion data = db.readWithVersion(key, lastVersion);
// 更新已读版本
readVersions.put(key, data.getVersion());
return data.getValue();
}
}
}
}
}
4.2 BASE 与 CAP 的关系
/**
* BASE 与 CAP 的关系
*/
public class BASEAndCAPRelationship {
/**
* 关系图解
*/
/*
┌─────────────────────────────────────────────────────────────────────────┐
│ CAP 定理 │
│ │
│ ┌───────────────┐ │
│ │ C │ │
│ │ Consistency │ │
│ └───────┬───────┘ │
│ │ │
│ │ │
│ ┌────────────┼────────────┐ │
│ │ │ │ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌──────┐ │ ┌──────┐ │
│ │ CA │ │ │ CP │ │
│ │ │ │ │ │ │
│ │单机 │ │ │强一致│ │
│ └──────┘ │ └──────┘ │
│ │ │
│ │ │
│ ┌──────┴──────┐ │
│ │ │ │
│ │ P │ │
│ │ Partition │ │
│ │ Tolerance │ │
│ └──────┬──────┘ │
│ │ │
│ │ │
│ ▼ │
│ ┌──────┴──────┐ │
│ │ A │ │
│ │ Availability│ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌──────┴──────┐ │
│ │ AP │◄──── BASE 理论适用 │
│ │ │ │
│ │ 基本可用 │ │
│ │ 软状态 │ │
│ │ 最终一致性 │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
*/
/**
* BASE 是 CAP 中 AP 方案的延伸
*
* CAP 选择 AP 后:
* - 放弃强一致性
* - 保证系统可用性
*
* BASE 进一步明确:
* - 基本可用:不是完全可用,而是"基本"可用
* - 软状态:允许中间状态存在
* - 最终一致:不保证实时一致,但保证最终一致
*/
}
五、实际应用场景
5.1 业务场景选择
/**
* 不同业务场景的一致性选择
*/
public class BusinessScenarioChoices {
/**
* 1. 金融交易系统 - 选择 CP
*/
public class FinancialSystem {
/**
* 银行转账
*/
@Transactional(isolation = Isolation.SERIALIZABLE)
public void transfer(String fromAccount, String toAccount,
BigDecimal amount) {
// 强一致性,防止重复转账或资金丢失
// 1. 扣减转出账户
accountMapper.decreaseBalance(fromAccount, amount);
// 2. 增加转入账户
accountMapper.increaseBalance(toAccount, amount);
// 3. 记录交易流水
transactionMapper.insert(fromAccount, toAccount, amount);
}
/**
* 库存扣减
*/
public boolean deductStock(Long productId, Integer quantity) {
// 使用数据库行锁保证强一致性
Product product = productMapper.selectForUpdate(productId);
if (product.getStock() >= quantity) {
productMapper.decreaseStock(productId, quantity);
return true;
}
return false; // 库存不足
}
}
/**
* 2. 社交系统 - 选择 AP
*/
public class SocialSystem {
/**
* 点赞功能
*/
public void like(Long userId, Long postId) {
// 最终一致性即可
// 1. 写入本地缓存
localCache.set("like:" + userId + ":" + postId, "1");
// 2. 异步写入数据库
asyncTaskExecutor.execute(() -> {
likeMapper.insert(userId, postId);
});
// 3. 异步更新计数
asyncTaskExecutor.execute(() -> {
postMapper.increaseLikeCount(postId);
});
}
/**
* 获取点赞数(可能不准确)
*/
public Integer getLikeCount(Long postId) {
// 先读缓存,可能不准确
Integer count = localCache.get("like_count:" + postId);
if (count != null) {
return count;
}
// 缓存没有则读数据库
return postMapper.getLikeCount(postId);
}
}
/**
* 3. 电商系统 - 混合选择
*/
public class ECommerceSystem {
/**
* 商品展示 - AP
*/
public ProductDetail getProductDetail(Long productId) {
// 最终一致性
// 允许展示的商品信息略有延迟
return cacheService.getProductDetail(productId);
}
/**
* 订单创建 - CP
*/
@Transactional
public Order createOrder(OrderDTO orderDTO) {
// 强一致性
// 1. 锁定库存
boolean locked = inventoryService.lockStock(
orderDTO.getProductId(), orderDTO.getQuantity());
if (!locked) {
throw new BusinessException("库存不足");
}
// 2. 创建订单
Order order = orderMapper.insert(orderDTO);
return order;
}
/**
* 支付 - CP
*/
@Transactional
public void pay(Long orderId) {
// 强一致性,保证支付状态准确
Order order = orderMapper.selectForUpdate(orderId);
if (order.getStatus() != OrderStatus.UNPAID) {
throw new BusinessException("订单状态异常");
}
// 更新订单状态
orderMapper.updateStatus(orderId, OrderStatus.PAID);
// 扣减真实库存
inventoryService.deductStock(order.getProductId(), order.getQuantity());
}
/**
* 订单列表 - AP
*/
public List<Order> getOrderList(Long userId) {
// 最终一致性,从缓存读取
return cacheService.getOrderList(userId);
}
}
/**
* 4. 配置中心 - 选择 CP
*/
public class ConfigCenter {
/**
* 配置更新
*/
public void updateConfig(String key, String value) {
// 写入多数节点
int successCount = 0;
for (ConfigNode node : configNodes) {
try {
node.write(key, value);
successCount++;
} catch (Exception ignored) {
}
}
if (successCount < quorum) {
throw new ConfigUpdateException("配置更新失败");
}
}
/**
* 配置读取
*/
public String getConfig(String key) {
// 从多数节点读取
Map<String, Integer> valueCount = new HashMap<>();
for (ConfigNode node : configNodes) {
try {
String value = node.read(key);
valueCount.merge(value, 1, Integer::sum);
} catch (Exception ignored) {
}
}
// 返回多数派认可的值
return valueCount.entrySet().stream()
.filter(e -> e.getValue() >= quorum)
.map(Map.Entry::getKey)
.findFirst()
.orElseThrow(() -> new ConfigReadException("配置读取失败"));
}
}
}
5.2 分布式系统的权衡
/**
* 分布式系统设计权衡
*/
public class DistributedSystemTradeoffs {
/**
* 一致性 vs 可用性 vs 性能
*/
/*
┌─────────────────────────────────────────────────────────────────────────┐
│ 权衡三角形 │
│ │
│ 一致性 │
│ /│\ │
│ / │ \ │
│ / │ \ │
│ / │ \ │
│ / │ \ │
│ / │ \ │
│ / │ \ │
│ / │ \ │
│ / │ \ │
│ 性能 ◄──────────────────────────► 可用性 │
│ │
│ 只能同时满足其中两项,必须牺牲第三项 │
└─────────────────────────────────────────────────────────────────────────┘
*/
/**
* 决策框架
*/
public class DecisionFramework {
/**
* 选择一致性策略的决策树
*/
public ConsistencyStrategy chooseStrategy(BusinessRequirement req) {
// 1. 是否容忍数据丢失?
if (!req.canTolerateDataLoss()) {
// 必须强一致性
return ConsistencyStrategy.STRONG;
}
// 2. 是否容忍短暂不一致?
if (!req.canTolerateInconsistency()) {
// 选择较强的一致性
return ConsistencyStrategy.CAUSAL;
}
// 3. 对延迟的要求
if (req.getLatencyRequirement() == LatencyRequirement.LOW) {
// 低延迟要求,选择最终一致性
return ConsistencyStrategy.EVENTUAL;
}
// 4. 对可用性的要求
if (req.getAvailabilityRequirement() == AvailabilityRequirement.HIGH) {
// 高可用要求,选择最终一致性
return ConsistencyStrategy.EVENTUAL;
}
// 默认最终一致性
return ConsistencyStrategy.EVENTUAL;
}
public enum ConsistencyStrategy {
STRONG, // 强一致性
CAUSAL, // 因果一致性
SESSION, // 会话一致性
EVENTUAL // 最终一致性
}
}
}
六、总结与最佳实践
6.1 核心要点总结
┌─────────────────────────────────────────────────────────────────────────┐
│ CAP 与 BASE 核心要点 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ CAP 定理: │
│ - C(一致性):所有节点数据一致 │
│ - A(可用性):每个请求都有响应 │
│ - P(分区容错):网络分区时系统仍可用 │
│ - 在分布式系统中,P 是必须的,实际在 CP 和 AP 间选择 │
│ │
│ BASE 理论: │
│ - BA(基本可用):故障时可降级服务 │
│ - S(软状态):允许中间状态存在 │
│ - E(最终一致性):最终所有副本一致 │
│ - BASE 是 AP 方案的延伸 │
│ │
│ 选择原则: │
│ - 金融、库存、订单 → CP(强一致性) │
│ - 社交、内容、日志 → AP(最终一致性) │
│ - 混合场景 → 根据具体操作选择 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
6.2 最佳实践
-
不要盲目追求强一致性
- 评估业务是否真的需要
- 强一致性带来性能损失
-
合理使用最终一致性
- 大多数场景足够
- 配合补偿机制
-
关注用户体验
- 会话一致性
- 读己写一致性
-
做好降级预案
- 服务降级
- 数据降级
- 功能降级
六、思考与练习
思考题
-
基础题:为什么说在分布式系统中,P(分区容错性)是必须的?CA系统真的存在吗?
-
进阶题:请分析线性一致性、顺序一致性、因果一致性和最终一致性的区别,并说明它们各自的性能开销特点。
-
实战题:假设你要设计一个电商订单系统,订单创建、库存扣减、支付扣款分别应该选择什么样的一致性策略?请给出理由。
编程练习
练习:实现一个简单的AP系统示例,模拟网络分区场景下的系统行为,对比强一致性方案和最终一致性方案的用户体验差异。
章节关联
- 前置章节:无(基础理论章节)
- 后续章节:分布式ID生成详解
- 扩展阅读:《数据密集型应用系统设计》第五章、Dynamo论文
📝 下一章预告
分布式系统中,唯一ID的生成是基础且关键的问题。下一章将讲解主流的分布式ID生成方案,包括雪花算法、号段模式、Leaf方案等,帮助你在实际项目中做出正确的技术选型。
本章完
参考资料:
- "CAP Twelve Years Later" - Eric Brewer
- "BASE: An Acid Alternative" - Dan Pritchett
- 《数据密集型应用系统设计》