混沌工程如何验证高可用?
简化版
混沌工程先定义可量化的稳态假设,再在受控爆炸半径内注入真实故障,观察系统是否仍满足 SLO,并用证据修正设计和 Runbook。 它不是随机“拔网线”:必须有前置检查、停止条件、回滚路径、审计和逐级扩大流程。
详细版
实验从风险模型出发,例如实例宕机、网络延迟、依赖超时、磁盘满或可用区失联。先在测试环境验证注入器,再从单实例、非核心流量、单可用区逐级扩展。稳态指标至少包括核心成功率、P99、错误预算、积压和数据一致性。
假设平时支付成功率 99.99%,实验目标是在杀掉一个实例后仍不低于 99.9%,P99 不超过 800ms,5 分钟内副本恢复。任一护栏越界立即自动停止注入并恢复。实验结束要核对隐藏后果,如重试放大、缓存雪崩、数据缺口和告警是否准确触达。
完整版教学
一、从稳态而不是故障动作开始
“杀一个 Pod”只是手段,实验问题应是“失去一个实例时,核心链路还能否维持目标”。稳态用用户可感知指标描述,例如有效成功率、延迟、订单一致性,而不是只看进程存活。没有稳态,就无法判断实验是成功还是仅仅没有报警。
记忆钩子:先写出系统应该守住什么,再决定破坏什么。
二、形成可证伪的假设
给定:订单服务 6 个实例,任一实例突然退出
预期:成功率 >= 99.9%,P99 <= 800ms
恢复:60s 内摘除故障实例,5min 内补足副本
护栏:错误率 > 1% 持续 30s 立即终止
假设必须包含故障、影响范围、业务指标和时间界限。“系统应该没问题”无法验收,也无法指导自动停止。
三、故障模型要覆盖依赖链
| 故障 | 注入方式 | 主要验证点 |
|---|---|---|
| 进程退出 | kill/container stop | 摘流和重建 |
| 网络延迟/丢包 | tc/netem | 超时、重试、熔断 |
| 磁盘满 | 限额或故障盘 | WAL、只读保护 |
| 依赖 5xx | 代理故障注入 | 降级语义 |
| AZ 隔离 | 网络策略/流量切断 | 仲裁与剩余容量 |
优先选择真实事故和架构假设对应的故障,而不是为了工具覆盖率制造花哨场景。
四、控制爆炸半径
实验按环境、租户、实例和时长设边界。首次只针对一个非核心实例、1% 白名单流量并限制 2 分钟;验证通过后才扩大。注入控制面应与被测系统故障域隔离,避免系统异常时无法撤销实验。
自动停止条件比人工盯屏更可靠。除了错误率,还可用支付金额差异、积压增长和副本不足数作护栏。高风险实验需要双人审批和业务低峰窗口。
五、用数字观察级联效应
正常流量 2000 QPS,每个请求最多重试 2 次。注入 20% 超时后,如果这 400 个失败请求都固定再尝试 2 次,额外流量上限就是 2000×20%×2=800 QPS;如果仅失败的重试请求才进入下一轮且每轮仍有 20% 超时,期望额外流量则是 400+80=480 QPS。两种策略的放大量不同,都可能使健康实例过载,因此实验不仅验证最终成功率,还要验证实际重试策略、线程池水位和熔断时间。
若实例摘除需 30 秒,流量均衡需再 20 秒,那么前 50 秒的错误曲线应符合预期。只看实验结束后的平均成功率会掩盖最危险窗口。
六、实验后的闭环
先停止注入并确认系统回到稳态,再核对数据一致性、队列、缓存和容量。记录假设、时间线、实际指标、触发告警、人工动作和未预期现象。失败实验不是坏结果,它证明了假设不成立;真正失败是没有形成修复项。
修复后要复现实验,防止“改了配置”就关闭问题。实验模板进入周期任务,但生产自动化仍需限频、变更冻结感知和 owner 确认。
七、常见误区与追问
- 误区:混沌工程就是随机制造故障。 它是围绕稳态假设的受控实验。
- 误区:服务没挂就算实验通过。 用户 SLO、数据和恢复时间都要达标。
- 误区:生产实验不需要回滚,因为故障会自动结束。 注入器、路由和数据副作用都需明确恢复。
- 误区:一次成功证明系统永久可靠。 代码、配置和流量持续变化,需要周期复验。
- 追问:先在测试环境还是生产? 注入器先在测试验证,但真实容量与依赖问题最终需受控生产实验。
- 追问:如何选实验优先级? 按事故历史、核心链路、单点假设和风险收益排序。
- 追问:实验导致真实事故怎么办? 自动护栏止损、执行回滚 Runbook,并按事故同等级复盘。
八、加强记忆
混沌实验按“稳态—假设—注入—护栏—观察—复盘—复验”推进。故障动作必须对应架构风险,范围从小到大,结果同时看用户指标、资源放大和数据正确性。最终目标不是证明系统不会坏,而是证明它按预期降级和恢复。