名称: 分布式系统设计 描述: 在设计分布式系统以实现可扩展性、可靠性和一致性时使用。涵盖CAP/PACELC定理、一致性模型(强一致性、最终一致性、因果一致性)、复制模式(领导者-追随者、多领导者、无领导者)、分区策略(哈希、范围、地理)、事务模式(saga、事件溯源、CQRS)、弹性模式(断路器、舱壁)、服务发现和缓存策略,用于构建容错的分布式架构。
分布式系统设计
使用经过验证的模式和一致性模型设计可扩展、可靠和容错的分布式系统。
目的
分布式系统是现代云原生应用的基础。理解基本权衡(CAP定理、PACELC)、一致性模型、复制模式和弹性策略对于构建在全球范围内扩展同时保持正确性和可用性的系统至关重要。
何时使用此技能
适用于:
- 设计包含多个服务的微服务架构
- 构建必须跨多个数据中心或区域扩展的系统
- 在网络分区期间选择一致性与可用性
- 选择复制策略(单领导者、多领导者、无领导者)
- 实现分布式事务(saga模式、事件溯源、CQRS)
- 设计具有适当一致性保证的分区容错系统
- 构建具有断路器、舱壁、重试的弹性服务
- 实现服务发现和服务间通信
核心概念
CAP定理基础
CAP定理: 在经历网络分区的分布式系统中,选择一致性(C)或可用性(A)。分区容错(P)是强制性的。
网络分区将会发生 → 始终设计为P
分区期间:
├─ CP(一致性 + 分区容错)
│ 使用场景:金融交易、库存、座位预订
│ 权衡:分区期间系统不可用
│ 示例:HBase、MongoDB(默认)、etcd
│
└─ AP(可用性 + 分区容错)
使用场景:社交媒体、缓存、分析、购物车
权衡:可能读取陈旧数据,需要冲突解决
示例:Cassandra、DynamoDB、Riak
PACELC: 扩展CAP以考虑正常操作(无分区)。
- 如果分区: 选择可用性(A)或一致性(C)
- 否则(正常): 选择延迟(L)或一致性(C)
一致性模型谱系
强一致性 ◄─────────────────────► 最终一致性
│ │ │
线性化 因果一致性 收敛
(最慢, (中间地带, (最快,
最一致) 因果有序) 最终一致)
强一致性(线性化):
- 所有操作按顺序原子性出现
- 读取总是返回最新写入
- 使用场景:银行余额、库存数量、座位预订
- 权衡:更高延迟,降低可用性
最终一致性:
- 如果没有新更新,所有副本最终收敛
- 使用场景:社交动态、产品目录、用户档案、DNS
- 权衡:可能读取陈旧数据,需要冲突解决
因果一致性:
- 所有节点以相同顺序看到因果相关操作
- 使用场景:聊天应用、协作编辑、评论线程
- 权衡:比最终更复杂,需要因果追踪
有限陈旧性:
- 陈旧性由时间或版本计数限制
- 使用场景:实时仪表板、排行榜、监控
- 权衡:必须监控延迟,比最终更复杂
复制模式
1. 领导者-追随者(单领导者):
- 所有写入到领导者,复制到追随者
- 追随者处理读取(负载分布)
- 同步: 等待追随者确认(强一致性,更高延迟)
- 异步: 不等待(最终一致性,可能数据丢失)
- 使用场景:最常见模式,强一致性用同步复制
2. 多领导者:
- 多个领导者在不同数据中心接受写入
- 领导者相互复制
- 需要冲突解决: 最后写入获胜、应用合并、向量时钟
- 使用场景:多数据中心、低写入延迟、地理分布式用户
- 权衡:冲突解决复杂性
3. 无领导者(Dynamo风格):
- 无单一领导者,基于法定人数读写
- 法定人数规则: W + R > N(W=写入法定人数,R=读取法定人数,N=副本数)
- 示例:N=5, W=3, R=2 → 强一致性(重叠保证)
- 使用场景:最大可用性、分区容错
- 权衡:复杂性,需要读取修复
分区策略
哈希分区(一致哈希):
- 键 → 哈希(键) → 分区分配
- 均匀分布,节点增减时最小重新平衡
- 使用场景:按ID点查询,均匀分布关键
- 示例:Cassandra、DynamoDB、Redis集群
范围分区:
- 键范围分配给分区(A-F, G-M, N-S, T-Z)
- 支持范围查询,有序数据
- 风险:数据倾斜时热点
- 使用场景:时间序列数据、排行榜、范围扫描
- 示例:HBase、Bigtable
地理分区:
- 按地理位置分区(美国东部、欧盟西部、亚太)
- 使用场景:数据本地化、GDPR合规、低延迟
- 示例:Spanner、Cosmos DB
弹性模式
断路器:
[关闭] → 正常操作
│(失败超过阈值)
▼
[打开] → 快速失败(不调用失败服务)
│(超时到期)
▼
[半开] → 尝试单个请求
│ 成功 → [关闭]
│ 失败 → [打开]
- 防止级联失败
- 快速失败而不是等待超时
- 参见references/resilience-patterns.md
舱壁隔离:
- 隔离资源(线程池、连接池)
- 一个分区的失败不影响其他
- 类似船舱防止完全淹没
超时和重试:
- 超时: 设置截止时间,超时快速失败
- 重试: 指数退避加抖动
- 幂等性: 确保安全重试(关键)
速率限制和背压:
- 保护服务免受过载
- 令牌桶、漏桶算法
- 背压:向上游信号减速
事务模式
Saga模式:
- 协调跨服务的分布式事务
- 无分布式2PC(两阶段提交)
编排: 服务响应事件
订单服务 → 订单创建事件
支付服务 → 监听 → 支付处理事件
库存服务 → 监听 → 库存预留事件
(补偿:如果支付失败 → 库存释放事件)
协调: 中央协调器
Saga协调器:
1. 调用订单服务
2. 调用支付服务
3. 调用库存服务
(如果步骤失败 → 反向调用补偿事务)
事件溯源:
- 将状态更改存储为不可变事件
- 通过重放事件重建状态
- 审计跟踪、时间旅行、调试
- 权衡:查询复杂性,快照优化
CQRS(命令查询责任分离):
- 分离读写模型
- 写模型:规范化、事务性
- 读模型:非规范化、缓存、优化
- 使用场景:不同读写模式,高读写比(10:1+)
- 常与事件溯源配对
服务发现
客户端发现:
- 客户端查询服务注册表(Consul、etcd、Eureka)
- 客户端负载均衡并直接调用服务
- 优点:无代理开销
- 缺点:客户端复杂性
服务器端发现:
- 客户端调用负载均衡器
- 负载均衡器查询注册表并路由
- 优点:客户端简单
- 缺点:负载均衡器单点故障
服务网格:
- 边车代理处理发现、路由、重试、断路器
- 示例:Istio、Linkerd
- 优点:将通信逻辑与服务解耦
- 缺点:操作复杂性
缓存策略
旁路缓存(延迟加载):
读取:
1. 检查缓存 → 命中?返回
2. 未命中?查询数据库
3. 存储在缓存,返回
写透:
写入:
1. 写入缓存
2. 缓存同步写入数据库
3. 返回成功
写回:
写入:
1. 写入缓存
2. 返回成功
3. 缓存异步写入数据库(批量)
缓存失效:
- TTL(生存时间):持续时间后过期
- 基于事件:数据更改时失效
- 手动:更新时显式失效
决策框架
选择一致性模型
决策树:
├─ 涉及金钱? → 强一致性
├─ 重复预订不可接受? → 强一致性
├─ 因果关系重要(聊天、编辑)? → 因果一致性
├─ 读取重、陈旧可容忍? → 最终一致性
└─ 默认? → 最终一致性(然后根据需要加强)
选择复制模式
├─ 单区域写入? → 领导者-追随者
├─ 多区域写入 + 冲突可接受? → 多领导者
├─ 多区域写入 + 无冲突? → 领导者-追随者带故障转移
└─ 最大可用性? → 无领导者(法定人数)
选择分区策略
├─ 需要范围扫描? → 范围分区(风险:热点)
├─ 数据驻留要求? → 地理分区
└─ 默认? → 哈希分区(一致哈希)
快速参考表
CAP/PACELC系统比较
| 系统 | 如果分区 | 否则(正常) | 使用案例 |
|---|---|---|---|
| Spanner | PC | EC(强) | 全局SQL |
| DynamoDB | PA | EL(最终) | 高可用性 |
| Cassandra | PA | EL(可调) | 宽列存储 |
| MongoDB | PC | EC(默认) | 文档存储 |
| Cosmos DB | PA/PC | EL/EC(5级) | 多模型 |
一致性模型使用案例
| 使用案例 | 一致性模型 |
|---|---|
| 银行账户余额 | 强(线性化) |
| 座位预订(航空) | 强(线性化) |
| 库存数量 | 强或有限 |
| 购物车 | 最终 |
| 产品目录 | 最终 |
| 协作编辑 | 因果 |
| 聊天消息 | 因果 |
| 社交媒体点赞 | 最终 |
| DNS记录 | 最终 |
法定人数配置
| 配置 | W | R | N | 一致性 | 使用案例 |
|---|---|---|---|---|---|
| 强 | 3 | 3 | 5 | 强 | 银行 |
| 平衡 | 3 | 2 | 5 | 强 | 默认 |
| 写入重 | 2 | 3 | 5 | 强 | 日志 |
| 读取重 | 3 | 1 | 5 | 最终 | 缓存 |
| 最大可用 | 1 | 1 | 5 | 最终 | 分析 |
渐进披露
详细参考
有关特定主题的全面覆盖,请参见:
- references/cap-pacelc-theorem.md - CAP和PACELC深入探讨及PACELC矩阵
- references/consistency-models.md - 强、最终、因果、有限陈旧性模式
- references/replication-patterns.md - 领导者-追随者、多领导者、无领导者复制
- references/partitioning-strategies.md - 哈希、范围、地理分区示例
- references/consensus-algorithms.md - Raft和Paxos概述(当需要共识时)
- references/resilience-patterns.md - 断路器、舱壁、超时、重试、速率限制
- references/saga-pattern.md - 编排与协调及工作示例
- references/event-sourcing-cqrs.md - 事件溯源和CQRS实现模式
- references/service-discovery.md - 客户端端、服务器端、服务网格模式
- references/caching-strategies.md - 旁路、写透、写回、失效
工作示例
完整、可运行的示例演示模式:
- examples/consistent-hashing/ - 带虚拟节点的一致哈希实现
- examples/circuit-breaker/ - 带状态转换的断路器模式
- examples/saga-orchestration/ - 带补偿事务的Saga协调器
- examples/event-sourcing/ - 带重放和快照的事件存储
- examples/cqrs/ - 带分离读写模型的CQRS
- examples/service-discovery/ - 基于Consul的服务发现和注册
ASCII图表
复杂概念的视觉表示:
- diagrams/cap-theorem.txt - CAP定理决策树
- diagrams/replication-topologies.txt - 领导者-追随者、多领导者、无领导者
- diagrams/saga-flow.txt - Saga编排和协调流程
- diagrams/caching-patterns.txt - 旁路、写透、写回
与其他技能的集成
相关技能:
对于Kubernetes部署:参见kubernetes-operations技能以获取Pod反亲和、服务网格
对于基础设施:参见infrastructure-as-code技能以部署分布式系统
对于数据库:参见databases-sql和databases-nosql以获取复制配置
对于消息传递:参见message-queues技能以获取事件驱动架构、Saga协调
对于监控:参见observability技能以获取分布式跟踪、监控模式
对于测试:参见performance-engineering技能以获取负载测试分布式系统
对于安全:参见security-hardening技能以获取mTLS、服务认证
常见模式
多数据中心模式
1. 选择复制:多领导者或无领导者
2. 地理分区数据
3. 实现冲突解决(LWW、向量时钟、应用特定)
4. 监控复制延迟
5. 在数据中心之间添加断路器
事件驱动Saga模式
1. 定义Saga步骤和补偿操作
2. 选择编排(事件)或协调(协调器)
3. 实现幂等处理程序(重试安全)
4. 使用发件箱模式发布事件(事务性)
5. 监控Saga进度和超时
高可用性模式
1. 使用无领导者复制(N=5, W=3, R=2)
2. 用一致哈希分区
3. 为失败节点添加断路器
4. 实现读取修复和反熵
5. 监控法定人数健康
最佳实践
为失败设计:
- 网络分区将会发生 - 始终设计为分区容错
- 使用超时、带指数退避的重试
- 实现断路器以防止级联失败
- 测试混沌工程场景(分区节点、注入延迟)
谨慎选择一致性:
- 默认为最终一致性,仅在需要时加强
- 强一致性有实际成本(延迟、可用性)
- 使用有限陈旧性作为中间地带
幂等性关键:
- 设计操作以安全重试
- 使用唯一请求ID进行去重
- Saga补偿事务必不可少
监控和观察:
- 带相关ID的分布式跟踪
- 监控复制延迟、法定人数健康
- 断路器状态更改警报
- 跟踪Saga进度和失败
战略分区:
- 哈希分区以均匀分布
- 范围分区以范围查询(监控热点)
- 地理分区以合规、延迟
版本化一切:
- 事件模式演化 - 使用版本化
- 服务兼容性的API版本化
- 分布式系统中的数据库模式迁移
避免的反模式
分布式单体:
- 微服务紧密耦合
- 跨服务共享数据库
- 修复:每个服务数据库,异步通信
过度使用两阶段提交(2PC):
- 慢、阻塞、降低可用性
- 修复:对分布式事务使用Saga模式
忽略网络故障:
- 假设网络可靠
- 修复:始终添加超时、重试、断路器
处处强一致性:
- 不必要的延迟和复杂性
- 修复:默认使用最终一致性,仅在需要处加强
无冲突解决策略:
- 多领导者无处理冲突
- 修复:选择LWW、向量时钟或应用特定合并
缓存冲击:
- TTL到期,所有客户端查询数据库
- 修复:概率早期到期、请求合并
故障排除
复制延迟过高:
- 检查数据中心间网络带宽
- 监控领导者写入吞吐量
- 考虑异步复制或多领导者
裂脑场景:
- 分区期间选举多个领导者
- 修复:使用共识(Raft、Paxos)选举领导者
- 实现防护令牌以防止双重写入
热点分区:
- 范围分区数据倾斜
- 修复:添加哈希组件,手动重新分配,使用复合键
Saga超时/停滞:
- 服务不可用,Saga无法完成
- 修复:实现带自动回滚的Saga超时
- 死信队列以手动干预
冲突解决失败:
- 多领导者冲突未处理
- 修复:实现明确解决策略(LWW、合并、手动)
- 监控冲突率,警报峰值