流量平衡合約(load balancer contract)的核心責任是定義平台何時把流量交給服務,以及服務何時安全退出流量。這份合約一旦模糊,部署、擴容、回退與事故處理都會出現同型問題。

contract 組成

Load Balancer Contract 可以拆成四個部分:

  1. routing contract:哪些路徑導向哪些服務,如何處理權重與版本。
  2. health contract:哪些訊號代表可接流量,何時摘除節點。
  3. connection contract:長短連線的 idle timeout、keepalive、重試規則。
  4. drain contract:版本切換時如何讓 in-flight request 安全收斂。

這四個部分共同定義 rollout 的穩定性。服務端 readiness 與平台端健康檢查要對位,否則會出現「服務已啟動但尚未可服務」的切換抖動。

draining 與 shutdown

draining 的責任是讓舊實例在下線前完成現有請求。drain 視窗的 workload 分類詳見 5.6 Platform Lifecycle Contract,本段聚焦 LB 如何配合 drain:短請求 API 的 drain 視窗可較短;長連線、串流或 websocket 場景需要更長窗口與明確 reconnect 策略。

部署流程中,LB 摘流量、服務停止接新請求、服務完成在途請求、實例退出,這四步要有固定順序。順序穩定後,rollback 才能在同一套機制下運作。

timeout 與 sticky session

idle timeout 是連線資源與使用者體驗的平衡點。timeout 太短會增加重連與錯誤,太長會占用連線與資源。設定時依請求型態與峰值流量校準、按 SLI 訊號迭代閾值。

Timeout 層級串聯

一條請求路徑上的 timeout 分佈在多個層級,每層各自有預設值。全路徑的 timeout 設計原則是由外到內遞減:外層(離使用者近)的 timeout 要大於內層(離資料源近),否則外層先放棄,內層還在處理一個已經沒人等的請求。

層級典型 timeout 範圍設定位置
Client / Browser30-120 秒前端 fetch / axios / SDK 設定
CDN edge5-30 秒CDN vendor 設定(Cloudflare / CloudFront)
Load balancer30-60 秒LB idle timeout / request timeout
Application5-30 秒HTTP server read/write timeout
Database / Cache1-5 秒連線池 query timeout / connect timeout

這張表的每一層 timeout 都要比它的下一層大。如果 LB timeout 30 秒但 application 設了 60 秒,LB 會在 30 秒回 504 給使用者,但 application 仍然持有連線等 DB 回應——佔用連線資源卻無法交付結果。

timeout 設計的常見失誤是只調 LB 層:團隊看到使用者回報 timeout,直接把 LB timeout 從 30 秒調到 120 秒。結果是慢請求佔用 LB 連線更久、連線池被慢請求填滿、其他正常請求也開始排隊 timeout。穩定做法是先在 application 或 DB 層找出延遲根因,而非放大外層 timeout 來「等更久」。

sticky session 適合需要短期會話一致性的場景,但它會提高特定節點負載不均與失效轉移成本。採用 sticky policy 前要先定義會話狀態落點與失效時的回復路徑。

LB + CDN 連線生命週期協調

當 LB 上游有 CDN 時、兩層的 timeout / retry 行為要對齊、否則會出現「使用者已經 timeout 但 origin 還在處理」這類雙層不一致:

  • CDN edge timeout 通常比 origin LB timeout 短(5-30 秒)— edge 認定 origin 慢就放棄。若 origin LB timeout 是 60 秒、edge 在 30 秒已放棄回 504、origin 還在處理一個沒人在意的 request。應對齊兩邊的 timeout 上限。
  • CDN retry policy 在 edge miss 後若拿不到 origin response、預設不會重試(避免雙倍 origin 流量)— LB 端的 idle timeout 設計要假設「只有一次機會」、不依賴上游重試
  • 長連線(WebSocket、SSE、gRPC)通常繞過 CDN — 直接連到 origin LB。這些連線的 idle timeout 跟一般 HTTP 不同、要單獨配置
  • Edge cache HIT 時 LB 完全沒收到 request — 容量規劃時要把 cache hit ratio 算進 origin RPS、不是用使用者 RPS 直接 size LB

詳見 5.9 邊緣分發與靜態資源 的 origin protection 段。

切流失敗的回退判讀

切流失敗的回退判讀第一步是先分辨「平台問題」跟「流量生命週期問題」、再決定回退手法。平台問題用重啟服務恢復、流量生命週期問題用凍結切換並等待震盪收斂。回退手法錯位會把事故推進第二階段。

切流失敗的本質是 connection lifecycle 跟切換時序錯位、平台元件本身往往是健康的。對應 5.C9 反例:平台切流未先 Draining:揭露切流失敗常因 connection lifecycle 管理錯位、重啟動作會放大震盪。以下基於通用工程知識展開回退節奏。

回退節奏有兩個時序階段、性質不同。

第一階段:先讓震盪不擴大。發現切流失敗的第一動作是凍結 rollout(不再擴大切換範圍)跟恢復舊入口權重(把 LB 規則 / DNS 加權 / service mesh 流量切回舊版本主導)。新版本不立即關閉、保留作為對照證據。這個階段的目標是穩定當前狀態、為後續分析爭取時間、所有動作要在分鐘級內完成。

第二階段:再讓系統可恢復。震盪不擴大後、進入「等待 + 修正」狀態。長連線跟 reconnect 風暴需要時間消化、盲目重啟新版本實例會把重連集中在新一輪實例上、造成 thundering herd。觀察連線數、reconnect rate、5xx 趨勢回到 baseline 是進入修正階段的訊號。修正動作聚焦於 drain window、idle timeout、health check、client retry 之間的節奏錯位、找出後修正、重新進入小範圍驗證。這個階段的時間尺度通常是小時級、不能用第一階段的緊急節奏對待。

