故障演练与混沌工程入门:在生产环境搞破坏

"生产环境能不能搞故障演练?"

这问题问老板,老板肯定说不行。但Netflix、Google都在生产环境搞,而且搞得很凶。

区别在于:有准备的搞破坏叫演练,没准备的叫事故。

为什么要故障演练

真实案例:

双十一前一个月,我们信心满满,觉得系统扛得住。结果当天:

  • Redis主节点挂了,failover花了30秒
  • 这30秒,订单服务疯狂报错
  • 用户看到的是"系统繁忙"

事后复盘:failover我们测过啊?测过,在测试环境。测试环境和生产环境的配置不一样,超时时间不一样,结果就不一样。

从那以后,我们开始在生产环境做故障演练。

混沌工程基本原则

Netflix提出的混沌工程原则:

  1. 建立稳态假设:定义什么是"正常"
  2. 多样化真实世界事件:模拟各种故障
  3. 在生产环境运行:测试环境不够真实
  4. 自动化持续运行:不是一次性的
  5. 最小化爆炸半径:可控的破坏

从小规模开始

第一步:演练环境隔离

不是直接在生产搞,而是先在生产的一小部分搞。


生产流量 (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主节点故障时,服务是否正常。

准备

  1. 确认Redis是主从架构
  2. 确认Sentinel配置正确
  3. 准备回滚方案

执行

# 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%
用户感知

案例:服务限流演练

目标:验证限流配置是否生效。

准备

  1. 确认限流配置(假设QPS限制1000)
  2. 准备压测工具

执行

# 用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上去观察,比之前用跳板机方便多了。

总结

故障演练的核心:

阶段 重点
准备 定义稳态、准备回滚、通知相关方
执行 可控破坏、实时监控
恢复 快速回滚、记录现象
复盘 分析问题、制定改进措施

从小开始,循序渐进:

  1. 先在测试环境练手
  2. 再在预发环境验证
  3. 最后在生产小流量演练
  4. 逐步扩大范围

不要怕搞破坏,怕的是不敢面对真正的故障。


有故障演练经验的欢迎交流~


posted @ 2025-12-23 11:37  花宝宝  阅读(40)  评论(0)    收藏  举报