跳到主要内容

分布式系统知识速查表

本文档汇总分布式系统开发中常用的概念、公式、配置和最佳实践,便于快速查阅。每个知识点都附带简要说明,帮助理解核心原理。

核心理论

CAP 定理

CAP 定理由 Eric Brewer 于 2000 年提出,2002 年由 Gilbert 和 Lynch 正式证明。它描述了分布式系统在网络分区时面临的根本性权衡。

精确定义

  • 一致性(Consistency):线性一致性(Linearizability)。所有操作看起来像是在单一时间点上原子执行,每个操作都在其调用和响应之间的某个时刻生效。
  • 可用性(Availability):系统中非故障节点收到的每个请求都必须产生响应,且响应必须在有限时间内返回。
  • 分区容错性(Partition Tolerance):系统在网络发生分区(部分节点之间无法通信)的情况下,仍然能够继续运行。
重要澄清

CAP 定理说的是:当网络分区发生时,必须在 C 和 A 之间选择,而非永远只能选两个。在网络正常时,系统可以同时满足 CAP 三个属性。

组合系统类型典型系统适用场景
CP强一致性优先ZooKeeper, Etcd, HBase, Consul配置管理、分布式锁、服务发现
AP高可用优先Cassandra, DynamoDB, Riak, CouchDB社交、日志、缓存、用户画像
CA理论不存在单机数据库无网络分区的系统

PACELC 定理

PACELC 定理由 Daniel Abadi 于 2010 年提出,是对 CAP 的扩展,考虑了正常情况下的权衡。

核心洞察:即使没有网络分区,我们也需要在延迟(Latency)和一致性(Consistency)之间权衡。强一致性需要等待多数派确认,必然带来更高的延迟。

BASE 理论

BASE 理论由 eBay 架构师 Dan Pritchett 于 2008 年提出,是 CAP 中 AP 系统的具体实践指南。

术语含义实践方法
Basically Available基本可用,允许降级限流、熔断、降级、延迟服务
Soft State软状态,允许中间状态异步复制、延迟更新、本地缓存
Eventually Consistent最终一致性读修复、反熵、合并策略

FLP 不可能性

定理:在异步分布式系统中,即使只有一个节点可能故障,也不存在确定性的共识算法能同时保证安全性和活性。

实践意义

  • 使用超时机制(牺牲活性保证安全性)
  • 使用随机化算法(如 Raft 的随机选举超时)
  • 接受"最终"而非"即时"的共识

分布式时钟

Happened-Before 关系

Lamport 提出的因果关系判断规则:

ab    a \rightarrow b \iff 满足以下之一:

  1. 同一进程内,aabb 之前执行
  2. aa 发送消息,bb 接收该消息
  3. 传递性:accbaba \rightarrow c \land c \rightarrow b \Rightarrow a \rightarrow b

并发关系ab    ¬(ab)¬(ba)a \parallel b \iff \neg(a \rightarrow b) \land \neg(b \rightarrow a)

时钟类型对比

时钟类型空间复杂度能判断并发能判断因果典型应用
Lamport 时钟O(1)O(1)部分全序排列、分布式锁
向量时钟O(n)O(n)冲突检测、版本控制
HLCO(1)O(1)分布式事务、快照隔离

Lamport 时钟规则

初始化:C = 0

规则1 - 内部事件:C = C + 1
规则2 - 发送消息:C = C + 1,消息附带时间戳 C
规则3 - 接收消息:C = max(C, 接收到的C) + 1

性质:a → b ⟹ C(a) < C(b)
注意:C(a) < C(b) ⟹̸ a → b(反向不成立!)

向量时钟比较

// 比较规则
VC(a) < VC(b) ⟺ ∀i: VC(a)[i]VC(b)[i] ∧ ∃j: VC(a)[j] < VC(b)[j]
VC(a) || VC(b) ⟺ ∃i,j: VC(a)[i] < VC(b)[i]VC(a)[j] > VC(b)[j]

// 示例
VC(a) = [2, 3, 1]
VC(b) = [2, 4, 2]
// VC(a) < VC(b),因为所有分量都 ≤,且分量2和3严格小于

