有效除錯:除錯是方法,不是天分

· tech

#sre#incident

📑 目錄

上一篇說 on-call 被叫到先止血;但止完血,總得找出為什麼。這篇講除錯——而它最重要的一個觀念是:除錯不是靠天分或運氣,是一套可以學的系統化方法。 新手和老手的差別,不在「知道答案」,而在有沒有一套逼近答案的流程

先認出反模式:亂猜與換零件

沒方法的除錯長什麼樣?隨機改東西看會不會好(換零件式除錯)、只檢查自己熟的地方一次改一堆設定被「最近好像動過什麼」牽著鼻子走。這些之所以沒用,是因為它們沒有在縮小問題的範圍——你只是在碰運氣,運氣好矇到、運氣差越弄越糟,而且事後你根本不知道到底是什麼修好的(因為一次改了太多)。

系統化除錯的流程

有方法的除錯,是一個有次序的迴圈:

① Triage 止血 先讓系統活著 (別急著找 root cause) ② Examine 觀察 看監控 / log 四個黃金訊號 ③ Diagnose 診斷 假設 → 測試 → 排除 二分逼近 ④ Treat 修復 一次改一個變因 可回復 沒好?回頭再提假設 每一步都在「縮小範圍」;而反模式(亂猜、隨機換零件、一次改一堆)從不縮小,只是碰運氣
先止血讓使用者無感,再依監控觀察(四個黃金訊號),然後用「假設→測試→排除」一步步逼近,最後謹慎修復。跟反模式的差別只有一個:它每一步都在縮小問題的範圍

診斷(③)是整個流程的核心,而它的手法就一句話:提出一個假設,想辦法驗證或否證它,藉此排除一部分可能。 這跟二分搜尋一模一樣——每測一次,就砍掉一半的嫌疑範圍。

核心武器:分而治之(二分法)

診斷時最鋒利的一招,是分而治之:沿著請求的路徑,不要逐段瞎試,而是先量中間——問「問題在這一段之前,還是之後?」一刀砍掉一半:

Client LB App Cache DB慢 ❌ ① 先量中間(App) ② App 之後才慢 → 縮到後段 → DB 沿路徑一次砍一半 → 幾步就定位,而不是從頭逐段瞎試 使用者回報:慢。別猜「大概是 X」,去量、去二分
二分法把「大海撈針」變成「幾步定位」:先量路徑中間,判斷問題在前段還後段,砍掉一半,再對剩下的一半重複。這招在任何分層系統都通用

幾條鐵律

流程之外,有幾條讓除錯不走歪的鐵律:

  • 一次只改一個變因。同時改三個東西然後好了,你永遠不知道是哪個修好的、其他兩個有沒有埋雷。
  • 相信資料,別相信直覺。去看監控、log、黃金訊號,用資料否證假設,而不是用直覺去確認成見。
  • 問「什麼變了」。多數故障跟「最近的一次變動」有關(部署、設定、流量)——先看變更紀錄,常常一秒破案;但也別被它綁架到不看別的。
  • 記錄你做了什麼。方便回溯、方便交接、也是之後寫 postmortem(下一篇)的原料。

反思

除錯是方法,不是天分

我剛入行時覺得資深工程師除錯像有神通——瞄一眼就知道哪裡壞。後來近距離看才發現,那不是神通,是一套穩定的逼近方法:先看資料、再提假設、然後二分縮小。他們不是「知道答案」,是「有辦法在幾步內逼出答案」。這個認知對我影響很大——它把除錯從「靠靈感的玄學」變成「可以刻意練習的技能」。我帶新人時最先教的也是這個:別急著猜,先看;別亂改,先縮小。 方法對了,任何人都能穩定除錯。

二分法是除錯的萬用鑰匙

「沿著資料流一次砍一半」這招,我用到哪裡都靈。它的威力在於每一步都讓問題空間減半——十段路徑,三四步就定位,而不是從頭試到尾。想通之後我發現,這跟我在 讀 SQL 執行計畫找瓶頸、在 gaps-and-islands 縮小問題、甚至在 code review 找 bug,用的都是同一種「縮小搜尋空間」的思維。學會二分定位,比背下任何特定 bug 的解法都值錢,因為它適用於你還沒遇過的所有問題。

「相信資料,別相信直覺」——去看,別猜

除錯最大的敵人,其實是「我覺得應該是 X」的成見。成見很危險,因為它讓你只去找支持它的證據、自動忽略矛盾的線索,於是你在錯的方向上越挖越深。系統化流程的價值,就在它強迫你去「」——看監控、看 log、看執行計畫——用事實去否證假設,而不是用直覺去確認。這跟我在 SLI 看使用者體感、在 讀 EXPLAIN 而不是猜反覆講的是同一個信念:讓事實說話。 工程師最該訓練的,不是猜得準,是忍住不猜、先去看的紀律。