混沌工程:故意破坏生产环境(从此不再出现故障)
Source: Dev.to
2 AM 值班电话的故事
现在是凌晨 2:07。
🚨 生产宕机 – 错误率高
所有检查项都已勾选,系统标称“高度可用”,却只有一个节点挂掉了。
那天晚上教会我们一个痛苦的真理:纸面上看起来可靠的系统,并不一定能在真实故障中存活。
什么是混沌工程?
混沌工程 是一种有意破坏系统,以了解系统在故障下行为的实践。
通俗来说:在可控的窗口期内制造受控的故障——最好在安全时段——让生产环境不在凌晨 2 点给你上课。
为什么会有它
- 现代系统是分布式的。
- 故障是不可避免的。
- 人类不擅长预测边缘情况。
混沌工程接受现实,而不是与之抗争。
传统测试的局限性
| 传统测试假设… | 现实情况… |
|---|---|
| 依赖项表现正常 | 数据库会变慢,而不仅仅是崩溃 |
| 网络可靠 | 网络会撒谎,延迟会突增 |
| 延迟可预测 | 第三方 API 随机超时 |
| 部分故障不会级联 | 分布式系统会以创意的方式失效 |
大多数宕机源于 未知的未知,而不是代码 bug。混沌工程在用户遇到之前就揭示这些未知。
定义“健康”系统
- 请求成功率
- 延迟分位数
- 错误预算
- 业务 KPI
没有明确的稳态指标,你只是在盲目破坏。
真实的故障类型(非模拟)
- 杀掉 pod
- 添加延迟
- 中断网络调用
- 限制 CPU
这些操作 在生产环境 中使用真实流量、真实数据和真实混沌——逐步进行,在安全窗口期内,并配有回滚计划和预定的停机时间。
实验示例
# Kill a pod
kubectl delete pod payment-service-xyz
- 在服务之间添加 500 ms 延迟
- 丢弃 10 % 的数据包
暴露出的问题: 重试风暴、超时配置错误、数据库变慢、Redis 不可用、第三方 500 错误、CPU 限流、内存压力、磁盘已满等。
如何运行混沌实验
- 挑选关键服务
- 定义稳态指标(成功率、延迟、错误预算)
- 在非生产环境开始
- 杀掉单个 pod
- 观察一切
- 修复薄弱环节
- 重复并扩大
- 在低流量时搬到生产
- 给依赖添加延迟
- 模拟数据库慢速
小规模、受控的混沌胜过根本没有混沌。
常见混沌工具
- Chaos Monkey – 最早的混沌工具
- LitmusChaos – 原生 Kubernetes 开源工具
- Gremlin – 可控的企业级混沌平台
- AWS FIS – 原生 AWS 故障注入服务
工具本身不等同于混沌工程;思维方式才是关键。
示例场景(Kubernetes + Spring Boot)
- 技术栈: Java Spring Boot 微服务、Kubernetes(EKS)、已启用 HPA、Redis 缓存、PostgreSQL 数据库
- 混沌操作: 在高峰流量期间杀掉 50 % 的 pod
观察到的故障:
- 连接池耗尽
- 数据库被猛烈重试
- 延迟冲破 SLA
- 没有断路器,重试过于激进,超时配置不佳
新增的缓解措施:
- 引入 Resilience4j(断路器、调优重试与超时)
- 改进就绪探针
结果: 系统经受住了混沌——证明负责任地使用混沌工程是有效的。
混沌工程的原则
- 假设驱动 – 以对稳态的明确假设为起点。
- 可测量 – 在实验前、期间和之后收集指标。
- 可回滚 – 确保能够快速恢复。
- 有目的的随机性 – 避免仅仅是“随意破坏”,那只是糟糕的运维。
你需要完善的监控、便捷的回滚、错误预算,以及懂系统的值班团队。没有可观测性,混沌只会产生噪音。
好处
- 减少生产宕机
- 加快事故响应
- 部署更安全
- 系统设计更优
- 值班工程师更有信心
你不再是“希望”系统能正常工作,而是知道它能。
入门指南
- 选择低风险目标(例如非关键微服务)。
- 定义稳态指标(成功率、延迟、错误预算)。
- 运行小规模实验(杀掉一个 pod、添加延迟)。
- 观察、学习、迭代。
逐步扩大范围,并在低流量窗口期将实验迁移到生产。
结束语
如果你今天在生产系统里杀掉了一个东西,首先会崩溃的是什么?
在评论区留下你的想法、战场故事或疑问——让我们在值班铃再次响起之前相互学习。