| name | failure-injection-testing |
| description | 通过受控故障注入验证系统的容错能力。在验证节点宕机、网络分区、磁盘慢盘/坏盘、时钟漂移等故障路径时使用。当系统声称具备容错/高可用能力但缺乏故障路径证据时、上线前需要验证恢复流程时,或需要建立常态化混沌工程实践时使用。 |
故障注入测试
概述
分布式系统的正确性问题集中在故障路径上,而故障路径在 happy path 测试中永远不会被走到。故障注入是主动、受控地制造故障,用证据回答"系统在最坏情况下是否仍然守住承诺"——而不是等生产事故来回答。
核心纪律:一次只注入一种故障,先定义不变量再注入,爆炸半径永远受控。
何时使用
- 系统声称有容错能力(副本、自动切换、重试)但没有故障路径的测试证据
- 上线前验证滚动升级、故障转移、扩容重均衡在异常下的行为
- 复盘后需要把事故场景固化为回归测试
- 建立常态化的混沌工程/故障演练机制
不适用于:单元级逻辑验证(用 test-driven-development)、性能瓶颈定位(用 performance-optimization)、已知故障的根因排查(用 debugging-and-error-recovery)。
流程
1. 定义要验证的承诺
把"高可用"翻译成可证伪的不变量,每条都必须是可机器检查的断言:
- 已 ack 的写入在任意单节点故障后不丢失
- 网络分区期间,多数派侧继续服务,少数派侧拒绝写入(不脑裂)
- 单块慢盘不使集群 p99 超过基线的 2 倍
- 任意时刻 kill 进程,重启后能恢复到一致状态
没有不变量的故障注入只是制造混乱,不是测试。
2. 建立稳态基线
注入前先测量正常状态下的关键指标(p99/p999 延迟、吞吐、副本滞后、错误率)。没有基线就无法判断注入后的偏移是故障影响还是注入工具本身的开销。
3. 选择故障类型与注入点
按系统架构枚举故障域,从最常见的开始:
| 故障类型 | 注入手段 | 典型验证目标 |
|---|
| 进程/节点宕机 | kill -9、停虚拟机 | 副本接管、重试路径、数据不丢 |
| 网络分区 | tc/iptables、Toxiproxy | 不脑裂、分区恢复后收敛 |
| 网络延迟/丢包 | tc qdisc add ... netem delay/loss | 超时与重试不失控、无重试风暴 |
| 慢盘 | dm-delay、限速 cgroup | 慢盘检测与隔离生效 |
| 坏盘/数据损坏 | dm-flakey、注入校验和错误 | 端到端校验和能发现静默损坏 |
| 磁盘写"说谎" | fault injection framework(fail_make_request) | fsync 语义被正确依赖 |
| 时钟漂移/跳变 | faketime、测试时钟 | lease 不重叠、单调钟假设成立 |
| 资源耗尽 | 打满磁盘、限制内存/句柄 | 优雅降级而非雪崩 |
kill point 的选择要有依据:在写路径的关键阶段(收到请求、写 WAL、刷盘、应用状态机、回复客户端)之间逐个注入,而不是随机杀。
4. 单次注入,观察收敛
- 注入一种故障
- 观察指标与日志:系统是否检测到?按预期路径恢复?
- 验证所有不变量——这是通过/失败的判据,不是"服务还活着"
- 清除故障,验证系统恢复到基线(副本追平、延迟回落)
5. 固化与常态化
- 每个通过的注入场景固化为自动化用例,进 nightly(而非 PR 门控——注入测试慢且重)
- 每个生产事故复盘后,补一个能复现该事故的注入场景
- 注入编排参数化(故障类型 × kill point × 负载),用 seed 驱动以便复现失败
- 定期提高强度:从单故障到组合故障、到随机化混沌(chaos monkey 式)
爆炸半径控制(不可跳过)
- 默认只在测试集群注入;生产环境的任何故障注入必须显式审批、有回退预案、限定范围(单节点 → 单机架,绝不跨故障域)
- 注入工具必须有可靠的"全部清除"路径,且清除后验证集群回到基线
- 注入期间数据按真实数据对待:不用未脱敏的生产数据做实验
常见合理化借口
| 借口 | 现实 |
|---|
| "我们有三副本,宕一台没事" | 三副本只证明你付了三份钱,不证明接管路径工作。未测试的故障转移等于没有 |
| "单元测试和集成测试都过了" | happy path 全绿对故障路径零覆盖。正确性问题恰恰住在故障路径上 |
| "随机关一下节点就算混沌工程了" | 没有不变量断言的随机破坏产生的是噪音,不是证据 |
| "测试环境测过了,生产肯定一样" | 测试集群通过了是准入证,不是终点——但生产注入必须审批、限速、有回退 |
| "这次先上线,故障测试后面补" | 故障路径的 bug 只在事故时暴露,那时的成本是数据丢失或停机 |
| "注入工具本身的干扰不用管" | netem/限速会改变被测系统的行为特征。不控制注入开销,结论无效 |
红旗警告
- 没有先写不变量断言就开始注入故障
- 一次注入多种故障,无法归因
- 只看"服务没挂"就宣布通过,不验证数据一致性和恢复完整性
- 故障注入用例靠
sleep 等待收敛而非轮询状态
- 注入测试失败后没有 seed/参数记录,无法复现
- 在生产注入前没有爆炸半径评估和审批记录
- 事故复盘没有产出新的故障注入用例
验证