事故覆盤模板:API 故障覆盤怎麼寫,時間線怎麼用資料還原
一份能用的事故覆盤模板,核心是六個部分:摘要、影響、時間線、根因、促成因素、行動項(下面的模板另加了一節“做得好的地方”)。容易寫虛的是其中兩塊:時間線要用監控資料核對,不能靠回憶拼;上游服務(比如某家 AI 模型 API)出故障時,覆盤物件要換成“我們自己的應對”。下面先給可複製的模板,再逐段講怎麼寫實。
為什麼很多覆盤寫完沒人看?
常見的問題有三個:
- 時間線是事後憑記憶補的,“大約 3 點左右發現異常”,沒人能複查。
- 根因寫成“上游服務不穩定”,然後就沒有下文,行動項是“加強監控”。
- 影響只寫“部分使用者受影響”,沒有請求數、失敗率或時長。
覆盤的價值在於下一次少花時間。所以每一句都應該能回答:證據在哪?下次能不能更早發現、更快恢復?
中文事故覆盤模板(可直接複製)
# 事故覆盤:<一句話描述現象>,<日期>
狀態:草稿 / 評審中 / 已定稿
負責人:<角色,例如當週值班>
評審時間:<日期>
## 1. 摘要
- 發生了什麼(一句話):
- 持續多久(開始 - 恢復,註明時區):
- 影響多大(失敗請求數 / 失敗率 / 受影響功能):
- 根因類別:自身程式碼 / 配置 / 基礎設施 / 上游依賴 / 網路
- 當前狀態:已恢復 / 已緩解待根治
## 2. 影響
| 指標 | 數值 | 資料來源 | 統計視窗 |
|---|---|---|---|
| 失敗請求數 | | | |
| 失敗率(失敗 / 總請求) | | | |
| 受影響功能或介面 | | | |
| 使用者可感知時長 | | | |
## 3. 時間線(統一用 UTC,括號內附北京時間)
| 時間 | 事件 | 證據(連結 / 截圖 / 日誌查詢) |
|---|---|---|
| T0 | 第一個異常訊號(探測失敗、錯誤率上升) | |
| T1 | 告警觸發 | |
| T2 | 有人確認並開始處理 | |
| T3 | 上游狀態頁首次更新(如適用) | |
| T4 | 採取緩解措施(切換、降級、回滾) | |
| T5 | 指標恢復 | |
| T6 | 官方宣佈恢復 / 事件關閉(如適用) | |
關鍵間隔:發現耗時 T1-T0 = ;響應耗時 T2-T1 = ;緩解耗時 T5-T2 =
## 4. 根因
<直接原因是什麼,用證據說話;不確定就寫“待確認”和確認方式>
## 5. 促成因素
<哪些條件讓影響變大或持續更久:缺少超時、重試放大、單一供應商、告警閾值等>
## 6. 做得好的地方 / 運氣成分
-
## 7. 行動項
| 編號 | 行動 | 型別(預防 / 發現 / 緩解) | 負責人 | 截止日期 | 驗收標準 |
|---|---|---|---|---|---|
| A1 | | | | | |
幾點約定:
- 無責覆盤:寫“告警閾值設成 30 分鐘導致發現晚”(示例),不寫“某某沒看告警”。覆盤對事不對人,否則下一次大家會傾向少寫細節。
- 時區統一:狀態頁、日誌、監控平臺的時區經常不一樣,混寫很容易讓時間線錯位幾個小時。
- 每個行動項都要有驗收標準:“加強監控”不是行動項,“對上游 API 增加每 5 分鐘一次的外部探測,連續 2 次失敗告警”(數值按自己的業務定)才是。
時間線怎麼用資料還原,而不是靠回憶?
時間線裡最有價值的是幾個時間差:異常何時開始、你何時知道、官方何時承認、何時真正恢復。這幾個點分別來自不同的資料來源,需要逐一對上。
第一步:確定 T0,第一個異常訊號
T0 優先取外部探測或請求日誌裡的第一次失敗,而不是告警時間。告警通常有聚合視窗和閾值,會比真實開始晚。
如果你有自己的請求日誌,可以按分鐘統計 5xx 和超時:
# 假設日誌是 JSON 行格式,含 ts(ISO 時間)和 status 欄位
jq -r 'select(.status >= 500) | .ts[0:16]' app.log | sort | uniq -c | head -20
第一個明顯高於基線的分鐘就是候選 T0。再往前看 10 分鐘,確認之前確實是正常的。
沒有自己的探測時,可以參考第三方的外部探測。cdnping 的 API 狀態頁 從 Cloudflare 邊緣每 5 分鐘探測一次各官方 API 入口,保留 30 天曆史;探測方法寫在 資料方法 裡。注意 cdnping 從 2026-10-17 才開始採集,更早的事故沒有它的探測資料。外部探測的解析度是 5 分鐘,用來核對“那段時間入口是否可達”足夠,精確到分鐘還得靠你自己的日誌。想自己搭探測,可以參考 自己測 AI API 的可用率。
第二步:對上官方狀態頁的時間
上游狀態頁給出的“事件建立時間”是 T3,它往往晚於 T0。狀態頁的事件等級、元件怎麼讀,可以看 怎麼看 OpenAI 狀態頁和 Claude 狀態頁。
下面用 cdnping 同步的官方狀態頁記錄做一個整理示例(來源:cdnping 每 15 分鐘同步的官方狀態頁事件,取 2026-10-15 前後幾條;分鐘數為 cdnping 記錄的事件持續時長):
| 服務商 | 事件標題(原文) | 影響級別 | 建立時間(UTC) | 北京時間 | 記錄時長 |
|---|---|---|---|---|---|
| Cloudflare | Increased HTTP 502 Errors | minor | 2026-10-15 10:47:18 | 10-15 18:47 | 591 分鐘 |
| OpenAI | Widespread feature degradation | major | 2026-10-15 16:29:26 | 10-16 00:29 | 146 分鐘 |
| Cloudflare | Network Performance Issues in Eastern North America | major | 2026-10-15 20:48:17 | 10-16 04:48 | 49 分鐘 |
| Cloudflare | Increased HTTP 5xx Errors Ashburn | minor | 2026-10-16 13:46:51 | 10-16 21:46 | -43 分鐘 |
假設你的服務依賴 OpenAI API,在 10 月 15 日那次事件裡受了影響,時間線可以這樣寫:
T0 2026-10-15 16:2x UTC 自己日誌中 5xx 開始上升(填實際分鐘)
T3 2026-10-15 16:29 UTC OpenAI 狀態頁建立事件 "Widespread feature degradation"(major)
T6 約 18:55 UTC 按記錄時長 146 分鐘推算的事件關閉時間
T5 ? 自己的錯誤率回到基線(以日誌為準,可能早於或晚於 T6)
T5 和 T6 要分開寫。官方關閉事件的時間和你的服務恢復的時間不一定一致:可能你的重試佇列還在消化積壓,也可能你早就切到了備用路徑。
第三步:檢查資料本身是否可信
上表最後一行的時長是 -43 分鐘。在 cdnping 這段記錄裡還有幾條類似的負數(例如 -57、-17、-183 分鐘)。可能的原因是狀態頁事後改寫了開始時間,或者事件屬於補錄。不管哪種原因,負數時長都不能直接寫進覆盤。遇到這種情況,回到官方狀態頁的事件詳情,逐條看 “Investigating / Identified / Resolved” 的更新時間,自己算。
這一步也適用於你自己的監控:探測節點本身掛了、時鐘漂移、日誌延遲入庫,都會讓時間線錯位。覆盤裡寫清每個時間點的來源,評審時別人才能複查。
第四步:用請求計數量化影響
“影響”一節最好有分母。以 AGI Plan 公開的逐小時請求統計為例(AGI Plan 是 cdnping 的商業合作方;資料來自 https://agiplan.dev/api/status/requests,不需要登入,口徑是隻有 5xx 算平臺失敗)。下面是 2026-10-16 連續三個小時的計數,每個小時桶從整點後第 5 分鐘起算:
| 小時桶起點(UTC) | 成功 | 失敗 | 失敗率 |
|---|---|---|---|
| 06:05 | 664 | 722 | 52.1% |
| 07:05 | 455 | 877 | 65.8% |
| 08:05 | 921 | 107 | 10.4% |
這類資料能回答“影響有多大、什麼時候開始回落”,但回答不了“為什麼”。同一時間段上游有沒有事件,要對照狀態頁記錄;單看這三行,不能下根因結論。這正是覆盤裡“根因”和“影響”要分開寫的原因。
失敗率、可用率和錯誤預算怎麼換算,可以參考 SLI、SLO、SLA 到底差在哪。
上游 AI 服務出故障,自己的覆盤寫什麼?
當根因是“OpenAI / Claude / 某家雲服務出了問題”時,不少團隊就不寫覆盤了。這種情況其實更該寫,因為上游故障並不少見。按 cdnping 同步的官方狀態頁記錄(2026-09-17 至 2026-10-17),Claude 有 6 條 major 級別事件,OpenAI 有 4 條 major、19 條 minor,Cloudflare 有 3 條 major、19 條 minor。更完整的統計見 AI 服務故障盤點:2026 年 9–10 月。
上游的根因你改不了,覆盤的焦點放在下面這些問題上:
我們比官方早還是晚知道?
對比 T0、T1 和 T3。如果你的告警比官方狀態頁還晚,說明你在依賴使用者反饋或官方公告來發現問題。改進方向是加外部探測,具體做法見 AI 應用可用性監控怎麼做。遇到問題時也可以先看 /down,那裡彙總了官方狀態頁、每 5 分鐘的 API 探測和使用者報告,能較快判斷是不是普遍現象。
錯誤碼處理對不對?
看日誌裡失敗請求的狀態碼分佈:
jq -r 'select(.upstream=="openai") | .status' app.log | sort | uniq -c | sort -rn
502、503、529 這類通常值得帶退避重試;400、401 重試沒用,只會放大流量。如果事故期間重試把請求量放大了幾倍,這就是一條促成因素。各狀態碼的含義和是否該重試,見 大模型 API 錯誤碼速查。
有沒有降級或切換路徑,用了嗎?
逐項檢查:
- 是否有備用模型或備用供應商?切換要改程式碼還是改配置?
- 切換花了多久?是誰決定的?有沒有預先寫好的判斷條件?
- 降級後使用者看到了什麼:報錯、排隊提示,還是功能悄悄變差?
- 超時設定是否合理?有沒有請求掛滿連線池拖垮其他功能?
- 恢復後是否切回?切回時有沒有引起第二次波動?
我們對使用者說了什麼?
記錄第一次對外通告的時間、渠道和措辭。如果使用者比你的公告更早發現問題,可以考慮給自己的服務做一個狀態頁,參考 給 AI 服務搭一個狀態頁。
上游故障類覆盤的行動項示例
| 行動 | 型別 | 驗收標準 |
|---|---|---|
| 對每個上游 API 增加外部探測,連續 2 次失敗告警 | 發現 | 演練中 10 分鐘內收到告警 |
| 5xx 重試改為指數退避並設上限 | 緩解 | 壓測中重試請求不超過原請求量的設定倍數 |
| 寫好切換備用供應商的操作手冊和觸發條件 | 緩解 | 值班人員按手冊獨立完成一次切換演練 |
| 訂閱上游狀態頁事件通知 | 發現 | 測試事件能推送到值班群 |
表裡的“設定倍數”“10 分鐘”請按自己的業務定,這裡只是示例。
寫完之後的自查清單
提交評審前過一遍:
- 時間線每一行都有證據連結或查詢語句嗎?
- 時區統一了嗎?
- 影響一節有分母(總請求數)和統計視窗嗎?
- 根因有證據,還是推測?推測是否標了“待確認”?
- 有沒有出現人名指責?改成對流程和系統的描述。
- 每個行動項都有負責人、截止日期和驗收標準嗎?
- 是否單獨寫了“如果再發生一次,我們能更早發現嗎”?
- 引用的外部資料(狀態頁、第三方探測)是否註明來源、視窗,是否檢查過異常值(例如負數時長)?
覆盤定稿後,過一到兩週回頭看行動項完成了多少,沒完成的在週會上單獨過一下。