事故時如何有效診斷問題與修正錯誤?

2026年7月29日

💎 加入 E+ 會員方案 與超過千位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

在軟體工程的工作中,難免會遇到各類問題。當遇到問題時,需要有效地排查問題,並做好錯誤修正。軟體工程師的工作核心是解決問題,因此如果能提升自己的解決問題能力,對於軟體工程師職涯來說會很有幫助。

很多人會認為,有些人天生比較會 debug,或者 debug 很吃經驗;然而,實際上不論天賦與經驗多寡,都可以透過一些有架構的方式,來加速問題解決。在這篇主題文,我們會來談在 Google 的 SRE 專書中介紹的有效排查與解決問題 (effective troubleshooting) 方法。

解決問題的四步驟

具體來說,Google 的 SRE 專書在這個章節中,把問題解決拆成兩個核心的要件,分別是排查問題的方法,以及對系統本身的理解。由於大家平常在工作中面對的系統都有所不同,所以這邊不會特別拉出對系統的理解這點來討論,而是會針對排查問題的方法來深談。

我們可以把軟體工程排查問題的方法,當成一種假設驗證的過程 (hypothetico-deductive method)。就像科學家在做實驗,會先觀察現象、提出假設,透過不同方法來驗證假設,然後在過程中不斷排除錯誤假設的方式,藉此來縮小範圍最終驗證假設。

舉例來說,假如今天網站突然跑得很慢,如果沒有用假設驗證法,可能會亂槍打鳥地猜「會不會是因為 Redis 出問題」或者「會不會是昨天合併的 PR 導致的」,當然這樣猜也有可能會猜中問題所在,但是往往會比較沒效率。

更理想的方式,是先找出哪個地方出錯,例如「在 XX API 的監控面板中看到大量的錯誤,錯誤類型跟超時有關,P95 的延遲確實大幅上升」。而當定位到某支 API 變慢,也不能直接就亂猜是快取出問題,或者是資料庫出問題,而是需要進一步查看,例如「如果是因為資料庫出問題,那資料庫的延遲應該會上升,資料庫延遲的監控沒有顯著變化,CPU 的用量也沒有明顯改變,所以問題應該出在其他地方」。

進一步說,Google 的 SRE 專書把問題解決方法拆成下面這樣的流程,以下讓我們逐一說明。

分流與檢視

在遇到問題時,分流 (triage) 是第一件要做的事。所謂的分流是指判斷問題多嚴重、影響多大,以及該用什麼樣的事故等級來應對。在實務上可能遇到各種問題,但不是每一個都該用最高規格處理;如果小事也動大工程,很快就會耗盡資源 (備註:推薦回顧 軟體工程師該如何做好監控 (monitoring)? 有談不同的優先等級)。

在分流階段,重點不是找 bug,而是判斷事件的影響,例如影響到多少使用者、功能壞掉是只有部分還是整個服務、問題是限縮在局部還是逐漸在擴大等等。

在分流階段有了初步判斷後,不要一開始就急著追根因。這個階段最重要的,是盡可能讓系統撐著。在 Google 的 SRE 專書有特別強調要「盡可能讓系統在當下的壞情況下持續運作 make the system work as well as it can under the circumstances」。

舉例來說,可以把流量從壞掉的集群,切到其他還在運作的集群。假如問題是會擴散的,甚至有時要當機立斷捨棄部分流量,不處理請求;這聽起來有點反直覺,但如果捨掉部分流量能避免整個系統崩塌,做出這種決策反而是更合理的。

書中用了止血 (stop the bleeding) 一詞,這就類似在急救時,如果患者正在大出血,醫生不會慢條斯理地研究病患到底為何受傷,而是會先止血,確保問題不會擴大。在面對系統的問題時,也該用同樣方式;因為終端使用者不會在乎工程團隊能不能完美找到根因,只會在乎產品能不能被使用。

在有了初步的分流與處置後,接著會進到檢查階段。理想的狀況下,系統要能夠讓工程團隊看見問題,要能做到這樣就需要建置完整的監控與可觀測性。先前我們在 軟體工程師該如何做好監控 (monitoring)? 與 什麼是可觀測性(Observability)? 為什麼需要可觀測性? 分別有討論這兩個主題,推薦讀者們可回顧。

