前置知识: Python

混沌工程与故障注入

4 min入门

稳定态假设、实验设计(假设/爆炸半径/中止条件)、注入对象与工具(Chaos Mesh/Litmus/AWS FIS)、与压力及灾备测试的分工。

知识点地图

  • 知识类别:混沌工程(chaos engineering)——在生产或类生产环境主动注入故障、验证系统韧性的实验方法,含故障注入(fault injection)工具层。
  • 解决什么问题:压测回答「扛多少量」,灾备演练回答「恢复流程对不对」,但「下游慢 500ms 会不会雪崩」「节点被杀会不会自愈」这类韧性假设没人验证过——混沌工程把假设变成实验。
  • 什么时候用到:验证超时/重试/降级配置真实生效;验证 K8s 自愈与多副本容错;验证监控告警真的会响;大促前对关键链路做韧性演练。

前置:稳定性与压测基础见压力与稳定性测试;灾备概念(RPO/RTO、多区域)见云架构设计。

1. 心智模型:韧性不是配出来的,是验证出来的

传统测试构造输入(发更多请求),混沌工程构造环境(让依赖变慢、让节点消失)。它的立论是:分布式系统由数千个「理论上应该这样工作」的机制组成——超时、重试、熔断、自愈探针——而其中大部分从未在任何一次故障中被真正触发过。等真实故障来检验,代价就是事故。

三个没有做过混沌实验的团队常见认知 vs 实验结果:

  • 「超时配了 3 秒所以下游慢不会拖垮我们」→ 实验发现连接池在 3 秒超时前就被占满(超时发生在 HTTP 层,池子租借等的是更早的一层)。
  • 「Deployment 3 副本杀一个 Pod 没影响」→ 实验发现 readinessProbe 间隔 30 秒,杀 Pod 后 30 秒内流量打到剩余副本直接打满。
  • 「磁盘满了监控会告警」→ 实验发现告警规则匹配的是 /data 挂载点,真实打满的是 /。

2. 实验设计四要素

混沌不是「搞破坏」,是科学实验:每个实验四要素缺一不可。

  1. 稳定态假设(steady state hypothesis):先用可度量指标定义「系统正常」——「下单成功率 > 99.9%,P95 < 300ms」。没有稳定态定义,实验结束后无法回答「系统韧性与之前一样吗」。
  2. 假设(hypothesis):「给支付回调依赖注入 500ms 延迟,下单成功率仍在 99.9% 以上」(预期韧性成立);或坦率地「我们不知道,想找出答案」。
  3. 爆炸半径(blast radius):注入影响的最小范围——先灰度一个实例、一条链路、预发环境。爆炸半径控制是混沌与「瞎搞」的分界线。
  4. 中止条件(abort condition):指标越过红线(成功率 < 99%)自动停止注入——实验必须是随时可一键止血的,不能依赖人肉盯盘反应速度。

工程场景(支付链路注入下游 500ms 延迟):大促前两周,支付团队对预发环境注入:风控接口 +500ms、短信网关错误率 10%。实验一:下单成功率确实稳住——但 P95 从 280ms 涨到 900ms,因为串行调用两个依赖;实验二把风控调用改并发后回落。两条结论进大促 checklist:串行依赖改并发;短信失败静默降级不阻塞主流程。没有这两次注入,答案只会在大促当晚 20:00 由真实用户给出。

3. 注入对象与典型实验

注入对象方式验证的韧性机制典型发现
延迟网络层延迟注入(目标依赖 +Nms)超时、重试、降级、熔断串行依赖放大延迟;重试风暴
错误HTTP 层返回 5xx/超时错误处理、fallbackfallback 未覆盖的分支
资源耗尽打满 CPU/内存/磁盘/连接池限流、排队、告警告警规则匹配错挂载点;池满早于超时
节点宕机杀 Pod/进程/断网自愈、副本冗余、会话保持readiness 慢导致短暂 5xx;粘性会话丢失
时钟跳变调整系统时间缓存过期、token 刷新依赖本地时钟的逻辑在跳变后批量失效
依赖断联断开数据库/消息中间件熔断、本地缓存、排队断联恢复后的「惊群重连」

实验优先级排序原则:从「爆炸半径可控 + 怀疑最深」的组合开始。生产环境只做已经预演过、有自动止血的实验;新团队第一年通常止步于预发 + 灰度。

4. 工具速览

工具生态适合
Chaos MeshCNCF,K8s 原生K8s 集群内延迟/杀 Pod/时钟/IO 注入
LitmusChaosCNCF,K8s带实验集(chaos experiments hub)的声明式编排
AWS FISAWS 托管AWS 资源层(杀实例、打不可用 IAM、限流 API)
toxiproxy应用层代理本地与 CI 的依赖延迟/断联模拟
Spring Chaos / Chaos Monkey 系框架内应用进程内部随机故障(依赖调用失败)
  • 选型直觉:K8s 工作负载的注入用 Chaos Mesh/Litmus;AWS 资源层(实例、可用区、API 限流)用 FIS;本地开发与单测级的依赖故障用 toxiproxy——三层工具对应三种爆炸半径。
  • 易错点:把混沌工具当成「手动搞事按钮」随便一打。工具只是执行器,价值全在实验设计四要素——没有稳定态假设与中止条件的注入就是事故制造。

