cover

事故管理:Runbook 與 Post-mortem 模板

流程概覽

flowchart LR
    A[偵測<br/>Detection] --> B[分級<br/>Triage]
    B --> C[應變<br/>Response]
    C --> D[解決<br/>Resolution]
    D --> E[覆盤<br/>Postmortem]
    E --> F[預防<br/>Prevention]
    F -->|持續改善| A

    style A fill:#F44336,color:#fff
    style B fill:#FF9800,color:#fff
    style C fill:#FFC107,color:#000
    style D fill:#4CAF50,color:#fff
    style E fill:#2196F3,color:#fff
    style F fill:#9C27B0,color:#fff

文章概覽

在本篇文章中,您將學習到:

  • 為什麼每一個生產系統都終將面臨故障,差別只在於你準備得多充分
  • 事故的完整生命週期:從偵測到預防的閉環流程
  • 事故嚴重等級(P1-P4)的分類標準與應對時效
  • On-call 輪值制度的設計原則與公平性考量
  • Runbook 的撰寫規範與常見範例
  • Blameless Post-mortem 的文化建設與實務範本
  • 5 Whys 根因分析法的應用
  • 災難復原演練(DR Drill)的執行方式

引言:每個生產系統都會故障,差別在於你準備得多好

在軟體工程的世界裡,有一個不變的真理:生產環境一定會出問題。 無論你的程式碼多麼嚴謹、測試覆蓋率多麼高、基礎設施多麼冗餘,故障終將發生。硬碟會壞、網路會斷、第三方服務會停擺、人為操作會出錯。

差別不在於故障會不會發生,而在於:

  • 你能多快發現問題? 是使用者打電話來抱怨,還是你的監控系統在使用者受到影響之前就發出告警?
  • 你能多快解決問題? 是手忙腳亂地 Google 搜尋解法,還是打開預先準備好的 Runbook 按步驟執行?
  • 你能從故障中學到什麼? 是責怪犯錯的人然後不了了之,還是透過結構化的 Post-mortem 找出系統性問題並徹底改善?

成熟的工程團隊不會試圖消除所有故障(這是不可能的),而是建立一套完善的事故管理流程,讓團隊在面對故障時能夠冷靜、有序、高效地應對,並從每一次故障中持續學習與改進。


事故生命週期

一個完整的事故管理流程包含六個階段,形成一個持續改善的閉環:

flowchart LR
    A[偵測<br/>Detection] --> B[分級<br/>Triage]
    B --> C[應變<br/>Response]
    C --> D[解決<br/>Resolution]
    D --> E[覆盤<br/>Post-mortem]
    E --> F[預防<br/>Prevention]
    F -->|回饋改善| A

    style A fill:#F44336,color:#fff
    style B fill:#FF9800,color:#fff
    style C fill:#FFC107,color:#000
    style D fill:#4CAF50,color:#fff
    style E fill:#2196F3,color:#fff
    style F fill:#9C27B0,color:#fff
  • 偵測(Detection):透過監控告警、用戶回報或自動化檢測發現異常
  • 分級(Triage):評估影響範圍與嚴重程度,決定應對層級
  • 應變(Response):啟動應對流程,指派事故指揮官,開始排查與修復
  • 解決(Resolution):實施修復措施,確認服務恢復正常
  • 覆盤(Post-mortem):進行根因分析,撰寫事故報告,產出改善行動項目
  • 預防(Prevention):執行行動項目,更新 Runbook,改善監控與告警

每一次故障都是改善系統的機會。這個閉環的關鍵在於最後一步(預防)的輸出會反饋到第一步(偵測),讓系統的可靠性隨著時間不斷提升。


核心概念

事故嚴重等級(Severity Levels)

並非所有事故都同等重要。明確的嚴重等級定義,讓團隊能夠根據影響程度分配適當的資源與關注度。

