在 n8n 中跨數百個租戶處理 API 速率限制的方法

嗨,各位,
我正在運行一個多租戶 n8n 平台,其中每個租戶連接到具有不同速率限制的外部 API。
挑戰在於某些租戶的限制非常低,而其他租戶的配額要高得多。
當前設置:Webhook → Queue → Worker → External API
我看到的問題:
• 某些租戶比其他租戶更快地達到速率限制
• 重試會造成流量暴增
• 一個繁忙的租戶可以消耗大量的工作進程容量
• 難以在租戶之間強制執行公平使用
我正在考慮:
• 每租戶隊列
• 令牌桶 / 漏桶速率限制
• Redis 計數器
• 為高流量租戶提供專用工作進程
對於大規模運行多租戶自動化的團隊:
• 你們如何強制執行每個租戶的速率限制?
• 你們按租戶隔離隊列還是使用具有節流的共享隊列?
• 有什麼推薦的模式可以防止一個租戶影響其他租戶,同時保持良好的吞吐量?

描述問題 / 錯誤 / 問題

錯誤訊息是什麼(如果有的話)?

請分享你的工作流程

(在你的畫布上選擇節點,使用鍵盤快捷鍵 CMD+C/CTRL+C 和 CMD+V/CTRL+V 來複製和貼上工作流程。)

分享最後一個節點返回的輸出

關於你的 n8n 設置的信息

  • n8n 版本:
  • 數據庫(默認:SQLite):
  • n8n EXECUTIONS_PROCESS 設置(默認:own, main):
  • 通過以下方式運行 n8n(Docker、npm、n8n cloud、桌面應用):
  • 操作系統:

@Decoure_Ryan 常見的做法是使用按租戶的速率限制,而不是全球統一限制。

Webhook → Queue → Rate Limit Check → Worker → API

使用 Redis 或資料庫追蹤每個租戶的請求,並且只在該租戶在其允許限制內時才處理任務。

這有助於:防止一個租戶影響其他租戶
處理每個租戶不同的 API 限制
減少重試造成的流量尖峰

對於高容量租戶:獨立佇列
專用 worker,使其流量不會影響其他人。

歡迎 @Decoure_Ryan 加入我們的社群!我是 Jay,我是 n8n 認證創作者。

這裡最實用的 n8n 特定方法是在每個外部 API 呼叫前使用程式碼節點來檢查和更新每個租戶的計數器。如果你使用 Redis,將金鑰儲存為 rate_limit:{tenantId},過期時間窗口與 API 的重設週期相符 — 在每個請求時遞增,如果租戶超過限制,路由到 Wait 節點而不是繼續進行。

針對重試突發問題:不要使用 n8n 的內建重試(它會立即觸發,可能會增加 429 錯誤),而是從 HTTP Request 節點捕獲錯誤輸出,並將其路由到 Wait 節點,該節點具有從 Retry-After 回應標頭提取的固定或動態延遲,然後迴圈回到請求。

如果你使用佇列模式,當每個租戶的工作在專用子工作流中執行時,每個工作流的並行限制可以為你提供自然的每租戶隔離 — 為每個租戶工作流設定 concurrency: 1,佇列會為你處理節流,無需任何 Redis 計數器邏輯。

以下是一些大規模運作中行之有效的做法:

按租戶的隊列是正確的選擇。具有節流的共享隊列聽起來很簡單,但似乎總是會導致嘈雜鄰居問題。隔離隊列可以提供真正的隔離,而無需複雜的優先級邏輯。
至於令牌桶實現,Redis 是穩健的選擇,只需使用基於 TTL 的補充來存儲每個租戶的鍵。重試不會在速率限制窗口重置後同時觸發,使用帶有 jitter 的指數退避。

至於工作進程分配,考慮分層模型:為最高流量的租戶設置一個小的專用工作進程池,為其他人設置共享工作進程。這將避免過度配置,同時仍然保護頂級租戶的吞吐量。

經常被忽視的是檢測每個租戶隊列深度和等待時間,而不僅僅是速率限制命中。這通常是你在出現 SLA 問題之前找到真正瓶頸的地方。

你調用的是什麼類型的外部 API?有些 API 提供突發額度,可以在相當程度上緩解重試問題。

在 Redis 中使用按租戶的令牌桶是正確的想法,關鍵的設計選擇是在工作到達 worker 之前執行限制,而不是在 worker 內部執行。如果 worker 拉取工作,然後在速率限制上等待,你就會浪費 worker 的容量做無用功,這正好是你所說的「一個忙碌的租戶會吃掉所有人的容量」的問題。

所以架構應該是這樣的:webhook 到佇列,然後是一個檢查租戶在 Redis 中的桶的門,只有當該租戶有預算時才將工作發送給 worker,否則就用延遲重新佇列。這樣可以防止受限租戶的待辦事項阻塞其他租戶。

關於重試突發:你的重試需要按租戶的退避策略,而不是全域的退避策略,否則一個已經達到其限制的租戶會重試進入相同的牆,並放大突發。指數退避加抖動,計入同一個桶。

對於真正的公平性,當有數百個租戶時,為少數幾個高流量租戶分配獨立佇列,為長尾租戶使用共享佇列通常是務實的分割。完全的按租戶佇列隔離更整潔,但運維的工作量要大得多。還有一點:對按租戶的佇列深度進行檢查,這樣當某個佇列的備份超過閾值時,你可以提前發現,而不是等到那個租戶抱怨他們的工作延遲了數小時才發現。

謝謝各位