診斷問題出在哪

在檢視問題後,接著要根據看到的證據,判斷問題到底比較可能出在哪裡。如果想要有效診斷,書中推薦用「簡化與縮小範圍 simplify and reduce」的方式,把問題拆小來看。

在理想情況下,系統裡每個元件,都應該有清楚定義的介面。在介面會定義需要什麼輸入,會回傳什麼輸出,這些都應該要是可被驗證的。因此,要判斷該元件有沒有出錯,最直接的方式,是測試輸入與輸出的對應。

進一步說,我們可以把這個流程看成一條資料流,在檢視的過程中問

  • 這一段收到的輸入是否正確?
  • 這一段吐出的輸出是否正確?
  • 資料是在哪一段開始變怪的?
  • 哪個元件前面還正常,後面就壞了?

以「使用者搜尋不到商品」為例,比起在整個大系統中大海撈針,可以改成診斷整個鏈路的資料流,從前端的請求開始檢視,一路看前端送的請求是否正確、API 收到的跟前端傳來的是否相同、API 背後呼叫搜尋服務這一段有沒有結果,這樣一路追,就能在過程中診斷出問題在哪。

書中有提到,在比較大的系統,這樣線性地追,可能要追很久。因此會推薦分而為治 (dividing and conquering),會把系統做拆分。例如實務上可以分工切成兩部分,有人追前端到後端這段,另一個人追後端到其他微服務這段,這樣將能更有效率辨別出問題。

在這個過程中,可能會找到幾個潛在的問題點,這時我們會把這些視為假設,在有了假設後,接著要基於假設來解決問題。

測試與解決問題

在解決問題時,要同時觀察假設是否有被驗證。Google 的 SRE 專書有提到兩種驗證方式,一種是比對實際狀況與理論。例如若懷疑是資料庫出問題導致 API 變慢,這時應該要有連帶的指標變化,例如資料庫的 CPU 也該有指標上的波動,如果沒有,則很可能問題不在這。

另一種做法是主動對系統做調整,然後觀察反應。舉例來說,如果假設新版本出問題,可以主動回滾 (rollback) 然後觀察系統是否回到穩定狀態;或是如果假設是功能旗標 (feature flag) 切換導致問題,則可以試著關閉功能旗標,然後再觀察是否回到穩定狀態。

就像醫生在看病一樣,當看到某個症狀,背後可能會有不同的潛在原因,醫生不見得能在一開始就精準定位。因此,醫生多半會根據症狀提出假設,然後做不同的檢查得到更多數值來驗證,或者給予某種處置後觀察病人反應,藉此來驗證。

在實務上,問題很常會是分成表面問題與深層問題。在實際遇到事故時,應該是以止損為優先,所以先解決表面問題,先不追根究底,反而會是更重要的。舉例來說,假如支付系統出問題,導致使用者無法正常結帳,觀測面板發現新的部署版本造成錯誤率上升,這時應該要立即回滾,以系統恢復為主要目標;而不是追根究底去解決,對於終端使用者的影響會比較小。

在做假設的測試時,書中有提到一個特別值得留意的觀點,就是要測試有互斥的替代可能。換句話說,一個好的測試應該要能清楚地告訴讓你知道你「如果結果是 A,就比較支持這個假設;如果結果是 B,就比較支持另一個假設」。

舉例來說,如果搜尋的 API 回傳 502,可能做的假設是對接到前端的 BFF 層壞掉,以及 BFF 層背後呼叫搜尋微服務壞掉。這時如果能夠直接對微服務層發請求,如果拿到的結果是壞掉的,就能夠很明確地判別問題。而在確定問題所在後,就能夠根據問題做相關的處置。


加入 E+ 會員方案

如果你覺得這篇分享有幫助,想閱讀更深入的內容,歡迎加入 E+ 會員。除了有會員專屬的深度文與影片,探討前後端開發、AI 工程、職涯發展,同時有 Discord 社群一同交流與成長。

許多 E+ 會員透過所任職公司的教育訓練補助 (E+ 會開立有統編的發票),不用花自己的錢,也能每週透過深度主題文與社群交流,拓展技術視野、加速職涯成長。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們