本機推理路由的故障轉移,我們在一次演練裡丟掉的 38 分鐘

上次給客戶的演示排在下午三點,早上的例行巡檢裡,我把主後端從 A 池切換到了 B 池,想趁沒流量的時候試一次真正的故障轉移。結果切換腳本在健康檢查這一步卡了 38 分鐘,差點把演示拖成事故。這篇把當時的除錯記錄和後來落地的三條規則寫下來,都是我們自己踩過的坑。

專屬插圖
本機推理路由的故障轉移,我們在一次演練裡丟掉的 38 分鐘

本機推理路由的故障轉移,我們在一次演練裡丟掉的 38 分鐘

上次給客戶的演示排在下午三點,早上的例行巡檢裡,我把主後端從 A 池切換到了 B 池,想趁沒流量的時候試一次真正的故障轉移。結果切換腳本在健康檢查這一步卡了 38 分鐘,差點把演示拖成事故。這篇把當時的除錯記錄和後來落地的三條規則寫下來,都是我們自己踩過的坑。

第一次切換:健康檢查怎麼「等」出來的

我們的閘道器按順序探活:請求 `/v1/models`,連續 3 次 200 才算健康,每次超時 5 秒。規則本身沒問題,問題出在切換腳本的寫法——它把「單次探測失敗」當成「後端不健康」,同時又把「不健康」當成「繼續重試」,兩層語義疊在一起,陷入了 38 分鐘的靜默循環:日誌裡每 5 秒一行超時,腳本卻認為「還在正常等待」。

最後發現 B 池的映像檔沒同步完成,`/v1/models` 回傳的是 503 而不是超時報錯。健康檢查只看「有沒有 200」,於是把所有非 200 都歸入「再等等」。

**規則一:明確區分「探活失敗」和「後端確認不健康」,並給總等待時間設上限。**現在我們切換的熔斷條件有兩個:單一後端連續 5 次探測失敗,或者總等待超過 5 分鐘,二者先到者觸發回切。切換腳本裡這兩個門檻都寫成了命令列參數,不留「預設一直等」的空間。

第二次切換:重試預算被吃光了

一週後真實故障來了,A 池裡一台節點的推理程序掛了。閘道器自動切換到 B 池這次很乾淨,但客戶端回饋首個請求延遲飆到了 20 秒。查下來不是網路問題,是重試放大:用戶端 SDK 預設 3 次重試,閘道器層 2 次重試,每次重試都重新排隊,請求實際被排隊了 6 次以上。

**規則二:重試預算必須在鏈路上做全區域限額,而不是每層各自設定。**我們把用戶端重試改成「整個請求生命週期最多 2 次」,閘道器重試只對冪等的健康探測開啟,對實際推理請求一律不重試,超時直接回切到備用池。改完之後同一場景的首請求延遲穩定在 4 秒以內。這裡有個容易忽略的點:LLM 推理請求看起來冪等(同樣的 prompt 重複提交結果一樣),但在排隊系統裡「重複提交」會重複佔用佇列,效果上等價於非冪等。

第三個坑:時鐘漂移讓「切換時間」沒辦法對齊

複盤時要把兩邊日誌拼起來,發現 A 池和 B 池的時鐘差了 40 秒,是機器重啟後 NTP 沒跟上的鍋。40 秒的差值讓「哪個請求在哪一側失敗」這種問題查起來非常費勁。

**規則三:時鐘同步和健康檢查一樣,都是基礎設施假設,要當成服務自己探測的一環。**現在閘道器每 10 分鐘校準一次本地時鐘偏差,偏差超過 5 秒直接報警;切換日誌裡所有時間戳強制帶時區標記,禁止使用未標記的本地牆鐘時間。

三條規則進 CI 之後

這三個月裡這套演練每月跑一次:切換主機、斷網、模擬映像檔半同步。總共回滾過一次(映像檔倉庫頻寬不夠導致 B 池起不來),其餘都按預期走完。觸發過的告警都留了記錄,沒有一次是「靜默失敗」。

本機推理的路由層其實就幹三件事:探活、排隊、切換。把這三件事各自的失敗模式寫清楚,切換演練就不會只是「點了一下按鈕」。比起換更高級的調度框架,先把「失敗後的行為」定義清楚,性價比更高。

留言區

歡迎分享你的想法!

發表留言

0/500

載入留言中…