"生產環境能不能搞故障演練?"

這問題問老闆,老闆肯定説不行。但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. 逐步擴大範圍

不要怕搞破壞,怕的是不敢面對真正的故障。


有故障演練經驗的歡迎交流~