分布式系统知识速查表
本文档汇总分布式系统开发中常用的概念、公式、配置和最佳实践,便于快速查阅。每个知识点都附带简要说明,帮助理解核心原理。
核心理论
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 提出的因果关系判断规则:
满足以下之一:
- 同一进程内, 在 之前执行
- 发送消息, 接收该消息
- 传递性:
并发关系:
时钟类型对比
| 时钟类型 | 空间复杂度 | 能判断并发 | 能判断因果 | 典型应用 |
|---|---|---|---|---|
| Lamport 时钟 | 否 | 部分 | 全序排列、分布式锁 | |
| 向量时钟 | 是 | 是 | 冲突检测、版本控制 | |
| HLC | 否 | 是 | 分布式事务、快照隔离 |
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 编排方式:
| 方式 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 编排式 | 中央协调器控制流程 | 流程清晰、易于监控 | 协调器成为瓶颈 |
| 协同式 | 各服务通过事件驱动 | 去中心化、扩展性好 | 流程难追踪、复杂度高 |
消息队列
消息模型
| 模型 | 特点 | 消费方式 | 适用场景 |
|---|---|---|---|
| 点对点 | 一条消息只被一个消费者消费 | 竞争消费 | 任务分发、工作队列 |
| 发布订阅 | 一条消息被多个消费者消费 | 广播消费 | 事件驱动、数据分发 |
主流消息队列对比
| 特性 | RabbitMQ | Kafka | RocketMQ |
|---|---|---|---|
| 吞吐量 | 中(万级/秒) | 高(百万级/秒) | 高(十万级/秒) |
| 延迟 | 低(微秒级) | 中(毫秒级) | 低(毫秒级) |
| 消息可靠性 | 高 | 高 | 极高 |
| 事务支持 | 支持 | 不支持 | 完善(事务消息) |
| 延迟消息 | 支持(插件) | 不支持 | 原生支持 |
| 消息回溯 | 不支持 | 支持 | 支持 |
| 适用场景 | 传统业务系统 | 大数据、日志 | 金融、电商 |
RabbitMQ 交换器类型
| 类型 | 路由方式 | 示例 |
|---|---|---|
| Direct | 精确匹配路由键 | order.created → 订单队列 |
| Topic | 通配符匹配 | order.* → 所有订单队列 |
| Fanout | 广播到所有绑定队列 | 消息广播 |
| Headers | 根据消息头匹配 | 复杂条件过滤 |
Kafka 核心概念
Topic(主题):消息的逻辑分类
Partition(分区):Topic 的物理分片,分布在多个 Broker
Consumer Group(消费者组):组内消费者分摊消费分区
分区分配规则:
- 一个分区只能被组内一个消费者消费
- 一个消费者可以消费多个分区
- 消费者数量不应超过分区数
消息确认模式
| 模式 | 描述 | 可靠性 | 性能 |
|---|---|---|---|
| 自动确认 | 投递后立即确认 | 低 | 高 |
| 手动确认 | 处理完成后确认 | 高 | 中 |
| 批量确认 | 批量确认多条消息 | 中 | 高 |
服务发现
发现模式对比
| 特性 | 客户端发现 | 服务端发现 |
|---|---|---|
| 网络延迟 | 低(直连) | 高(经过代理) |
| 客户端复杂度 | 高 | 低 |
| 语言绑定 | 是 | 否 |
| 运维复杂度 | 低 | 高 |
| 故障隔离 | 好 | 一般 |
| 扩展性 | 好 | 受限于代理 |
注册中心对比
| 特性 | Consul | etcd | ZooKeeper | Nacos | Eureka |
|---|---|---|---|---|---|
| 一致性模型 | CP | CP | CP | AP/CP | AP |
| 健康检查 | 多种方式 | Lease | Session | 多种方式 | 心跳 |
| 多数据中心 | 支持 | 不支持 | 不支持 | 支持 | 不支持 |
| 配置管理 | 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 集群方案
| 方案 | 架构 | 特点 |
|---|---|---|
| 主从复制 | 一主多从 | 简单、读写分离、手动故障转移 |
| Sentinel | Sentinel 监控 + 主从 | 自动故障转移、高可用 |
| Cluster | 多主多从 + 分片 | 数据分片、自动故障转移、可扩展 |
共识算法
算法对比
| 算法 | 作者 | 特点 | 消息复杂度 | 容错模型 | 典型系统 |
|---|---|---|---|---|---|
| Paxos | Lamport | 理论基础,难理解 | 崩溃容错 | Chubby, Spanner | |
| Raft | Ongaro | 易理解,有 Leader | 崩溃容错 | Etcd, Consul, TiKV | |
| ZAB | Yahoo | ZooKeeper 专用 | 崩溃容错 | ZooKeeper | |
| PBFT | Castro | 拜占庭容错 | 拜占庭容错 | Hyperledger |
Raft 核心概念
Raft 由 Diego Ongaro 和 John Ousterhout 于 2014 年提出,将共识问题分解为三个子问题:
核心机制:
| 机制 | 描述 | 关键参数 |
|---|---|---|
| Leader 选举 | 超时触发选举,多数派投票获胜 | electionTimeout: 150-300ms |
| 日志复制 | Leader 追加日志,复制到 Follower | heartbeatInterval: 50ms |
| 安全性 | 日志匹配、Leader 完整性保证 | commitIndex, lastApplied |
选举超时计算:
典型配置: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. 返回虚拟节点对应的物理节点
虚拟节点数量经验值:
分库分表数量估算
分库数量:
库数量 = ⌈并发量 / 单库并发上限⌉
分表数量:
表数量 = ⌈数据总量 / 单表数据上限⌉
经验值(MySQL):
单表建议 < 1000 万行
单库建议 < 1TB 数据
单库并发建议 < 10000 QPS
数据复制
复制模式对比
| 模式 | 流程 | 延迟 | 数据安全 | 吞吐量 | 适用场景 |
|---|---|---|---|---|---|
| 同步复制 | 写主→等所有从→返回 | 高 | 最高 | 低 | 金融核心、关键配置 |
| 异步复制 | 写主→返回→异步写从 | 低 | 可能丢失 | 高 | 日志、非关键数据 |
| 半同步复制 | 写主→等至少一个从→返回 | 中 | 较高 | 中 | 通用业务数据 |
Quorum 机制
Quorum 机制通过读写节点数的约束来保证一致性:
其中 为写入成功的节点数, 为读取成功的节点数, 为总副本数。
常用配置:
| 配置 | W | R | 特点 | 适用场景 |
|---|---|---|---|---|
| 写优先 | N | 1 | 写慢读快 | 读多写少 |
| 读优先 | 1 | N | 写快读慢 | 写多读少 |
| 平衡 | 平衡 | 通用场景 |
一致性模型谱系
| 模型 | 描述 | 典型系统 |
|---|---|---|
| 线性一致性 | 所有操作看起来在单一时间点原子执行 | ZooKeeper, Etcd, Spanner |
| 顺序一致性 | 所有进程看到相同的操作顺序(但不一定是实时) | MySQL 主从复制 |
| 因果一致性 | 有因果关系的操作顺序一致,无因果可乱序 | Cassandra, DynamoDB |
| 最终一致性 | 最终收敛到一致状态 | DNS, CDN, Riak |
分布式ID
方案对比
| 方案 | 长度 | 有序 | 趋势递增 | 依赖 | QPS | 适用场景 |
|---|---|---|---|---|---|---|
| UUID | 36字符 | 否 | 否 | 无 | 极高 | 临时标识、追踪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 SETNX | Redis Redlock | ZooKeeper | etcd |
|---|---|---|---|---|
| 性能 | 极高 | 高 | 中 | 中 |
| 可靠性 | 中 | 高 | 高 | 高 |
| 实现复杂度 | 低 | 中 | 中 | 中 |
| 公平性 | 不支持 | 不支持 | 支持 | 支持 |
| 可重入 | 需实现 | 需实现 | 原生支持 | 需实现 |
| 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):
- 记录开始时间
- 依次向 N 个节点请求加锁(使用相同 key 和 value)
- 计算获取锁耗时
- 成功条件:多数派成功 且 耗时 < 锁过期时间
- 锁有效时间 = 过期时间 - 获取耗时
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 锁原理:
- 创建临时顺序节点
/lock/resource-00001 - 检查是否是最小节点
- 是最小节点 → 获取锁成功
- 不是最小节点 → 监听前一个节点的删除事件
- 前一个节点删除 → 被唤醒,再次检查
可观测性
三大支柱对比
| 维度 | 日志(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、内存、磁盘、网络等资源
常用组件端口
| 组件 | 默认端口 | 用途 |
|---|---|---|
| ZooKeeper | 2181 | 客户端连接 |
| ZooKeeper | 2888 | Follower 连接 Leader |
| ZooKeeper | 3888 | Leader 选举 |
| Etcd | 2379 | 客户端 API |
| Etcd | 2380 | 节点间通信 |
| Redis | 6379 | 客户端连接 |
| Redis Sentinel | 26379 | 哨兵端口 |
| Kafka | 9092 | Broker 端口 |
| Consul | 8500 | HTTP API |
| Consul | 8600 | DNS 接口 |
| Seata | 8091 | Server 端口 |
| Prometheus | 9090 | Web UI/API |
| Grafana | 3000 | 可视化界面 |
| Jaeger | 16686 | Web UI |
| Jaeger | 14268 | HTTP 收集 |
| OpenTelemetry | 4317/4318 | OTLP 接收 |
关键公式
可用性计算
- 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 个节点的系统可用性
- :单节点可用性
- :节点数量
分区容量估算
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 通过以下机制实现外部一致性:
- 时间戳分配:
- 提交等待:直到 为 true
这保证了:如果事务 T1 提交在 T2 开始之前(物理时间),则 T1 的时间戳 < T2 的时间戳。
常见问题排查
| 问题 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 数据不一致 | 网络延迟/分区 | 检查网络延迟、复制状态 | 增加重试、强一致性读 |
| 分布式事务超时 | 网络问题/负载高 | 检查超时日志、资源使用 | 增加超时、降级处理 |
| 死锁 | 锁顺序不一致 | 分析锁获取日志 | 统一加锁顺序、超时释放 |
| 脑裂 | 网络分区 | 检查节点通信状态 | 多数派投票、fencing token |
| 时钟回拨 | NTP 同步问题 | 检查系统时间、NTP 状态 | 关闭 NTP/使用容忍方案 |
| 热点数据 | 分片不均匀 | 分析数据分布、访问模式 | 调整分片键、热点隔离 |
| 雪花算法 ID 重复 | 时钟回拨/机器 ID 冲突 | 检查时钟、机器 ID 配置 | 时钟监控、ZK 分配 ID |
学习资源
经典论文
| 论文 | 作者 | 核心贡献 |
|---|---|---|
| CAP Theorem | Gilbert & Lynch | CAP 定理的正式证明 |
| Paxos Made Simple | Leslie Lamport | Paxos 算法的简化解释 |
| In Search of an Understandable Consensus Algorithm | Ongaro & Ousterhout | Raft 算法 |
| Spanner: Google's Globally-Distributed Database | TrueTime 和外部一致性 | |
| Dynamo: Amazon's Highly Available Key-value Store | Amazon | 最终一致性的工业实践 |
推荐书籍
- 《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 |