負載平衡再聰明,系統總有部分會被打爆。過載時的正解不是「整台關掉」,而是繼續接下能處理的份量、優雅拒絕其餘——先降級、再拒絕、最後才回錯誤。一台過載的後端仍該穩定服務它撐得住的那部分。
🧠 Intuition
TIP
用 QPS 當容量指標會騙人——同樣的 QPS,成本隨 client 行為與版本飄移。改用請求消耗的 CPU 時間直接量,才是穩定的「請求成本」。
- 降級回應(degraded responses):資料少一點、精準差一點,但成本低——只搜一部分 corpus、讀本地過期副本而非主儲存。壞掉之前先「變糙」。
- 每客戶配額(per-customer quota):全球過載時,只對「行為失當」的客戶回錯誤,其他人不受影響。依協商用量設 CPU 配額,加總可超賣(假設不會同時打滿)。
- 重要度分級(criticality):每個 RPC 標四級(
CRITICAL_PLUS→CRITICAL→SHEDDABLE_PLUS→SHEDDABLE)。過載時先拒低 criticality,且沿 RPC 呼叫鏈自動傳播;它與延遲需求正交(打字建議是高 SHEDDABLE 但低延遲)。 - 利用率訊號:task 以 CPU rate(executor load average)自保,越接近上限越積極拒絕;短促 fan-out 被平滑吸收,持續高負載才觸發拒絕。
⚖️ Tradeoffs
Client 端 adaptive throttling — 拒絕不是免費的
- 純靠 backend 拒絕有反效果:拒絕本身也吃 CPU,大量拒絕一樣能把 backend 打爆。
- 解法:client 觀察自己近 2 分鐘的
requests與accepts,當requests > K × accepts時本地按機率丟棄,機率約(requests − K×accepts) / (requests + 1)。 - 參數 K 的取捨:K=2 略過量地放行、讓 backend「停止拒絕」的狀態更快傳開;K=1.1 更積極節流,但對解除反應較慢。
- 各 criticality 分開統計,避免低優先流量的節流誤傷高優先請求。
負載卸除 vs 自動擴展 — 沒溝通就會互相反噬
- 真實事故(Workbook「Dressy」案例):某區先達 CPU 閾值開始卸載,拒絕請求時 CPU 不變,負載平衡器誤判該區「每請求 CPU 成本更低、更高效」,於是把更多流量導過去——雪上加霜。
- 根因是兩個系統各自配置、沒有互通;要當成一套統一的負載管理來檢視。
- 準則:閾值設成先 autoscale、再卸載(否則卸掉的是本可擴容服務的流量);各位置保留最小實例數當故障轉移餘裕;在 RPC 上設 deadline,別為對使用者已無益的請求持有資源。
🔑 Takeaways
- 過載的第一原則:過載後端不該全關——降級 → 拒絕 → 回錯誤,永遠先服務撐得住的份量。
- 用 CPU 成本而非 QPS 衡量容量;配上每客戶配額 + criticality 分級 + client adaptive throttling,讓錯誤只落在該落的人身上。
- 負載卸除、自動擴展、負載平衡彼此耦合——孤立配置會產生災難性回饋迴路;務必檢查交互作用並設 deadline。
No notes yet — jot your takeaways or Q&A here.