Health check endpoint 設計
Health check endpoint 的責任是讓外部用一個標準請求就問到服務的權威健康狀態,取代肉眼登入機器猜死活。它是這個模組所有自動恢復機制的共同輸入:重啟靠它判斷該不該重啟、負載平衡靠它決定要不要送流量、告警靠它知道什麼時候該叫人。端點回什麼、探多深,是每個服務要自己設計的決策,不是框架給的預設值。
設計的核心問題只有一個:「這個端點回 200 的時候,到底保證了什麼」。答得越含糊,下游依賴這個訊號做的每個決策就越不可靠。
淺檢查只證明 HTTP handler 活著
最簡單的 health endpoint 是收到請求就回 200。這種檢查探到的深度只到「HTTP server 還在接受連線、路由還在運作」,不保證服務真的能做事。進程活著不等於內部子系統活著——一個服務可以進程好端端跑著、pgrep 找得到、CPU 不高,但它內部某個關鍵子系統已經 wedged,這種狀態下淺檢查照樣回 200。這正是 程序、服務與狀態怎麼判 裡「進程活著 ≠ 在運作」那條,搬到服務自我回報的場景。
一個資料寫入服務的 handler 執行緒還在監聽、但它背後的資料庫連線池已經全部逾時,淺檢查會回 200,負載平衡繼續把寫入請求送進來,每一筆都在下游卡死。訊號說健康、實際在掉資料——淺檢查的盲點就在這裡:它證明的比它看起來保證的少很多。
深檢查探到服務真正依賴的子系統
深檢查在回答健康之前,先確認服務賴以運作的關鍵子系統確實可用。一個寫入服務的深檢查會實際碰一下儲存層——取一個連線、確認 pool 沒枯竭就夠,不必完整寫一筆;一個查詢服務會確認索引載入完成、快取連得上。深檢查回 200 的保證比淺檢查強:不只 handler 活著,服務真正做事需要的那條路徑也通。
深檢查的成本是它要花時間、也可能引入自己的失敗。檢查本身若把每個下游依賴都同步 ping 一遍,就製造了依賴放大:一個非關鍵的下游慢一點,health check 跟著逾時,服務被判成不健康、被摘掉流量或被重啟,但服務本身其實還能服務核心請求。所以深檢查的設計要先切開「關鍵依賴」跟「非關鍵依賴」——關鍵依賴掛了服務確實無法運作,值得檢查;非關鍵依賴(一個可以降級的推薦引擎、一個非同步的分析上報)掛了不該讓整個服務被判死。這條切分沒有通則,取決於這個服務缺了哪個子系統就真的做不了事。
帶診斷資訊的回應把「活著」跟「有沒有在做事」分開
health endpoint 回的不只有狀態碼,還可以帶回讓外部判讀健康程度的欄位。本站 collector 的 /health 回 200 的同時附帶「最後一次成功寫入的時間」——這個時間戳把兩件事分開了:狀態碼 200 說進程活著,最後寫入時間說它有沒有在做事。進程活著但最後寫入停在十分鐘前,是「活著但卡住」的定案訊號,比單看狀態碼可靠。
更細的健康程度來自處理管線的內部計數。collector 在 endpoint 暴露 channel.depth(待寫入事件的積壓數)跟 storage.errors(寫入錯誤累計)這類計數器;積壓持續變高、錯誤持續累加,代表服務還活著、但已經降級——處理速度跟不上進來的量。這是二元的「掛了沒」之外的中間態訊號。
中間態不一定要暴露給最終呈現層。同一套 collector 的 DevOps 儀表板服務狀態卡刻意設計成純二元——綠色正常、紅色異常,不讓看板的人去解讀積壓數字。中間態的量化欄位存在於 endpoint、供機器判讀與告警規則收斂用;呈現層則收斂成二元,讓人一眼就懂。健康程度探得多細,跟最終要呈現多細,是兩個獨立的決策。
啟動期的健康是另一種狀態
服務剛起來、還在載入索引或重建狀態時,它既不是掛了、也還不能服務——這是啟動自檢要覆蓋的一段。collector 啟動時會檢查儲存完整性、重建索引,這段期間服務進程活著,但還沒準備好接流量。淺檢查在這時就會回 200,若外部據此開始送流量,請求會打在還沒就緒的服務上。啟動期的健康狀態要跟「就緒可服務」分開回報——啟動中、就緒、存活是三種不同狀態,對應 liveness、readiness 與 startup 三種 probe 要分開回答的問題。
誰來戳這個端點
設計好回什麼之後,還要決定誰來讀它。服務自己不會主動回報,要有外部的探測者定期戳。最輕量的做法是一個定時器對 endpoint 發健康請求並設逾時,戳不動就讓那次檢查失敗、走既有的告警鏈——服務掛了怎麼自動知道 的外部探針段有單機 systemd 上的完整實作(curl /health 設 5 秒逾時、逾時就 failed)。跑在編排平台上時,這個角色由平台的 probe 機制接手,探測的語意、失敗後的動作,是 liveness 與 readiness 的主題。
外部探測比服務自我回報可靠的地方在於:服務內部卡死時,它可能連「我不健康」都報不出來——是外部戳它、發現戳不動,才抓得到這種失效。自我回報只能覆蓋服務還有能力回應的那些失敗。
下一步路由
- 活著、準備好接流量、啟動中是三種健康、對應三種 probe → Liveness 與 Readiness
- 端點設計好之後,怎麼在單機用 systemd 定時探測並告警 → 服務掛了怎麼自動知道
- 探到不健康之後怎麼自動重啟、放棄了才告警 → systemd watchdog 與自動重啟
- health signal 怎麼收斂成 DevOps 儀表板的服務狀態卡 → Monitoring DevOps 儀表板