故障演练与混沌工程入门:在生产环境搞破坏
"生产环境能不能搞故障演练?"
这问题问老板,老板肯定说不行。但Netflix、Google都在生产环境搞,而且搞得很凶。
区别在于:有准备的搞破坏叫演练,没准备的叫事故。
为什么要故障演练
真实案例:
双十一前一个月,我们信心满满,觉得系统扛得住。结果当天:
- Redis主节点挂了,failover花了30秒
- 这30秒,订单服务疯狂报错
- 用户看到的是"系统繁忙"
事后复盘:failover我们测过啊?测过,在测试环境。测试环境和生产环境的配置不一样,超时时间不一样,结果就不一样。
从那以后,我们开始在生产环境做故障演练。
混沌工程基本原则
Netflix提出的混沌工程原则:
- 建立稳态假设:定义什么是"正常"
- 多样化真实世界事件:模拟各种故障
- 在生产环境运行:测试环境不够真实
- 自动化持续运行:不是一次性的
- 最小化爆炸半径:可控的破坏
从小规模开始
第一步:演练环境隔离
不是直接在生产搞,而是先在生产的一小部分搞。
生产流量 (100%)
│
├── 正常服务 (99%)
│
└── 演练服务 (1%) ← 在这里搞破坏
用流量染色把1%的请求导到演练环境。
### 第二步:定义稳态指标
什么算正常:
```yaml
稳态指标:
- 错误率 < 0.1%
- P99延迟 < 500ms
- 可用性 > 99.9%
- 订单成功率 > 99%
演练过程中超过这些阈值就立即回滚。
第三步:准备回滚方案
# 演练开始前的checklist
□ 回滚脚本准备好了吗?
□ 值班人员到位了吗?
□ 监控大盘打开了吗?
□ 用户通知发了吗?(可选)
常见故障场景
场景一:服务节点故障
模拟一个服务节点挂掉。
# 方法1:直接kill进程
kill -9 $(pgrep -f "java.*order-service")
# 方法2:用tc模拟网络不通
tc qdisc add dev eth0 root netem loss 100%
# 方法3:用iptables阻断端口
iptables -A INPUT -p tcp --dport 8080 -j DROP
观察点:
- 负载均衡能否自动摘除故障节点?
- 摘除需要多长时间?
- 客户端能否自动重试到其他节点?
场景二:网络延迟
# 模拟100ms延迟
tc qdisc add dev eth0 root netem delay 100ms
# 模拟延迟+抖动
tc qdisc add dev eth0 root netem delay 100ms 50ms
# 模拟丢包
tc qdisc add dev eth0 root netem loss 10%
观察点:
- 超时配置是否合理?
- 熔断器是否触发?
- 是否有雪崩风险?
场景三:CPU/内存压力
# CPU压满
stress --cpu 8 --timeout 60
# 内存压满
stress --vm 4 --vm-bytes 4G --timeout 60
# 或者用stress-ng(更强大)
stress-ng --cpu 0 --cpu-method all --timeout 60
观察点:
- 服务是否被OOM Kill?
- K8s是否自动扩容?
- 限流是否生效?
场景四:磁盘故障
# 模拟磁盘满
dd if=/dev/zero of=/data/bigfile bs=1G count=100
# 模拟IO慢
echo 1 > /proc/sys/vm/block_dump # 开启IO调试
观察点:
- 日志写入失败如何处理?
- 数据库是否会挂?
- 告警是否及时?
场景五:依赖服务故障
# 模拟MySQL故障
systemctl stop mysql
# 模拟Redis故障
redis-cli DEBUG SLEEP 30
# 模拟第三方API超时
# 用mock server返回延迟响应
观察点:
- 降级策略是否生效?
- 缓存是否能兜底?
- 用户体验如何?
工具推荐
Chaos Monkey(Netflix)
最早的混沌工程工具,随机kill EC2实例。
ChaosBlade(阿里)
国内用得最多,支持多种故障注入:
# 安装
wget https://github.com/chaosblade-io/chaosblade/releases/download/v1.7.2/chaosblade-1.7.2-linux-amd64.tar.gz
tar -xvf chaosblade-1.7.2-linux-amd64.tar.gz
# CPU满载
./blade create cpu fullload
# 网络延迟
./blade create network delay --time 3000 --interface eth0
# 进程kill
./blade create process kill --process java
# 销毁实验
./blade destroy <uid>
Litmus(K8s专用)
K8s原生的混沌工程平台:
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
name: nginx-chaos
spec:
appinfo:
appns: default
applabel: "app=nginx"
chaosServiceAccount: litmus-admin
experiments:
- name: pod-delete
spec:
components:
env:
- name: TOTAL_CHAOS_DURATION
value: "30"
Gremlin
商业化产品,界面友好,适合企业。
实战案例
案例:Redis故障演练
目标:验证Redis主节点故障时,服务是否正常。
准备:
- 确认Redis是主从架构
- 确认Sentinel配置正确
- 准备回滚方案
执行:
# 1. 登录Redis主节点
redis-cli -h redis-master
# 2. 模拟主节点挂掉
DEBUG SLEEP 60
# 或者
DEBUG SEGFAULT
观察:
# 在Sentinel上观察
redis-cli -h sentinel -p 26379
SENTINEL master mymaster
# 看failover日志
tail -f /var/log/redis/sentinel.log
结果记录:
| 指标 | 预期 | 实际 |
|---|---|---|
| Failover时间 | <10s | 8s |
| 服务错误率 | <5% | 3.2% |
| 用户感知 | 无 | 无 |
案例:服务限流演练
目标:验证限流配置是否生效。
准备:
- 确认限流配置(假设QPS限制1000)
- 准备压测工具
执行:
# 用wrk发压
wrk -t10 -c200 -d30s http://service/api/test
观察:
- 监控QPS是否稳定在1000左右
- 超过部分是否返回429
- 被限流的请求日志
演练流程规范
演练前
## 演练申请单
- 演练名称:Redis主从切换演练
- 演练时间:2024-12-23 14:00-15:00
- 影响范围:订单服务可能有短暂不可用
- 回滚方案:手动切回原主节点
- 值班人员:张三(运维)、李四(开发)
- 审批人:王五
## Checklist
□ 演练方案已评审
□ 回滚脚本已验证
□ 监控大盘已准备
□ 相关方已通知
演练中
## 演练记录
14:00 开始演练
14:02 执行故障注入
14:02 发现主节点不可用
14:10 Sentinel触发failover
14:11 新主节点选举完成
14:12 服务恢复正常
14:15 演练结束
## 异常记录
- 14:03-14:10 订单服务错误率上升至5%
- 14:05 触发错误率告警
演练后
## 演练总结
### 问题
1. Failover时间过长(8s),预期5s
2. 错误率峰值5%,预期3%
### 原因
1. Sentinel down-after-milliseconds配置为5000ms
2. 客户端重试间隔配置不合理
### 改进措施
1. 调整Sentinel配置
2. 优化客户端重试策略
### 后续计划
- 下周再次演练验证
远程协作
我们几个研发在不同城市,演练的时候需要同时看多台服务器的状态。
用星空组网把相关服务器组到一个网络里后,大家都能直接SSH上去观察,比之前用跳板机方便多了。
总结
故障演练的核心:
| 阶段 | 重点 |
|---|---|
| 准备 | 定义稳态、准备回滚、通知相关方 |
| 执行 | 可控破坏、实时监控 |
| 恢复 | 快速回滚、记录现象 |
| 复盘 | 分析问题、制定改进措施 |
从小开始,循序渐进:
- 先在测试环境练手
- 再在预发环境验证
- 最后在生产小流量演练
- 逐步扩大范围
不要怕搞破坏,怕的是不敢面对真正的故障。
有故障演练经验的欢迎交流~

浙公网安备 33010602011771号