“生产环境能不能搞故障演练?”
这问题问老板,老板肯定说不行。但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 qdiscadddev eth0 root netem loss100%# 方法3:用iptables阻断端口iptables -A INPUT -p tcp --dport8080-j DROP观察点:
- 负载均衡能否自动摘除故障节点?
- 摘除需要多长时间?
- 客户端能否自动重试到其他节点?
场景二:网络延迟
# 模拟100ms延迟tc qdiscadddev eth0 root netem delay 100ms# 模拟延迟+抖动tc qdiscadddev eth0 root netem delay 100ms 50ms# 模拟丢包tc qdiscadddev eth0 root netem loss10%观察点:
- 超时配置是否合理?
- 熔断器是否触发?
- 是否有雪崩风险?
场景三:CPU/内存压力
# CPU压满stress --cpu8--timeout60# 内存压满stress --vm4--vm-bytes 4G --timeout60# 或者用stress-ng(更强大)stress-ng --cpu0--cpu-method all --timeout60观察点:
- 服务是否被OOM Kill?
- K8s是否自动扩容?
- 限流是否生效?
场景四:磁盘故障
# 模拟磁盘满ddif=/dev/zeroof=/data/bigfilebs=1Gcount=100# 模拟IO慢echo1>/proc/sys/vm/block_dump# 开启IO调试观察点:
- 日志写入失败如何处理?
- 数据库是否会挂?
- 告警是否及时?
场景五:依赖服务故障
# 模拟MySQL故障systemctl stop mysql# 模拟Redis故障redis-cli DEBUG SLEEP30# 模拟第三方API超时# 用mock server返回延迟响应观察点:
- 降级策略是否生效?
- 缓存是否能兜底?
- 用户体验如何?
工具推荐
Chaos Monkey(Netflix)
最早的混沌工程工具,随机kill EC2实例。
ChaosBlade(阿里)
国内用得最多,支持多种故障注入:
# 安装wgethttps://github.com/chaosblade-io/chaosblade/releases/download/v1.7.2/chaosblade-1.7.2-linux-amd64.tar.gztar-xvf chaosblade-1.7.2-linux-amd64.tar.gz# CPU满载./blade create cpu fullload# 网络延迟./blade create network delay --time3000--interface eth0# 进程kill./blade create processkill--process java# 销毁实验./blade destroy<uid>Litmus(K8s专用)
K8s原生的混沌工程平台:
apiVersion:litmuschaos.io/v1alpha1kind:ChaosEnginemetadata:name:nginx-chaosspec:appinfo:appns:defaultapplabel:"app=nginx"chaosServiceAccount:litmus-adminexperiments:-name:pod-deletespec:components:env:-name:TOTAL_CHAOS_DURATIONvalue:"30"Gremlin
商业化产品,界面友好,适合企业。
实战案例
案例:Redis故障演练
目标:验证Redis主节点故障时,服务是否正常。
准备:
- 确认Redis是主从架构
- 确认Sentinel配置正确
- 准备回滚方案
执行:
# 1. 登录Redis主节点redis-cli -h redis-master# 2. 模拟主节点挂掉DEBUG SLEEP60# 或者DEBUG SEGFAULT观察:
# 在Sentinel上观察redis-cli -h sentinel -p26379SENTINEL 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上去观察,比之前用跳板机方便多了。
总结
故障演练的核心:
| 阶段 | 重点 |
|---|---|
| 准备 | 定义稳态、准备回滚、通知相关方 |
| 执行 | 可控破坏、实时监控 |
| 恢复 | 快速回滚、记录现象 |
| 复盘 | 分析问题、制定改进措施 |
从小开始,循序渐进:
- 先在测试环境练手
- 再在预发环境验证
- 最后在生产小流量演练
- 逐步扩大范围
不要怕搞破坏,怕的是不敢面对真正的故障。
有故障演练经验的欢迎交流~