為大型語言模型加上流量控制:為什麼 QPS 並非越高越安全
許多團隊將「QPS 限額」視為一個可以不斷調降的大數值,直到業務發出警報時再稍微調低。然而,閘道器上的速率限制其實扮演著更微妙的角色:它是您與模型推論叢集之間唯一的緩衝區。今天的主題就是該如何設定這個緩衝區,而許多人的直覺答案往往是錯誤的。

為大型語言模型加上流量控制:為什麼 QPS 並非越高越安全
許多團隊將「QPS 限額」視為一個可以不斷調降的大數值,直到業務發出警報時再稍微調低。然而,閘道器上的速率限制其實扮演著更微妙的角色:它是您與模型推論叢集之間唯一的緩衝區。今天的主題就是該如何設定這個緩衝區,而許多人的直覺答案往往是錯誤的。
先說結論:**限制值的正確設定位置,取決於您的失敗成本結構,而非預估的流量峰值。**
閘道器限流究竟在防範什麼
模型服務是這類系統中最昂貴的下游元件:一次推論請求會佔用 GPU 記憶體數十秒至數分鐘,請求堆積會直接導致 TTFT(首字延遲)惡化。若閘道器不進行限速,當突發流量進入時,GPU 佇列會迅速填滿——這並非導致服務崩潰,而是所有請求的回應時間同時出現長尾現象,使用者體驗則是「全站變慢」。
因此,限流的真正目標並非防止過載,而是**將過載轉化為可預測的排隊行為**。這一點與傳統的 API 限流有很大的不同。
三種常見的限流設定方式及其潛在問題
**固定 QPS 上限**:最簡單的方式,但問題在於您使用一個常數去壓制一個隨時間劇烈變化的分佈。早高峰期的 QPS 可能是 200,深夜則只有 15,同樣設定為 100 的上限,在這兩個時段意味著完全不同的排隊長度。
**視窗計數器(每 10 秒放行 N 個)**:比單純的 QPS 稍微穩定一些,但邊界效應嚴重——在第 10 秒剛開始的瞬間,兩個視窗之間可能會瞬間放行 2N 個請求。模型服務對秒級的突發流量極為敏感,這種尖峰正是您希望避免的。
**令牌桶(token bucket)**:維護一個桶,以恆定速率填入令牌,每次請求消耗一個令牌。相較於視窗計數器,它天然允許適度的突發(當桶內有剩餘令牌時),但不會讓突發量無上限。大多數生產環境的閘道器都採用此機制。
如何決定參數:從推論耗時反向推算
這兩個數值是閘道器端必須調整的:
- **填充速率(rps)**:單位時間內補充的令牌數量。
- **桶容量(burst)**:突發時一次性可放行的請求數量。
正確的做法是從下游反向推算,而非憑空猜測。您需要的數據包括:
- 模型推論的平均延遲 p95(並非平均值,尾延遲決定了排隊行為)
- 後端 GPU 池的並行處理上限
一個粗略但實用的推導方法:如果您的並行上限是 C,平均延遲是 T 秒,那麼系統能穩定承接的 rps 大約是 C / T。將閘道器的 rps 設定為此數值的 0.7 到 0.8 倍,以留出緩衝空間。
**桶容量**則是另一項權衡。若設定太大,突發尖峰仍會衝擊下游;若設定太小,正常的波動也會受到誤傷。經驗上的起始設定值為 C 的 1.2 到 1.5 倍——這足以容納合理的不規則流量,又不至於將未飽和狀態轉變為真正的堆積。
反直覺之處
許多人在設定限流後的第一個反應是:「如果限流比例(被拒絕的請求佔比)為 0%,就表示我限得不夠嚴格。」這是最容易陷入的誤區。
**零拒絕率通常表示您有大量閒置容量在浪費預算。** 此外,對於一個長期幾乎不觸發限流的系統,您根本無法得知當限流真正被壓制時的行為表現——下一次流量翻倍時,您只會在生產環境中首次面對斷崖式的效能下降。
更穩健的做法是:故意在預發環境中發送比您預估峰值高出 50% 的負載,觀察 TTFT 惡化曲線在哪裡開始變陡,那個拐點附近的 QPS 才值得作為您的基準上下限。
檢查清單
在發布限流規則之前,請確認以下三點:
1. 您的 rps 和桶容量是從 p95 延遲反向推算得出的,還是營運人員憑直覺給出的一個數字?
2. 觸發限流時的行為是什麼——直接回傳 429 錯誤,還是讓請求在佇列中等待並設有超時機制?(直接回傳 429 的誤傷率通常比排隊加等待高出不少。)
3. 您是否有辦法在不撰寫程式碼的情況下,查看「距離最近一次 429 錯誤還有多少餘量」?若無法看到這個數值,下一次擴充容量將成為您被動應對的時刻。
流量控制並非懲罰使用者的機制,而是讓您能夠預測成本的手段。使用反向推算的數值進行設定,並透過觀測數據進行校準,這比「先設定高一點,出事再調降」要安全得多。
留言區
歡迎分享你的想法!
載入留言中…