"生產環境能不能搞故障演練?"
這問題問老闆,老闆肯定説不行。但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上去觀察,比之前用跳板機方便多了。
總結
故障演練的核心:
|
階段
|
重點
|
|
準備
|
定義穩態、準備回滾、通知相關方
|
|
執行
|
可控破壞、實時監控
|
|
恢復
|
快速回滾、記錄現象
|
|
覆盤
|
分析問題、制定改進措施
|
從小開始,循序漸進:
- 先在測試環境練手
- 再在預發環境驗證
- 最後在生產小流量演練
- 逐步擴大範圍
不要怕搞破壞,怕的是不敢面對真正的故障。
有故障演練經驗的歡迎交流~