等級名稱定義範例回應時間更新頻率
P1Critical核心服務完全中斷,大量用戶受影響主資料庫掛掉、全站無法存取、支付系統全面失敗15 分鐘內每 15 分鐘
P2Major核心功能嚴重降級,部分用戶受影響API 回應時間超過 10 秒、部分區域無法登入、搜尋功能異常30 分鐘內每 30 分鐘
P3Minor非核心功能異常,少數用戶受影響推播通知延遲、報表匯出失敗、後台管理某功能錯誤4 小時內每日
P4Low不影響服務的小問題UI 顯示瑕疵、日誌格式錯誤、非關鍵告警誤報下個工作日視需要

嚴重等級的判定應基於以下維度:

  1. 影響範圍:受影響的用戶數量或比例
  2. 業務影響:是否影響核心營收或關鍵業務流程
  3. 資料風險:是否有資料遺失或損毀的風險
  4. 時間敏感度:問題是否會隨時間持續惡化

On-call 輪值制度

On-call 是事故管理的第一道防線。設計良好的 On-call 制度,能確保任何時候都有人能夠回應告警並處理事故。

公平輪值的設計原則:

  • 輪值週期:建議以一週為單位輪值,避免單次 on-call 時間過長造成疲勞
  • 至少兩層:Primary(主要)和 Secondary(備援),Primary 無法回應時自動升級到 Secondary
  • 補休機制:週末或假日的 on-call 值班應給予對等的補休時間
  • 跨時區團隊:如果團隊分布在不同時區,利用 follow-the-sun 模式,讓每個時區只需負責其工作時段
  • 新人保護期:新加入的工程師應有至少 2-4 週的 shadow 期,跟隨資深工程師學習後才正式加入輪值

升級路徑(Escalation Path):

告警觸發
  └─→ On-call Primary(5 分鐘無回應)
        └─→ On-call Secondary(10 分鐘無回應)
              └─→ Team Lead / Engineering Manager(15 分鐘無回應)
                    └─→ VP of Engineering / CTO

以下是一份 On-call 輪值表範本:

# On-call 輪值表 — 2024 Q4
 
## 輪值規則
- 輪值週期:每週一 09:00 至下週一 09:00(UTC+8)
- 回應時間:P1 事故 15 分鐘內、P2 事故 30 分鐘內
- 升級時限:Primary 5 分鐘未回應自動升級到 Secondary
- 補休規則:週末/假日值班可補休等時數
 
## 輪值表
 
| 週次 | 日期範圍 | Primary | Secondary | 備註 |
|------|----------|---------|-----------|------|
| W40 | 09/30 - 10/06 | Alice | Bob | |
| W41 | 10/07 - 10/13 | Bob | Charlie | 國慶連假,加強關注 |
| W42 | 10/14 - 10/20 | Charlie | David | |
| W43 | 10/21 - 10/27 | David | Alice | |
| W44 | 10/28 - 11/03 | Alice | Bob | |
| W45 | 11/04 - 11/10 | Bob | Charlie | |
| W46 | 11/11 - 11/17 | Charlie | David | 雙十一大促,全員待命 |
| W47 | 11/18 - 11/24 | David | Alice | |
 
## 升級路徑
1. Primary On-call
2. Secondary On-call
3. Team Lead:Emily(電話:0912-xxx-xxx)
4. Engineering Manager:Frank(電話:0923-xxx-xxx)
 
## 聯繫方式
- 告警通知管道:PagerDuty → Slack #incidents → 電話
- 事故溝通頻道:Slack #incident-war-room
- 狀態頁面:https://status.example.com

事故指揮官(Incident Commander)

在 P1 或 P2 事故中,必須有一位明確的事故指揮官(Incident Commander, IC)來協調所有應對行動。IC 的角色不是親自動手修復問題,而是統籌全局,確保正確的人在做正確的事