兩階段時序不能合併。把第一階段(凍結 + 切回)跟第二階段(等待 + 修正)並列執行、會在連線尚未穩定時嘗試修正、造成第二次震盪。

回退時最常見的誤判是「LB 顯示新節點 healthy = 服務可服務」。LB 的健康判斷通常是定期 health check 通過,跟「該節點能承受重連潮」是不同問題。事故中要把這兩個訊號分開看:節點層健康(health check pass)、連線層健康(reconnect rate、長連線錯誤率、tail latency)。

切流告警條件

對應 5.C9 反例 的「部署專屬告警條件」段:揭露切流期告警的三個核心訊號(批次內 5xx 突增、長連線重連率快速上升、rollback time 超過既定 RTO)。本段在 case 三條基礎上補第 4 條(per-version error rate 偏離)與操作建議。

切流期告警的核心責任是對應切流批次節奏、跟日常閾值分離。日常閾值在切流期會被切換本身的短暫波動觸發、變成 alert noise;切流期需要更嚴格的「批次內偏差」訊號。

可操作的切流期告警條件:

  • 批次內 5xx 異常升高:當前批次相對於前一批的 5xx 升幅超過閾值、停止下一批。
  • 長連線重連率飆升:reconnect rate 超過 baseline N 倍、暗示 drain / timeout 錯位。
  • 回退時間超過 RTO:執行回退後恢復時間超過既定 RTO、升級為事故等級。
  • per-version error rate 偏離:新舊版本 error rate 差距超過閾值、不收斂(屬本章補強、case 未明示)。

這些告警的閾值要在 release plan 中先定義、進事故時直接套用、避免臨時拍定。把切流告警跟一般日常告警分流到不同 channel,避免事故團隊在切流期被日常 noise 淹沒。

判讀訊號

訊號判讀重點對應動作
rollout 期間 5xx 上升且集中在舊版本drain 順序或窗口不足拉長 drain 時間、調整摘流順序
readiness 通過但首批請求延遲高應用啟動完成與可服務條件未對齊細化 readiness 指標、補 startup gate
reconnect storm 出現在切版後timeout 與連線生命週期不匹配調整 idle timeout、分批切流
canary 比例低時正常,擴到高比例出現抖動LB 權重策略與服務容量曲線不一致降低增量批次、補容量保護
多租戶場景下單租戶延遲飆升sticky/routing policy 造成熱點聚集分離租戶路由、加入負載重平衡
回退後 reconnect 風暴持續重啟動作放大震盪、未先恢復穩定路徑凍結切換、等連線數穩定、再修錯位點

「回退後 reconnect 風暴持續」是切流事故中最容易誤判的訊號。判讀順序:先看是否「凍結切換」已執行(rollout 是否真的停了)、再看「舊入口權重」是否回到主導比例(DNS / LB 規則是否切回)、最後看連線數曲線是否進入下降。三項都做完仍見風暴持續、才考慮新版本實例層級的問題(image / config / runtime 漂移)、而非反向重啟新版本。解凍切換的條件是「連線數曲線回到 baseline + reconnect rate 低於閾值連續 N 分鐘」、不是「等夠久了就解凍」的時間導向。

常見誤區

把 load balancer 當成「只做轉發」的元件,會忽略它在部署與事故中的決策角色。LB 設定定義了流量切換節奏、回退可行性與故障擴散速度。

Health check 跟 readiness 的混淆會在切換時暴露隱性風險。health contract 要反映服務真實 readiness — 含依賴連線池、必要 config、關鍵背景任務狀態 — 而非停在單一探針成功訊號。

把「LB 顯示節點 healthy」當作「服務可承受流量」的訊號,也是事故中的常見誤判。健康檢查通過跟承受重連潮是不同層級的訊號。

案例回寫

流量契約可用 5.C9 反例 回寫。先看事件中的摘流量順序、drain 視窗與連線重建節奏,再回到本章判讀 connection contract 與 drain contract 是否對齊。

這個案例主要支撐的是「連線生命週期與摘流量順序」判讀,不直接支撐 container build 可重現性;若根因在映像與 runtime 漂移,應回到 5.1。

當回退後錯誤率仍高或重連風暴延續,通常表示 timeout 與 sticky policy 仍在放大舊連線狀態。先重建連線生命週期時序,再把回退判斷同步到 8.19 Incident Decision Log

跨模組路由

load balancer contract 是部署平台與操作控制面的匯流點。

  1. 與 5.6 的交接:drain 的生命週期定義與 workload 分類回到 Platform Lifecycle Contract
  2. 與 04 的交接:版本切換訊號與錯誤率證據進入 Observability Evidence Package
  3. 與 06 的交接:canary 放行與回退條件進入 Release Gate
  4. 與 07 的交接:入口治理與管理面保護進入 7.3 入口治理與伺服器防護
  5. 與 08 的交接:切換與回退判斷記錄到 Incident Decision Log
  6. 5.9 邊緣分發 的交接:CDN 是 origin LB 的上游、edge miss 後流量進 origin LB、timeout / retry 設定要協調。

下一步路由

要把 LB 合約放進整體部署流程,接著讀 5.2 Kubernetes 部署策略5.C9 反例。要把部署切換接到事故流程,接著讀 8.19 Incident Decision Log