Table of contents
Open Table of contents
TL;DR
容灾是伞状概念,包含容错(Fault Tolerance)和灾难恢复(Disaster Recovery)。容错要求故障发生时零中断继续服务(用冗余掩盖故障);灾难恢复关注灾难后如何恢复(用备份和复制缩短恢复时间)。核心思想:故障不是”是否发生”而是”何时发生”——系统设计必须将故障视为常态。
概念区分
| 维度 | 容错(FT) | 高可用(HA) | 灾难恢复(DR) |
|---|---|---|---|
| 核心目标 | 故障时继续运行,用户无感知 | 最大化正常运行时间 | 灾难后恢复系统 |
| 故障规模 | 组件级(单盘、单节点) | 服务级 | 灾难级(机房、Region) |
| 中断容忍 | 零中断 | 允许极短中断(秒级) | 允许中断(分钟到小时) |
| 衡量指标 | 故障掩盖率 | SLA uptime % | RTO + RPO |
三者的关系:FT 是 HA 的实现手段之一,HA 关注”别挂”,DR 关注”挂了怎么办”。
故障类型
| 类型 | 典型案例 | 检测难度 |
|---|---|---|
| 硬件故障 | 磁盘损坏、内存 bit flip、电源故障 | 低~中 |
| 软件故障 | Bug、内存泄漏、配置错误、依赖故障 | 中~高 |
| 网络故障 | 网络分区、延迟抖动、DNS 故障 | 高 |
| 人为错误 | 误操作 DROP TABLE、变更引入 regression | 最常见(约 70%) |
Google SRE 数据:人为错误是生产故障首要原因。 所以容错不能只考虑硬件软件,操作审计、变更管控、灰度发布等流程性措施同样是容错的一部分。
冗余策略
| 策略 | 资源利用率 | 切换时间 | 适用层 |
|---|---|---|---|
| Active-Active | 高 | 0(无需切换) | 无状态服务 |
| Active-Passive | 低(50%浪费) | 秒~分钟 | 有状态服务(DB) |
| N+1 | 较高 | 取决于调度 | 计算节点池 |
| 2N | 低(50%浪费) | 极短 | 关键基础设施(电源) |
故障域(Blast Radius)
架构设计的核心任务之一是控制故障影响范围:
故障域层级:Server < Rack < AZ < Region
副本必须跨故障域分布。3 副本放同一 Rack,交换机一挂全完。
优雅降级
核心:保住核心功能,牺牲非核心功能。这是产品决策,不是纯技术问题。
正常 → 功能降级(关闭推荐/评论)
→ 数据降级(返回缓存/默认值)
→ 体验降级(静态页面)
→ 流量降级(限流/排队)
→ 完全不可用 ← 要避免到这一步
降级必须提前编码,降级开关通过配置中心秒级生效,不能在故障时临时决定。
混沌工程
不是”随机搞破坏”,而是科学实验方法:受控故障注入,验证系统行为是否符合预期。
原则:建立稳态假设 → 用真实世界事件模拟 → 在生产环境运行 → 持续自动化 → 最小化 blast radius。
工具:Chaos Monkey(Netflix,随机杀实例)、Litmus/Chaos Mesh(K8s 原生)、Toxiproxy(网络故障模拟)。
GameDay:有组织的故障演练。计划→执行→复盘→修复。关键系统每季度至少一次。
灾难恢复(DR)
RPO 和 RTO
最后一次备份 ──RPO(丢多少数据)──▶ 灾难 ──RTO(停多久)──▶ 恢复完成
RPO/RTO 越小成本越高。这是业务决策——业务方需要回答”丢 1 小时数据的代价是多少钱”。
DR 策略分级
| 策略 | RTO | RPO | 成本 | 适用场景 |
|---|---|---|---|---|
| Backup & Restore | 小时~天 | 小时~天 | 最低 | 非关键系统 |
| Pilot Light | 分钟~小时 | 接近 0 | 低 | 中等重要性 |
| Warm Standby | 分钟级 | 接近 0 | 中 | 重要业务 |
| Multi-Site Active-Active | 秒级~0 | 0 | 最高 | 核心交易系统 |
- Pilot Light:核心数据组件持续同步(DB 副本),计算资源不启动,灾难时启动+扩容+切流量
- Warm Standby:DR 站点缩小规格运行中,灾难时扩容到全量
- Multi-Site:两站同时承载流量,最大挑战是双向数据同步的冲突解决
备份验证
不验证的备份等于没备份。 GitLab 2017 年事故——5 种备份全部失败,靠偶然快照救回。
备份验证必须包括:完整性校验 + 定期恢复到隔离环境 + 时效性检查 + 失败告警。
PostgreSQL 备份:小库用 pg_dump;大库用 pg_basebackup + WAL 归档支持 PITR;推荐 pgBackRest(增量、并行、远程、验证)。
跨 Region 复制
| 复制方式 | RPO | 写性能影响 | 适用场景 |
|---|---|---|---|
| 同步 | 0 | 高 | 同城/同 AZ |
| 异步 | >0 | 无 | 跨 Region |
| 半同步 | 接近 0 | 中 | 同城双中心 |
物理限制:北京到上海 ~5ms RTT,北京到美东 ~200ms RTT。跨 Region 同步复制不可行。
关键设计模式
Circuit Breaker
快速失败比慢速等待好。三态:Closed(正常)→ Open(全部拒绝)→ Half-Open(试探)。
关键参数:失败阈值(滑动窗口内错误率 50% 且至少 20 个请求)、Open 持续时间(30-60s)、Half-Open 成功阈值。
Bulkhead(隔舱)
不同下游依赖使用独立线程池/连接池。API-B 超时耗尽自己的池子,API-A/C/D 完全不受影响。
Timeout + Retry + Backoff + Jitter
每个外部调用都必须设 timeout,没有超时 = 资源泄漏定时炸弹。
组合使用:超时分层递减 + 限制重试次数(2-3 次)+ 指数退避 + Jitter 打散 + 总超时兜底。
不是所有错误都该重试:503/超时可重试;400/401/404 不可重试;非幂等操作需要 idempotency key。
幂等性
容错体系的基石——没有幂等性,重试就是定时炸弹。
实现方式:幂等键(客户端生成 UUID)、数据库唯一约束(ON CONFLICT DO NOTHING)、状态机(操作只在特定状态执行)、乐观锁(version 字段)。
故障场景速查
| 场景 | 应对 | RTO |
|---|---|---|
| 单节点故障 | K8s 自动重调度 | 秒级 |
| 单 AZ 故障 | 流量切其他 AZ | 分钟级 |
| Region 故障 | DR 站点接管 | 分钟~小时 |
| 网络分区 | Quorum 多数派继续服务 | 秒~分钟 |
| 数据损坏 | PITR 恢复到损坏前 | 小时级 |
| 级联故障 | Circuit Breaker + Bulkhead + 限流 | 取决于隔离速度 |
级联故障是最危险的:Service A 超时 → 线程池耗尽 → Service B 调 A 超时 → B 也耗尽 → 继续蔓延。防止组合拳:Circuit Breaker + Bulkhead + Timeout + 限流 + 降级。
Pitfalls
- 备份从未恢复测试 — 备份天天在跑但真恢复时才发现损坏/不完整。对策:每月恢复演练到隔离环境
- DR 方案只在文档里 — 手册中的 IP/密码/工具早已过时。对策:每季度 DR 演练
- 级联故障 — 非核心服务 DB 慢查询拖垮整个系统。对策:外部调用设 timeout + Circuit Breaker
- 脑裂 — 网络分区后两个”主”同时写,数据分叉。对策:quorum + STONITH fencing
- 超时设置不合理 — 每层都 30s timeout,下游卡住上游全部线程阻塞。对策:超时分层递减 + context deadline 传递
- 重试风暴 — 所有客户端同时重试,3 倍流量打挂刚恢复的服务。对策:Backoff + Jitter + Circuit Breaker + 重试预算
- 只有复制没有备份 — 误删 DROP TABLE 被忠实地复制到所有副本。对策:复制应对硬件故障,备份应对数据损坏/误删(PITR)
- 监控盲区 — 复制延迟从 1s 悄悄涨到 1 小时无人知。对策:复制延迟监控 + 分级告警
生产 Checklist
基础容错:
- 所有外部调用有 timeout + Circuit Breaker
- 不同下游独立连接池(Bulkhead)
- 重试含 Backoff + Jitter,目标接口幂等
- 非核心功能有降级开关
- 无单点故障
数据保护:
- 自动备份 + 备份存储在不同 Region
- 每月备份恢复验证
- WAL 归档支持 PITR
- 复制延迟有监控和告警
灾难恢复:
- RPO/RTO 已定义(业务方确认)
- DR 策略级别匹配 RPO/RTO
- 每季度 DR 演练
- DR 环境配置与生产同步
混沌工程:
- 定期 GameDay
- 生产环境有受控故障注入能力
- 演练发现项有跟踪闭环