9. 最佳实践
设计分布式系统没有银弹,但有一套可复用的检查清单和决策树。本章把它们整理成工程师可以直接落地的指南。
9.1 设计检查清单
9.1.1 超时与重试
- [ ] 所有 RPC 调用都设置连接超时和请求超时;
- [ ] 超时时间基于 P99 延迟,而不是平均值;
- [ ] 重试使用指数退避 + 抖动,避免惊群;
- [ ] 重试次数有上限,超过后进入降级或失败处理;
- [ ] 写操作必须幂等或带 idempotency key。
9.1.2 幂等性与去重
- [ ] 关键写接口(扣费、注册、状态变更)要求客户端提供唯一 key;
- [ ] 服务端维护 idempotency key 索引,设置合理过期时间;
- [ ] 同一 key 的并发请求通过锁或数据库唯一索引去重;
- [ ] 重试时保持 key 不变,不重新生成。
9.1.3 熔断与降级
- [ ] 对下游依赖设置熔断器,失败率达到阈值后快速失败;
- [ ] 降级方案预先设计:返回缓存、默认值、简化结果;
- [ ] 熔断打开后定期探测恢复,避免永久隔离;
- [ ] 关键路径与非关键路径分离,避免非关键失败拖垮核心功能。
9.1.4 可观测性
- [ ] 所有服务暴露 Prometheus 风格的 metrics;
- [ ] 记录 request id,贯穿所有服务调用;
- [ ] 关键路径接入分布式追踪;
- [ ] 日志统一格式、统一采集、统一查询;
- [ ] 对 etcd、GCS、scheduler 等控制面组件设置专项监控。
9.1.5 状态管理
- [ ] 区分“有状态服务”和“无状态服务”,无状态服务优先水平扩展;
- [ ] 状态持久化到可靠存储,不依赖内存;
- [ ] 使用版本号或向量时钟检测并发冲突;
- [ ] 定期 snapshot / checkpoint,控制恢复时间目标(RTO)。
9.2 CAP 决策树
text
数据是否必须强一致?
├── 是 → 选择 CP
│ └── 是否需要跨地域低延迟写?
│ ├── 是 → 考虑 Spanner / CockroachDB / 分区后每区独立 Raft
│ └── 否 → etcd / ZooKeeper / TiDB
└── 否 → 选择 AP
└── 读延迟是否敏感?
├── 是 → 本地副本 + 异步复制 + 读修复
└── 否 → 最终一致 KV / 对象存储AI Infra 场景映射:
| 数据 | CAP 选型 | 系统 |
|---|---|---|
| K8s 状态 | CP | etcd |
| 训练 checkpoint 元数据 | CP | 数据库 / 强一致 KV |
| 训练数据集副本 | AP | 对象存储 |
| 推理缓存 | AP | Redis / 本地缓存 |
| 模型版本注册 | CP | Model Registry + 对象存储强一致 |
9.3 一致性选型决策树
text
是否需要线性一致?
├── 是 → 线性一致(etcd、ZooKeeper、Spanner)
└── 否 → 是否存在因果依赖?
├── 是 → 因果一致(向量时钟、CRDT)
└── 否 → 最终一致(版本向量、last-write-wins)9.4 测试策略
9.4.1 单元测试
- 每个分布式模块单独测试:时钟、向量时钟、Raft 节点、quorum 计算;
- 使用 FakeClock 和 InProcessNetwork 避免真实网络;
- 覆盖正常路径、失败路径、边界条件。
9.4.2 集成测试
- 多节点集群启动,注入故障,验证恢复;
- 使用 Docker Compose 或 Kind 搭建局部 K8s 集群;
- 验证 etcd 选主、apiserver watch、controller 重调谐。
9.4.3 混沌工程
- 随机 kill pod / 容器;
- 注入网络延迟、丢包、分区;
- 验证:系统是否自动恢复、数据是否一致、监控是否告警。
工具:Chaos Mesh、Litmus、Netflix Chaos Monkey、Toxiproxy。
9.5 部署与运维检查清单
- [ ] 控制面副本跨 AZ / 跨机架;
- [ ] 关键服务有 leader election 或热备;
- [ ] 存储卷有快照和跨区域备份;
- [ ] 网络策略限制不必要的跨节点通信;
- [ ] 资源配额防止单个任务耗尽共享资源;
- [ ] 定期演练故障恢复和 rollback;
- [ ] 文档化 RTO / RPO 目标。
9.6 一句话总结
分布式系统的最佳实践,本质上是“在不确定的环境中做确定性的工程”:用超时与重试掩盖网络抖动,用幂等与去重保证语义正确,用熔断与降级控制爆炸半径,用可观测性填补黑盒,用混沌工程提前暴露脆弱点。