工程场景(K8s 杀 Pod 验证自愈 + 磁盘打满验证告警):

bash
# 实验 1:随机杀 payments 命名空间一个 Pod,观察自愈与流量切换
kubectl delete pod -l app=payments -n payments --field-selector=status.phase=Running

# 实验 2:用 chaosd/dd 给根分区灌满 95%,验证告警触发与清理预案
dd if=/dev/zero of=/tmp/filler bs=1M count=40000
# 观察点:磁盘告警是否在 5 分钟内触发;清理 runbook 是否可执行

实验 1 的常见翻车点:只看 Pod 起来了就宣布成功——要看的是注入窗口内的用户侧错误率(ingress 指标),那里藏着 readiness 探针配置的全部真相。实验 2 的价值一半在告警、一半在演练清理预案——没人真删过 40GB 垃圾文件。

5. 与压力/稳定性/灾备测试的分工

方法改变的量回答的问题成功标准
压力测试负载(输入量)扛到多少量、拐点在哪达到目标 QPS 且错误率达标(见压力与稳定性测试)
稳定性/浸泡测试时间(持续负载)长跑是否劣化(内存泄漏、句柄)N 天后指标不劣化
灾备演练整体(切区域/切库)恢复流程与 RTO/RTO 达标按预案完成切换,RPO/RTO 达标(见云架构设计)
混沌实验环境状态(局部故障)韧性机制是否如假设工作稳定态指标在注入期间保持

边界易混点:压测把量推过拐点后观察到崩溃,那是容量结论;混沌在正常负载下注入局部故障,观察的是韧性结论。灾备演练动的是「整个可用区/区域」,混沌动的是「一个实例、一个依赖」——爆炸半径差两个数量级。

6. 从一次实验到常态化

成熟的混沌实践是流水线化的:实验定义进版本库(代码化)、稳定态指标进监控(自动判读)、注入进 CI/CD 的定时或发布前阶段(自动化)、结果进复盘文档(知识化)。起步顺序建议:

  1. 预发环境手工跑 2-3 个经典实验(杀 Pod、延迟注入、磁盘打满);
  2. 把实验参数与稳定态判据写成声明式配置(Chaos Mesh YAML / FIS 模板);
  3. 接入发布前自动化(大促演练、季度韧性日);
  4. 最后才考虑生产环境低爆炸半径实验——这一步多数团队终年不必到达。

动手实践

任务:为一条「下单链路(网关 -> 订单服务 -> 库存服务 + 短信通知)」设计一次混沌实验方案:

  1. 写稳定态假设(选 2 个可度量指标);
  2. 写假设句式:「注入 X,预期 Y」;
  3. 设计爆炸半径(环境、实例范围、流量比例)与中止条件(指标红线);
  4. 选择工具并写注入参数(延迟 500ms 打在哪一跳上,为什么);
  5. 预写「实验报告」的发现栏结构(哪怕实验还没跑)。

提示:

  1. 稳定态指标必须来自现有监控(没有先补监控,这是实验前置依赖);
  2. 延迟打在「库存服务」与打在「短信网关」上,实验价值完全不同——短信是旁路、库存是同步依赖;
  3. 中止条件要自动化(监控指标触发自动撤销注入),写成「谁在什么阈值做什么动作」。
参考方案(先自己写,再展开对照)
  • 稳定态假设:下单成功率 > 99.9%(1 分钟窗口);下单 P95 < 300ms。
  • 假设:「给库存服务注入 +500ms 延迟(预发环境、单实例、5% 流量),下单成功率保持在 99.9% 以上,P95 上升幅度 < 100ms(因为库存超时配置为 300ms 且有降级路径)。」
  • 爆炸半径:预发环境、inventory 服务的单个 Pod、网关层只路由预发流量;生产不做本实验。
  • 中止条件:成功率跌破 99.5% 或出现无法下单的持续 1 分钟,自动撤销注入(Chaos Mesh 的 pause + 告警到值班)。
  • 工具与参数:Chaos Mesh NetworkChaos,delay=500ms jitter=50ms,selector 指向 inventory Pod,duration=5m。打库存(同步依赖)而非短信(旁路)——同步依赖的延迟才考验超时与降级机制。
  • 报告发现栏结构:指标曲线(成功率/P95 对比基线)、预期是否成立、未预期现象、行动项(改超时/加降级/修告警)、下次实验建议。

常见陷阱

  1. 没有稳定态假设就开打:结束后说不出「系统变好了还是坏了」;四要素前置。
  2. 中止条件靠人肉:盯盘反应永远慢过自动止血;指标红线自动撤销。
  3. 第一次就上生产:爆炸半径失控;预发 → 灰度 → 生产三级递进。
  4. 只验证「Pod 起来了」不验证用户侧指标:自愈的真相在注入窗口内的错误率里。
  5. 把混沌当一次性活动:系统每次发布都在变化,去年的实验结论今天未必成立;实验配置代码化并定期重跑。

相关阅读

参考与致谢