IC 的核心職責:

  1. 宣告事故:確認事故等級,啟動對應的應對流程
  2. 組建應對團隊:根據問題類型召集相關領域的工程師
  3. 任務分派:將排查與修復工作分配給團隊成員,避免重複勞動
  4. 狀態同步:定期(每 15 分鐘)向利害關係人更新進展
  5. 決策裁定:當團隊對修復方案有分歧時,做出最終決定
  6. 記錄時間軸:確保所有關鍵事件和決策都被記錄下來(供 Post-mortem 使用)
  7. 宣告恢復:確認問題已解決,服務恢復正常後,結束事故狀態

IC 輪值建議: IC 通常由資深工程師或 Tech Lead 輪流擔任,與 On-call 輪值獨立排班。在規模較小的團隊中,On-call Primary 可以同時兼任 IC。

事故期間的溝通

事故發生時,清晰的溝通與資訊透明是降低混亂的關鍵。

內部溝通:

  • 開設專屬的事故頻道(例如 #incident-2024-1015-db-outage),所有討論集中在此
  • 避免在多個管道同時討論,造成資訊碎片化
  • IC 定期發送結構化的狀態更新:目前狀況 → 正在做什麼 → 下一步 → 預計恢復時間

外部溝通:

  • 狀態頁面(Status Page):如 Statuspage.io 或自建狀態頁面,讓使用者自行查看服務狀態
  • 社群媒體:在官方 Twitter/X 帳號發布簡短狀態更新
  • 客戶通知:對於企業客戶,透過專屬管道(Slack Connect、Email)進行主動通知
  • 內部利害關係人:透過 Email 或 Slack 通知業務、客服、管理層,提供影響範圍與預計恢復時間

溝通範本 — 狀態更新:

[事故更新 — YYYY-MM-DD HH:MM]
等級:P1
狀態:調查中 / 已識別 / 修復中 / 已解決

摘要:
[簡述目前狀況]

影響範圍:
[受影響的服務/功能/用戶群]

目前行動:
[團隊正在進行的排查或修復工作]

預計恢復時間:
[如可預估則提供,否則說明下次更新時間]

下次更新時間:HH:MM

Runbook:事故處理的操作手冊

什麼是 Runbook?

Runbook 是一份逐步操作指引,記錄了處理特定已知問題的標準流程。它的核心價值在於:

  • 降低 MTTR(Mean Time To Recovery):不需要從頭排查,按照已知步驟快速修復
  • 消除人員依賴:即使最熟悉系統的工程師不在,其他人也能按照 Runbook 處理問題
  • 減少人為錯誤:在壓力下,人容易做出錯誤判斷;有了 Runbook,按步驟執行即可
  • 知識傳承:將團隊累積的實戰經驗系統化地記錄下來

Runbook 的結構

一份好的 Runbook 應該具備以下結構:

# Runbook:[問題標題]
 
## 基本資訊
- **嚴重等級**:P1 / P2 / P3 / P4
- **影響服務**:[受影響的服務名稱]
- **最後更新**:YYYY-MM-DD
- **維護者**:[姓名 / 團隊]
- **相關告警**:[對應的告警規則名稱或 ID]
 
## 症狀(Symptoms)
描述觸發此 Runbook 的症狀,讓 on-call 工程師能快速判斷是否適用。
 
- 告警訊息:`[具體的告警內容]`
- 用戶反映:[用戶可能回報的現象]
- 監控表現:[Grafana dashboard 上的異常指標]
 
## 影響評估(Impact Assessment)
- 受影響的用戶群體
- 受影響的功能
- 是否有資料遺失風險
- 問題是否會持續惡化
 
## 診斷步驟(Diagnosis)
按順序執行以下步驟,找出問題的根因:
 
### 步驟 1:確認服務狀態
```bash
# 檢查服務是否正在執行
kubectl get pods -n production -l app=<service-name>
 
# 查看最近的日誌
kubectl logs -n production <pod-name> --tail=100

步驟 2:檢查依賴服務

# 檢查資料庫連線
psql -h <db-host> -U <user> -d <database> -c "SELECT 1;"
 
# 檢查 Redis 連線
redis-cli -h <redis-host> ping

步驟 3:檢查資源使用狀況

# 檢查 CPU 和 Memory
kubectl top pods -n production -l app=<service-name>
 
# 檢查磁碟空間
df -h

解決步驟(Resolution)

根據診斷結果,選擇對應的修復方案:

情境 A:服務程序崩潰

# 重啟服務
kubectl rollout restart deployment/<service-name> -n production
 
# 確認重啟成功
kubectl rollout status deployment/<service-name> -n production

情境 B:資源不足

# 擴展 Pod 數量
kubectl scale deployment/<service-name> -n production --replicas=<N>

情境 C:需要回滾

# 查看部署歷史
kubectl rollout history deployment/<service-name> -n production
 
# 回滾到上一版本
kubectl rollout undo deployment/<service-name> -n production

驗證(Verification)

修復後,執行以下步驟確認服務已恢復:

  • 服務健康檢查通過:curl -s https://api.example.com/health
  • 錯誤率恢復正常(< 0.1%)
  • 回應時間恢復正常(P99 < 200ms)
  • 告警已自動解除
  • 抽查用戶功能正常

升級條件(Escalation)

如果以上步驟無法解決問題,請升級處理:

  • 30 分鐘內無法恢復 → 通知 Team Lead
  • 1 小時內無法恢復 → 通知 Engineering Manager
  • 涉及資料遺失 → 立即通知 CTO + 法務

參考資料

  • [系統架構圖連結]
  • [相關的 Post-mortem 報告]
  • [相關的設計文件]

#### 常見 Runbook 範例

以下是幾個生產環境中最常見的問題情境,每個團隊都應該預先準備對應的 Runbook:

**1. 服務無法存取(Service Down)**

主要症狀:健康檢查失敗、HTTP 5xx 錯誤率飆升、使用者回報無法連線。

診斷方向:
- 檢查 Pod / Container 狀態,是否有 OOMKilled 或 CrashLoopBackOff
- 檢查最近是否有部署變更(git log、deployment history)
- 確認上游依賴(資料庫、快取、第三方 API)是否正常
- 查看應用程式日誌中的 error / fatal 訊息

常見修復:重啟服務、回滾到上一版本、擴展 Pod 數量。

**2. 磁碟空間滿(Disk Full)**

主要症狀:磁碟使用率告警(> 90%)、服務開始回傳 I/O 錯誤、資料庫無法寫入。

診斷方向:
- `df -h` 確認哪個磁碟分區已滿
- `du -sh /var/log/*` 找出佔用空間最大的目錄
- 檢查日誌輪替(logrotate)是否正常運作
- 確認是否有異常的大檔案或未清理的暫存檔

常見修復:清理過期日誌、刪除暫存檔、擴展磁碟容量、修復 logrotate 設定。

**3. 資料庫連線耗盡(Database Connection Exhausted)**

主要症狀:應用程式回傳 "too many connections" 錯誤、新請求被拒絕、連線池等待超時。

診斷方向:
- `SELECT count(*) FROM pg_stat_activity;` 查看當前連線數
- `SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction';` 檢查是否有長時間未釋放的連線
- 檢查應用程式的連線池設定(pool size、idle timeout)
- 確認是否有慢查詢佔用連線過久

常見修復:終止 idle 連線、調整連線池設定、優化慢查詢、增加最大連線數。

**4. SSL/TLS 憑證過期(Certificate Expired)**

主要症狀:瀏覽器顯示安全警告、HTTPS 連線失敗、API 呼叫回傳 SSL 錯誤。

診斷方向:
- `openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates` 檢查憑證有效期
- 確認自動續約(如 Let's Encrypt / cert-manager)是否正常運作
- 檢查是否有中繼憑證遺失(chain certificate)

常見修復:手動更新憑證、修復自動續約機制、設定憑證到期前 30 天的提醒告警。

---

### Post-mortem:從故障中學習

#### Blameless Post-mortem 文化

Post-mortem 的目的是**從系統層面找出問題並改善**,而不是追究個人責任。如果團隊文化中,犯錯的人會被懲罰,那麼人們就會傾向隱藏錯誤、避免揭露真正的根因,最終導致問題反覆發生。

**Blameless 文化的核心原則:**

1. **人會犯錯,系統不應依賴人不犯錯**:如果一個人為操作失誤能導致嚴重事故,那問題在於系統缺乏足夠的防護機制,而不在於那個人
2. **專注於「如何」而非「誰」**:討論「這件事是如何發生的」和「我們的系統如何讓這件事有可能發生」,而非「是誰做錯的」
3. **鼓勵透明**:讓所有參與者感到安全,願意完整揭露事件經過,包括自己的失誤
4. **錯誤是學習機會**:每一次故障都讓我們更了解系統的弱點,這些知識極其寶貴

**實務做法:**
- Post-mortem 文件中不提及具體人名,使用角色描述(如「on-call 工程師」、「部署者」)
- Post-mortem 會議由非直接相關的人主持,確保客觀
- 將重點放在行動項目(Action Items)上——**我們要改變什麼,讓同樣的問題不再發生?**

#### Post-mortem 模板

以下是一份完整的 Post-mortem 報告範本:

```markdown
# Post-mortem 報告:[事故標題]

## 基本資訊
- **事故編號**:INC-YYYY-NNNN
- **事故等級**:P1 / P2 / P3
- **事故日期**:YYYY-MM-DD
- **事故時長**:X 小時 Y 分鐘
- **事故指揮官**:[角色]
- **報告撰寫人**:[角色]
- **報告日期**:YYYY-MM-DD

## 摘要(Summary)
以 2-3 句話簡述發生了什麼事、影響範圍、以及如何解決。

> 範例:2024 年 10 月 15 日 14:00-16:30,由於資料庫主節點的磁碟空間耗盡,
> 導致核心 API 服務無法處理寫入請求,約 60% 的用戶在此期間無法完成訂單。
> 問題在清理過期日誌並擴展磁碟容量後解決。

## 影響(Impact)
- **受影響時間**:HH:MM - HH:MM(共 X 分鐘)
- **受影響服務**:[列出受影響的服務]
- **受影響用戶數**:約 XX,XXX 人(佔總用戶 XX%)
- **業務影響**:
  - 訂單流失:約 XXX 筆
  - 營收損失:約 $XXX
  - SLA 違約:是 / 否
- **資料影響**:是否有資料遺失或損毀

## 時間軸(Timeline)
所有時間以 UTC+8 表示。

| 時間 | 事件 |
|------|------|
| 13:45 | 磁碟使用率告警觸發(> 90%) |
| 13:50 | On-call 工程師收到告警,開始調查 |
| 14:00 | 資料庫主節點磁碟 100%,開始拒絕寫入 |
| 14:05 | API 錯誤率開始飆升,健康檢查失敗 |
| 14:10 | 升級為 P1 事故,指派事故指揮官 |
| 14:15 | 開設 #incident-2024-1015-db-disk 頻道 |
| 14:20 | 識別根因:未清理的慢查詢日誌佔用 50GB |
| 14:30 | 開始清理過期日誌 |
| 14:45 | 磁碟空間釋放至 60%,資料庫恢復寫入 |
| 15:00 | API 服務恢復正常,錯誤率降至基準線 |
| 15:30 | 提交磁碟擴展申請,容量從 100GB 增至 200GB |
| 16:00 | 磁碟擴展完成 |
| 16:30 | 確認所有指標穩定,宣告事故結束 |

## 根因分析(Root Cause Analysis)
### 直接原因
資料庫主節點的慢查詢日誌(slow query log)未設定 logrotate,
持續累積至佔滿磁碟空間。

### 根本原因
1. 資料庫伺服器的 logrotate 設定在上次遷移時遺漏
2. 磁碟使用率的告警門檻設為 90%,留給反應的時間不足
3. 沒有針對磁碟增長速率的趨勢告警

### 5 Whys 分析
1. **為什麼服務中斷?** → 資料庫無法寫入
2. **為什麼資料庫無法寫入?** → 磁碟空間已滿
3. **為什麼磁碟空間會滿?** → 慢查詢日誌持續增長未被清理
4. **為什麼日誌未被清理?** → logrotate 設定遺漏
5. **為什麼 logrotate 設定會遺漏?** → 伺服器遷移的 checklist 中未包含日誌管理的驗證項目

## 經驗教訓(Lessons Learned)

### 做得好的地方
- 告警在服務完全中斷前 15 分鐘就觸發了
- On-call 工程師在 5 分鐘內開始回應
- 根因識別迅速(20 分鐘內完成)
- 團隊溝通順暢,利害關係人及時收到通知

### 需要改善的地方
- 磁碟告警門檻 90% 太高,反應時間不足
- 沒有標準化的伺服器遷移 checklist
- 缺乏磁碟增長趨勢的預測性告警

### 意外收穫
- 發現另外兩台伺服器也有相同的 logrotate 遺漏問題,及時修復

## 行動項目(Action Items)

| # | 行動項目 | 優先級 | 負責人 | 到期日 | 狀態 |
|---|----------|--------|--------|--------|------|
| 1 | 所有 DB 伺服器加入 logrotate 設定 | P0 | DBA 團隊 | 10/18 | 完成 |
| 2 | 磁碟告警門檻調整為 75%,增加 60% 預警 | P0 | SRE 團隊 | 10/18 | 完成 |
| 3 | 新增磁碟增長速率的趨勢告警 | P1 | SRE 團隊 | 10/25 | 進行中 |
| 4 | 建立伺服器遷移標準 checklist | P1 | Infra 團隊 | 10/31 | 待開始 |
| 5 | 撰寫「磁碟空間滿」Runbook | P1 | On-call 團隊 | 10/25 | 進行中 |
| 6 | 排程季度性的磁碟容量審查 | P2 | SRE 團隊 | 11/15 | 待開始 |

## 附錄
- [相關的 Grafana Dashboard 截圖]
- [告警記錄連結]
- [Slack 事故頻道存檔]

5 Whys 根因分析法

5 Whys 是一種簡單但極其有效的根因分析技術。透過連續追問「為什麼」,從表面症狀逐步深入到根本原因。

使用原則:

  1. 從事實出發:第一個「為什麼」應該基於可觀察的事實,而非假設
  2. 不要太早停下:如果答案仍然是技術層面的,繼續往下追問;真正的根因通常是流程或文化層面的
  3. 不要分叉太多:每一層選擇最主要的原因繼續追問,避免發散成一棵樹
  4. 每一層都要有證據:「因為 X」這個回答需要有日誌、指標或其他證據支持
  5. 通常 3-5 層就夠了:不需要機械式地一定要問 5 次,重點是找到可以改善的根因

範例:API 回應時間異常

  1. 為什麼 API 回應時間超過 5 秒? → 資料庫查詢耗時過久
  2. 為什麼資料庫查詢耗時過久? → 某張表缺少必要的索引,進行了全表掃描
  3. 為什麼會缺少索引? → 新的查詢模式在 feature 開發時被加入,但沒有對應的索引
  4. 為什麼沒有建立對應的索引? → Code Review 流程中沒有包含資料庫查詢效能的檢查項目
  5. 為什麼 Code Review 沒有這個檢查項目? → 團隊缺乏資料庫效能相關的 Review checklist

行動項目:建立 Code Review checklist,加入「資料庫查詢效能」檢查項,要求所有新增的查詢都必須附上 EXPLAIN 分析結果。

行動項目的追蹤與跟進

Post-mortem 最常見的失敗模式是:報告寫完了,行動項目沒有人追蹤,然後同樣的問題再次發生。

確保行動項目落地的做法:

  1. 每個行動項目都有明確的負責人和到期日:不寫「團隊一起做」,而是指定一個具體的負責人
  2. 行動項目進入正式的工作追蹤系統:將行動項目建立為 Jira ticket 或 GitHub Issue,而非只存在於 Post-mortem 文件中
  3. 定期檢視進度:在每週的團隊會議中花 5 分鐘回顧未完成的行動項目
  4. 設定完成標準:每個行動項目應有明確的「完成」定義,而非模糊的「改善 XX」
  5. 季度回顧:每季度統計行動項目的完成率,識別系統性的執行瓶頸

事故嚴重等級分類表

以下整理一份更完整的分類參考表,可以直接作為團隊的分級標準使用:

維度P1 (Critical)P2 (Major)P3 (Minor)P4 (Low)
用戶影響> 50% 用戶受影響10-50% 用戶受影響< 10% 用戶受影響幾乎無感
功能影響核心功能完全不可用核心功能嚴重降級非核心功能異常細微問題
營收影響直接營收損失間接營收影響潛在營收影響無營收影響
資料風險資料遺失或損毀資料可能不一致低風險無風險
回應要求立即、全員待命30 分鐘內、相關團隊工作時間處理排入 backlog
溝通頻率每 15 分鐘更新每 30 分鐘更新每日更新視需要
需要 IC
需要 Post-mortem是(必須)是(必須)建議

災難復原演練(DR Drill)

紙上談兵的 Runbook 和事故應對流程,只有在實際演練過後才知道是否有效。災難復原演練(Disaster Recovery Drill)是定期驗證團隊事故應對能力的必要措施。

演練頻率與類型

類型頻率說明範例
桌面演練(Tabletop)每月團隊坐在一起,口頭走過事故情境「假設主資料庫掛了,我們的流程是什麼?」
模擬演練(Simulation)每季在 staging 環境中模擬真實故障手動關閉一個服務,測試告警與應對流程
混沌工程(Chaos Engineering)持續性在生產環境中注入可控的故障使用 Chaos Monkey 隨機終止 Pod

季度演練流程

  1. 規劃(演練前 2 週)

    • 選定演練情境(例如:資料庫故障轉移、多區域切換、全站回滾)
    • 定義成功標準(例如:RTO < 30 分鐘、RPO < 5 分鐘)
    • 通知參與人員與利害關係人
    • 準備觀察指標與記錄模板
  2. 執行(演練當天)

    • 在預定時間注入故障
    • On-call 團隊按照標準流程應對
    • 記錄所有關鍵事件的時間點
    • 觀察者記錄流程中的問題與改善點
  3. 覆盤(演練後 1 週內)

    • 比對實際表現與成功標準
    • 識別 Runbook 中的錯誤或不足
    • 評估告警的及時性與準確性
    • 更新 Runbook 與應對流程
    • 將改善項目納入下一個 Sprint

演練的常見陷阱

  • 事先通知太多人:如果所有人都知道「今天下午 3 點會演練」,就無法真實測試應對速度
  • 只演練簡單場景:永遠只模擬「重啟服務」這種簡單操作,無法發現複雜情境下的問題
  • 演練後沒有跟進:演練發現了問題,但沒有人去修復,下次演練又遇到同樣的問題

常見問題與風險

在建立事故管理流程的過程中,團隊常會遇到以下挑戰:

問題一:Runbook 過時

症狀:On-call 工程師打開 Runbook,發現裡面的指令已經不適用——服務已經遷移到新的叢集、指令中的 hostname 已經改了、依賴的工具已經被替換。

解法

  • 將 Runbook 的維護責任明確指派給服務擁有者
  • 每次事故處理後,如果發現 Runbook 有誤或不足,作為 Post-mortem 的行動項目進行更新
  • 設定季度性的 Runbook 審查週期,確認所有 Runbook 仍然有效
  • 在 Runbook 中標記最後驗證日期,超過 3 個月未驗證的 Runbook 標記為「需要審查」

問題二:Post-mortem 行動項目未跟進

症狀:Post-mortem 會議開得很熱烈,行動項目列了一大堆,但三個月後回頭看,大部分都沒有完成。然後同樣的問題再次發生。

解法

  • 行動項目必須建立在工作追蹤系統中(Jira / Linear / GitHub Issues),而非僅存在於文件裡
  • 指派具體的負責人和到期日,不接受「大家一起做」這種模糊分配
  • 在每週的工程團隊週會中花 5 分鐘回顧未完成的 Post-mortem 行動項目
  • 追蹤行動項目完成率作為團隊的 KPI 之一

問題三:告警疲勞(Alert Fatigue)

症狀:告警太多、太頻繁、太多誤報,導致 on-call 工程師開始忽略告警。當真正的問題發生時,反應速度嚴重下降,甚至完全沒有注意到。

解法

  • 定期審查告警規則,刪除已經不適用的告警
  • 設定合理的告警門檻,避免過於敏感的告警
  • 區分「需要立即處理」的告警和「僅供觀察」的通知,使用不同的通知管道
  • 追蹤告警的信噪比(signal-to-noise ratio),目標是 actionable alert 比例 > 80%
  • 如果一個告警連續一個月都沒有需要實際處理的情況,考慮降級或刪除

問題四:事故處理過度依賴特定人員

症狀:每次出事都是同一個人在處理,其他人只能在旁邊看。這個人一旦休假或離職,團隊就陷入恐慌。

解法

  • 強制輪值:每個人都必須排入 On-call 輪值,不允許永遠由同一人值班
  • Pair On-call:新加入輪值的工程師先與資深工程師配對值班 2-4 週
  • 記錄所有事故處理過程,轉化為 Runbook,將個人經驗系統化
  • 定期進行 DR Drill,讓所有人都有實戰經驗

問題五:缺乏事故管理工具

症狀:事故發生時,在 Slack 群組中混亂地討論,沒有統一的事故追蹤、沒有自動化的升級流程、沒有結構化的狀態更新。

解法

  • 導入事故管理平台(PagerDuty、OpsGenie、incident.io)
  • 設定自動化的升級流程(告警 → Slack 通知 → 電話 → 自動升級)
  • 建立事故模板,讓事故的建立和追蹤有標準化的格式
  • 與 ChatOps 整合,在 Slack 中直接管理事故生命週期

小結

事故管理不是一個一次性的專案,而是一個持續改善的過程。它的核心目標是:

指標說明改善方向
MTTD(Mean Time To Detect)從故障發生到被偵測的時間改善監控與告警的覆蓋率和靈敏度
MTTR(Mean Time To Recovery)從故障偵測到服務恢復的時間完善 Runbook、自動化修復
MTBF(Mean Time Between Failures)兩次故障之間的間隔時間落實 Post-mortem 行動項目、預防性維護

建立成熟的事故管理文化需要時間,但回報是巨大的。當你的團隊能夠在凌晨三點被告警叫醒後,冷靜地打開 Runbook、按步驟排查修復、在 30 分鐘內恢復服務,然後隔天用一場 Blameless Post-mortem 找出根因並改善系統——你就知道,這個團隊已經準備好面對任何挑戰了。

記住:目標不是消除所有故障,而是建立一個能夠優雅地處理故障、並從每次故障中變得更強的系統與團隊。


Proto 實踐對照

Proto 中的事故管理準備:Django Proto 內建結構化 JSON 日誌(方便 EFK 收集)和 PII Masking;Infra 層的 告警 ChatOps 整合了 Slack/Discord 通知。事故發生時,這些基礎建設讓團隊能快速定位問題。


延伸閱讀

  • Alerts & ChatOps:如何設計有效的告警策略,以及透過 ChatOps 提升事故回應效率
  • Backup & DR:備份策略與災難復原計畫的完整指南
  • Metrics & Monitoring:監控系統的設計原則,為事故偵測提供堅實的基礎