HLC(混合逻辑时钟)

HLC 结合物理时钟和逻辑时钟,由 Sandeep Kulkarni 等人于 2014 年提出:

HLC = (l, c)
l = 逻辑时间(接近物理时间)
c = 计数器(同一物理时间内的逻辑计数)

规则:
- 本地事件:l = max(l, pt), c = (pt > l) ? 0 : c + 1
- 接收消息:l = max(l, pt, l'), c 根据比较结果更新

优势:
- 保持因果顺序
- 接近物理时间
- 空间复杂度 O(1)

分布式事务

事务方案对比

方案一致性性能复杂度侵入性适用场景
2PC强一致金融核心、数据库跨库事务
3PC强一致极少使用
TCC最终一致电商、支付、高并发场景
Saga最终一致长流程业务编排
本地消息表最终一致内部系统集成
事务消息最终一致异步解耦、削峰填谷

2PC 协议流程

2PC 问题

问题描述解决方案
同步阻塞Prepare 阶段锁定资源,阻塞其他事务超时机制、资源预留优化
单点故障协调者故障导致所有参与者阻塞协调者高可用、日志恢复
数据不一致部分参与者提交成功,部分失败人工介入、事务补偿
脑裂问题网络分区导致多个协调者Paxos/Raft 选主

TCC 三大问题

TCC 模式需要特别注意三个核心问题,它们是正确实现 TCC 的关键:

问题描述根本原因解决方案
空回滚Try 未执行但 Cancel 执行Try 超时触发回滚Cancel 检查 Try 是否执行(查询事务日志)
悬挂Cancel 比 Try 先执行网络延迟致请求乱序Try 执行前检查是否已 Cancel
幂等性重复调用致数据错误网络重试机制唯一事务ID + 状态检查 + 乐观锁

TCC 幂等性实现模板

public boolean confirm(String xid) {
// 1. 查询事务记录
TransactionRecord record = transactionMapper.findByXid(xid);

// 2. 幂等检查:已提交或无记录,直接返回成功
if (record == null || record.isConfirmed()) {
return true;
}

// 3. 状态检查:确保 Try 已成功
if (!record.isTrySuccess()) {
throw new IllegalStateException("Try 未执行成功");
}

// 4. 执行确认逻辑(使用乐观锁)
int updated = transactionMapper.updateStatus(
xid,
TransactionStatus.CONFIRMED,
record.getVersion() // 乐观锁
);

return updated > 0;
}

Saga 模式

Saga 将长事务拆分为多个本地事务,每个事务都有对应的补偿操作:

Saga 编排方式

方式描述优点缺点
编排式中央协调器控制流程流程清晰、易于监控协调器成为瓶颈
协同式各服务通过事件驱动去中心化、扩展性好流程难追踪、复杂度高

消息队列

消息模型

模型特点消费方式适用场景
点对点一条消息只被一个消费者消费竞争消费任务分发、工作队列
发布订阅一条消息被多个消费者消费广播消费事件驱动、数据分发

主流消息队列对比

特性RabbitMQKafkaRocketMQ
吞吐量中(万级/秒)高(百万级/秒)高(十万级/秒)
延迟低(微秒级)中(毫秒级)低(毫秒级)
消息可靠性极高
事务支持支持不支持完善(事务消息)
延迟消息支持(插件)不支持原生支持
消息回溯不支持支持支持
适用场景传统业务系统大数据、日志金融、电商

RabbitMQ 交换器类型

类型路由方式示例
Direct精确匹配路由键order.created → 订单队列
Topic通配符匹配order.* → 所有订单队列
Fanout广播到所有绑定队列消息广播
Headers根据消息头匹配复杂条件过滤

Kafka 核心概念

Topic(主题):消息的逻辑分类
Partition(分区):Topic 的物理分片,分布在多个 Broker
Consumer Group(消费者组):组内消费者分摊消费分区

分区分配规则:
- 一个分区只能被组内一个消费者消费
- 一个消费者可以消费多个分区
- 消费者数量不应超过分区数

消息确认模式

模式描述可靠性性能
自动确认投递后立即确认
手动确认处理完成后确认
批量确认批量确认多条消息

服务发现

发现模式对比

特性客户端发现服务端发现
网络延迟低(直连)高(经过代理)
客户端复杂度
语言绑定
运维复杂度
故障隔离一般
扩展性受限于代理

注册中心对比

特性ConsuletcdZooKeeperNacosEureka
一致性模型CPCPCPAP/CPAP
健康检查多种方式LeaseSession多种方式心跳
多数据中心支持不支持不支持支持不支持
配置管理KV 存储原生支持不支持支持不支持
Spring Cloud 集成支持需适配需适配原生支持原生支持

负载均衡算法

算法适用场景优点缺点
轮询实例性能相近简单公平不考虑实例差异
加权轮询实例性能不同按能力分配需要配置权重
随机实例性能相近简单分布可能不均匀
最少连接请求处理时间差异大动态均衡需要维护连接数
一致性哈希有状态服务、缓存状态局部性实例变化时重新分布
区域优先多地域部署减少延迟需要区域感知

分布式缓存

缓存模式对比

模式读流程写流程一致性性能
Cache-Aside先缓存后数据库先数据库后删缓存最终一致
Read-Through缓存层封装直接写数据库最终一致
Write-Through缓存层封装缓存层同步写数据库强一致
Write-Behind缓存层封装缓存层异步写数据库弱一致最高

缓存三大问题

问题描述解决方案
缓存穿透查询不存在的数据,请求穿透到数据库空值缓存、布隆过滤器
缓存击穿热点 key 过期瞬间,大量请求同时查询数据库互斥锁、热点数据永不过期
缓存雪崩大量 key 同时过期或缓存服务宕机随机过期时间、熔断降级、高可用部署

一致性策略

策略流程问题
先删缓存,再更新数据库删缓存 → 更新数据库并发时可能将旧数据写入缓存
先更新数据库,再删缓存更新数据库 → 删缓存推荐,删除失败可重试
延迟双删删缓存 → 更新数据库 → 延迟删缓存处理并发问题

Redis 数据结构

结构特点典型应用
String最基本类型,支持数值操作缓存、计数器、分布式锁
Hash字段-值映射,适合对象用户信息、商品详情
List有序可重复列表消息队列、最新列表
Set无序不重复集合标签、关注关系、共同好友
Sorted Set有序不重复集合,带分数排行榜、带权集合

Redis 持久化

方式原理优点缺点
RDB定期快照恢复快、文件紧凑可能丢失数据、fork 阻塞
AOF记录写操作命令数据安全、可读文件大、恢复慢
混合RDB + AOF 增量兼顾两者优点需 Redis 4.0+

Redis 集群方案

方案架构特点
主从复制一主多从简单、读写分离、手动故障转移
SentinelSentinel 监控 + 主从自动故障转移、高可用
Cluster多主多从 + 分片数据分片、自动故障转移、可扩展

共识算法

算法对比

算法作者特点消息复杂度容错模型典型系统
PaxosLamport理论基础,难理解O(n)O(n)崩溃容错Chubby, Spanner
RaftOngaro易理解,有 LeaderO(n)O(n)崩溃容错Etcd, Consul, TiKV
ZABYahooZooKeeper 专用O(n)O(n)崩溃容错ZooKeeper
PBFTCastro拜占庭容错O(n2)O(n^2)拜占庭容错Hyperledger

Raft 核心概念

Raft 由 Diego Ongaro 和 John Ousterhout 于 2014 年提出,将共识问题分解为三个子问题:

核心机制

机制描述关键参数
Leader 选举超时触发选举,多数派投票获胜electionTimeout: 150-300ms
日志复制Leader 追加日志,复制到 FollowerheartbeatInterval: 50ms
安全性日志匹配、Leader 完整性保证commitIndex, lastApplied

选举超时计算

electionTimeout=baseTimeout+random(0,maxRandom)\text{electionTimeout} = \text{baseTimeout} + \text{random}(0, \text{maxRandom})

典型配置:baseTimeout = 150ms, maxRandom = 150ms,总超时范围 150-300ms。

日志复制流程

ZAB 协议

ZAB(ZooKeeper Atomic Broadcast)是 ZooKeeper 专用协议:

ZAB 四阶段

阶段说明
发现(Discovery)Follower 提交最新事务,Leader 汇总
同步(Synchronization)Leader 将新事务同步给 Follower
广播(Broadcast)Leader 广播客户端请求
恢复(Recovery)Leader 故障后的恢复流程

Paxos 核心不变量

Paxos 由 Leslie Lamport 提出,其正确性依赖于以下不变量:

P2c(核心不变量):对于任意值 v 和提案编号 n,如果编号为 n、值为 v 的提案被发出,则存在一个多数派集合 S 满足:

  • 条件(a):S 中没有 Acceptor 接受过编号小于 n 的提案;或
  • 条件(b):v 是 S 中编号小于 n 的最大提案的值

这个不变量保证了:一旦某个值被选定,所有更高编号的提案必须使用相同的值。

数据分区

分区策略对比

策略算法优点缺点适用场景
哈希分区hash(key) % N数据分布均匀无法范围查询、扩容迁移量大KV 存储、用户数据
范围分区key ∈ [start, end)支持范围查询可能数据倾斜时序数据、日志
一致性哈希环形空间定位扩容迁移量小实现复杂缓存、分布式存储
虚拟槽槽位映射节点均匀 + 灵活需要维护映射表Redis Cluster

一致性哈希

虚拟节点解决数据倾斜

物理节点 → 虚拟节点 (150-200 个/节点)
虚拟节点 → 哈希环位置

查找过程:
1. 计算 key 的 hash
2. 顺时针找到第一个虚拟节点
3. 返回虚拟节点对应的物理节点

虚拟节点数量经验值

vnodes=max(150,totalKeys10000)\text{vnodes} = \max(150, \frac{\text{totalKeys}}{10000})

分库分表数量估算

分库数量:
库数量 = ⌈并发量 / 单库并发上限⌉

分表数量:
表数量 = ⌈数据总量 / 单表数据上限⌉

经验值(MySQL):
单表建议 < 1000 万行
单库建议 < 1TB 数据
单库并发建议 < 10000 QPS

数据复制

复制模式对比

模式流程延迟数据安全吞吐量适用场景
同步复制写主→等所有从→返回最高金融核心、关键配置
异步复制写主→返回→异步写从可能丢失日志、非关键数据
半同步复制写主→等至少一个从→返回较高通用业务数据

Quorum 机制

Quorum 机制通过读写节点数的约束来保证一致性:

强一致性条件:W+R>N\text{强一致性条件:} W + R > N

其中 WW 为写入成功的节点数,RR 为读取成功的节点数,NN 为总副本数。

常用配置

配置WR特点适用场景
写优先N1写慢读快读多写少
读优先1N写快读慢写多读少
平衡N/2+1\lceil N/2 \rceil + 1N/2+1\lceil N/2 \rceil + 1平衡通用场景

一致性模型谱系

模型描述典型系统
线性一致性所有操作看起来在单一时间点原子执行ZooKeeper, Etcd, Spanner
顺序一致性所有进程看到相同的操作顺序(但不一定是实时)MySQL 主从复制
因果一致性有因果关系的操作顺序一致,无因果可乱序Cassandra, DynamoDB
最终一致性最终收敛到一致状态DNS, CDN, Riak

分布式ID

方案对比

方案长度有序趋势递增依赖QPS适用场景
UUID36字符极高临时标识、追踪ID
雪花算法18位数字时钟订单号、消息ID
号段模式可变数据库业务系统
Redis INCR可变Redis分布式序列

雪花算法结构

64 位 = 1 位符号 + 41 位时间戳 + 10 位机器ID + 12 位序列号

┌───────┬─────────────────────┬────────────┬────────────┐
│ 1 bit │ 41 bits │ 10 bits │ 12 bits │
│ 符号位 │ 时间戳(ms) │ 机器ID │ 序列号 │
│ │ (约 69 年) │ (1024 节点) │ (4096/ms) │
└───────┴─────────────────────┴────────────┴────────────┘

ID = ((timestamp - epoch) << 22) | (workerId << 12) | sequence

时间回拨处理

public synchronized long nextId() {
long currentTime = System.currentTimeMillis();

if (currentTime < lastTimestamp) {
long offset = lastTimestamp - currentTime;

if (offset <= 5) {
// 小回拨:等待时间追上
Thread.sleep(offset);
currentTime = System.currentTimeMillis();
} else {
// 大回拨:报错或使用备用 workerId
throw new ClockBackwardException(offset);
}
}

// 正常生成逻辑...
}

分布式锁

实现方案对比

特性Redis SETNXRedis RedlockZooKeeperetcd
性能极高
可靠性
实现复杂度
公平性不支持不支持支持支持
可重入需实现需实现原生支持需实现
Watch 机制

Redis 锁命令

# 获取锁(原子操作)
SET lock:resource unique_value NX PX 30000

# 参数说明:
# NX - 只在键不存在时设置(Not eXists)
# PX 30000 - 过期时间 30 秒
# unique_value - 唯一标识,防止误解锁

# 释放锁(Lua 脚本保证原子性)
EVAL "
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
" 1 lock:resource unique_value

Redlock 算法

Redlock 由 Redis 作者 Antirez 提出,使用多个独立 Redis 节点提高可靠性:

算法步骤(N=5)

  1. 记录开始时间 t1t_1
  2. 依次向 N 个节点请求加锁(使用相同 key 和 value)
  3. 计算获取锁耗时 t2t1t_2 - t_1
  4. 成功条件:多数派成功 且 耗时 < 锁过期时间
  5. 锁有效时间 = 过期时间 - 获取耗时

ZooKeeper 锁实现

// 使用 Curator 框架
InterProcessMutex lock = new InterProcessMutex(client, "/lock/resource");

try {
// 获取锁(阻塞,带超时)
if (lock.acquire(30, TimeUnit.SECONDS)) {
try {
// 执行业务逻辑
doBusiness();
} finally {
lock.release();
}
}
} catch (Exception e) {
// 处理异常
}

ZooKeeper 锁原理

  1. 创建临时顺序节点 /lock/resource-00001
  2. 检查是否是最小节点
  3. 是最小节点 → 获取锁成功
  4. 不是最小节点 → 监听前一个节点的删除事件
  5. 前一个节点删除 → 被唤醒,再次检查

可观测性

三大支柱对比

维度日志(Logs)指标(Metrics)追踪(Traces)
数据类型文本/结构化数值时间序列有向无环图(DAG)
粒度单个事件聚合统计请求级别
存储成本
查询灵活性
主要用途问题诊断趋势监控、告警调用链分析

分布式追踪核心概念

Trace  = 完整请求链路,由多个 Span 组成
Span = 单个工作单元,记录操作和时间
TraceID = 全局唯一标识,贯穿整个链路
SpanID = 单个 Span 的唯一标识
ParentSpanID = 父 Span 标识,构建调用树

上下文传播(Context Propagation):
W3C 标准:traceparent, tracestate
格式:traceparent: 00-{trace-id}-{parent-id}-{trace-flags}

指标类型

类型特点适用场景示例
Counter只增不减计算速率、累计值请求总数、错误总数
Gauge可增可减当前状态内存使用、队列长度、温度
Histogram分布统计百分位数响应时间分布、请求大小分布
Summary流式分位数高精度分位数延迟 SLA 监控

RED 和 USE 方法

RED 方法(针对服务):

R - Rate(速率):每秒请求数,反映系统负载
E - Errors(错误):每秒错误数,反映系统健康
D - Duration(耗时):响应时间分布,反映用户体验

USE 方法(针对资源):

U - Utilization(利用率):资源使用百分比
S - Saturation(饱和度):排队等待程度
E - Errors(错误):操作错误率

适用对象:CPU、内存、磁盘、网络等资源

常用组件端口

组件默认端口用途
ZooKeeper2181客户端连接
ZooKeeper2888Follower 连接 Leader
ZooKeeper3888Leader 选举
Etcd2379客户端 API
Etcd2380节点间通信
Redis6379客户端连接
Redis Sentinel26379哨兵端口
Kafka9092Broker 端口
Consul8500HTTP API
Consul8600DNS 接口
Seata8091Server 端口
Prometheus9090Web UI/API
Grafana3000可视化界面
Jaeger16686Web UI
Jaeger14268HTTP 收集
OpenTelemetry4317/4318OTLP 接收

关键公式

可用性计算

可用性=MTBFMTBF+MTTR\text{可用性} = \frac{\text{MTBF}}{\text{MTBF} + \text{MTTR}}
  • MTBF(Mean Time Between Failures):平均故障间隔时间
  • MTTR(Mean Time To Recovery):平均修复时间

"N 个九"含义

可用性年停机时间适用场景
99%3.65 天内部工具
99.9%8.76 小时一般业务
99.99%52.6 分钟电商、支付
99.999%5.26 分钟金融核心

N 个节点的系统可用性

系统可用性=1(1p)n\text{系统可用性} = 1 - (1 - p)^n
  • pp:单节点可用性
  • nn:节点数量

分区容量估算

分片数=总数据量单表上限\text{分片数} = \lceil\frac{\text{总数据量}}{\text{单表上限}}\rceil

Google Spanner 与 TrueTime

Google Spanner 通过 TrueTime API 实现了全球分布数据的强一致性事务。

TrueTime API

TT.now()      返回 TTinterval{earliest, latest}
真实时间一定在此区间内

TT.after(t) = TT.now().earliest > t
TT.before(t) = TT.now().latest < t

时间不确定性:通常 1-7ms,来源:

  • 本地时钟漂移
  • 时间参考服务器不确定性
  • 通信延迟

外部一致性

Spanner 通过以下机制实现外部一致性:

  1. 时间戳分配s>TT.now().latests > \text{TT.now().latest}
  2. 提交等待:直到 TT.after(s)\text{TT.after}(s) 为 true

这保证了:如果事务 T1 提交在 T2 开始之前(物理时间),则 T1 的时间戳 < T2 的时间戳。

常见问题排查

问题可能原因排查方法解决方案
数据不一致网络延迟/分区检查网络延迟、复制状态增加重试、强一致性读
分布式事务超时网络问题/负载高检查超时日志、资源使用增加超时、降级处理
死锁锁顺序不一致分析锁获取日志统一加锁顺序、超时释放
脑裂网络分区检查节点通信状态多数派投票、fencing token
时钟回拨NTP 同步问题检查系统时间、NTP 状态关闭 NTP/使用容忍方案
热点数据分片不均匀分析数据分布、访问模式调整分片键、热点隔离
雪花算法 ID 重复时钟回拨/机器 ID 冲突检查时钟、机器 ID 配置时钟监控、ZK 分配 ID

学习资源

经典论文

论文作者核心贡献
CAP TheoremGilbert & LynchCAP 定理的正式证明
Paxos Made SimpleLeslie LamportPaxos 算法的简化解释
In Search of an Understandable Consensus AlgorithmOngaro & OusterhoutRaft 算法
Spanner: Google's Globally-Distributed DatabaseGoogleTrueTime 和外部一致性
Dynamo: Amazon's Highly Available Key-value StoreAmazon最终一致性的工业实践

推荐书籍

  • 《Designing Data-Intensive Applications》by Martin Kleppmann
  • 《分布式系统:原理与范型》by Tanenbaum & van Steen
  • 《数据密集型应用系统设计》(中文版)

开源项目

项目用途GitHub
Etcd分布式键值存储github.com/etcd-io/etcd
Consul服务发现与配置github.com/hashicorp/consul
Seata分布式事务框架github.com/seata/seata
ShardingSphere分库分表中间件github.com/apache/shardingsphere
Redis分布式缓存与锁github.com/redis/redis
OpenTelemetry可观测性标准github.com/open-telemetry
Jaeger分布式追踪github.com/jaegertracing/jaeger
Prometheus监控告警github.com/prometheus/prometheus