博客 / 詳情

返回

ByteByteGo學習筆記:設計限流器

在現代應用系統中,限流器(Rate Limiter)是一種至關重要的工具,用於控制客户端對服務的請求速率。

限流器的基本概念

限流器的核心功能是限制在特定時間內可以發送的請求數量。在HTTP世界中,限流器通過定義閾值來控制請求流量。以下是一些常見的限流規則:

  • 用户每秒最多可以發佈2條推文。
  • 每天最多可以創建10個賬户,且這些賬户必須來自不同的IP地址。
  • 每週最多可以從同一設備領取5次獎勵。

設計限流器的好處

  • 防止資源耗盡:通過拒絕服務(DoS)攻擊可以導致資源耗盡,幾乎所有大型科技公司都會實施某種形式的限流。例如,Twitter限制用户每3小時最多發佈300條推文。
  • 降低成本:限制過多的請求意味着更少的服務器和更多的資源分配給高優先級的API。這對於使用第三方API的公司尤為重要。
  • 防止服務器過載:通過減少服務器負載,限流器可以過濾掉由機器人或用户錯誤行為引起的過多請求。

設計範圍

在設計限流器時,需要明確其類型(構建的限流器是客户端還是服務器端API限流器)。以下是一些關鍵問題需要考慮:

  • 限流器是否根據IP地址、用户ID或其他屬性來限制API請求?
  • 限流器是否足夠靈活以支持不同的限制規則?
  • 系統是否能夠處理大量請求?
  • 系統是否在分佈式環境中工作?
  • 限流器是作為一個獨立服務還是應用代碼中實現?

系統要求

限流器系統需要滿足以下要求:

  • 準確限制過多請求。
  • 低延遲,限流器不應減慢HTTP響應時間。
  • 儘可能少地使用內存。
  • 分佈式限流,限流器可以在多個服務器或進程之間共享。
  • 異常處理,當請求被限制時,向用户提供明確的異常信息。
  • 高容錯性,例如,緩存服務器宕機時,不會影響整個系統。

高層次設計

為了簡化設計,使用基本的客户端和服務器模型進行通信。以下是兩種常見的實現方式:

  • 客户端實現:通常,客户端不是一個可靠的實現位置,因為客户端請求可以被惡意行為者偽造,而且我們可能無法控制客户端實現。
  • 服務器端實現:限流器位於服務器端。
    image
    除了客户端和服務器端實現,還有一種替代方案,即在API服務器之間創建一個限流中間件。
    image

微服務中的限流

微服務已經成為廣泛流行的架構,限流通常在稱為API網關的組件中實現。API網關是一個完全託管的服務,支持限流、終止、身份驗證、IP白名單、靜態內容服務等。API網關作為支持限流的中間件。

限流器的實現位置

在設計限流器時,需要考慮其實現位置。以下是一些指導原則:

  • 評估當前技術棧,確保編程語言能夠高效實現限流。
  • 確定適合業務需求的限流算法,並在服務器端實現。
  • 如果已經使用微服務架構並在設計中包含API網關,可以在API網關中添加限流器。
  • 如果有足夠的資源,可以自己構建限流器;否則,商業API網關可能是更好的選擇。

限流算法

1.令牌桶算法

  • 原理:令牌桶算法通過一個固定容量的桶來存儲令牌,令牌以固定速率添加到桶中。每個請求消耗一個令牌,如果桶中沒有足夠的令牌,請求將被拒絕。
  • 優點:

    • 算法簡單易懂,易於實現。
    • 內存效率高,因為只需要存儲令牌和桶的大小。
    • 允許短時間內的流量突發,因為桶中可以積累令牌。
  • 缺點:

    • 參數調整(桶大小和令牌補充速率)可能具有挑戰性,需要根據具體需求進行調優。
  • 適用場景:

    • 適用於需要靈活處理請求突發的場景。
    • 適用於分佈式系統,可以在多個服務器之間共享令牌桶。

2.漏桶算法

  • 原理:漏桶算法以固定速率處理請求,通常使用先進先出(FIFO)隊列實現。請求按固定速率從桶中流出,如果桶滿了,新的請求將被丟棄。
  • 優點:

    • 內存效率較高,因為只需要存儲請求隊列。
    • 請求以固定速率處理,適合穩定輸出速率的場景。
  • 缺點:

    • 有兩個參數(桶大小和輸出速率),可能不易調優。
    • 不允許流量突發,因為請求必須按固定速率處理。
  • 適用場景:

    • 適用於需要穩定輸出速率的場景。
    • 適用於電子商務公司,需要控制請求處理速率。

3.固定窗口計數器

  • 原理:將時間劃分為固定大小的窗口,併為每個窗口分配一個計數器。每個請求增加計數器,如果計數器達到預定義閾值,新請求將被丟棄。
  • 優點:

    • 內存效率高,因為只需要存儲計數器。
    • 易於理解,實現簡單。
  • 缺點:

    • 在窗口邊緣可能出現流量突發問題,因為計數器在每個窗口開始時重置。
  • 適用場景:

    • 適用於簡單場景,不需要複雜的流量控制。
    • 適用於對流量突發不敏感的場景。

4.滑動窗口計數器

  • 原理:結合固定窗口計數器和滑動窗口日誌,維護請求時間戳的有序集合。新請求到來時,移除過時的時間戳,如果請求數量超過閾值,請求將被拒絕。
  • 優點:

    • 非常準確,不會超過速率限制。
    • 適用於任何滾動窗口場景。
  • 缺點:

    • 消耗大量內存,因為即使請求被拒絕,時間戳仍需存儲在內存中。
  • 適用場景:

    • 適用於需要高精度控制的場景。
    • 適用於對流量控制要求嚴格的場景。

高層次架構

限流器的基本思想很簡單:需要一個計數器來跟蹤來自同一用户、IP地址等的請求數量。如果計數器超過限制,請求將被禁用。計數器可以存儲在內存緩存中,如Redis。
image

客户端發送請求到限流中間件,中間件從Redis中獲取計數器並檢查是否達到限制。如果達到限制,請求將被拒絕;否則,請求將被髮送到API服務器。

限流規則

Lyft開源了他們的限流組件,提供了一些限流規則的例子。以下是一些常見的規則:

domain: messaging
descriptors:
  - key: message_type
    value: marketing
    rate_limit:
      unit: day
      requests_per_unit: 5

這些規則通常寫在配置文件中並保存在磁盤上。

超出限流

如果請求超出限流,API將返回HTTP響應代碼429(請求過多)。根據用例,可能會將請求排隊以供後續處理。
限流器頭部
當用户請求過多時,限流器會返回以下HTTP頭部:

  • X-Ratelimit-Remaining:窗口內剩餘的允許請求數。
  • X-Ratelimit-Limit:窗口內允許的請求數。
  • X-Ratelimit-Retry-After:等待多少秒後可以再次請求。

詳細設計

規則存儲在磁盤上,工作線程頻繁從磁盤拉取規則並存儲在緩存中。當客户端發送請求到服務器時,請求首先發送到限流中間件。中間件從緩存中加載規則,並根據響應決定請求是否被轉發到API服務器。
image

分佈式環境中的限流器

在分佈式環境中構建限流器並不困難,但需要解決兩個挑戰:競態條件和同步問題。

競態條件

在高併發環境中,多個請求可能同時讀取和增加計數器,導致不正確的結果。解決競態條件的常見策略包括使用鎖和Lua腳本。

同步問題

在分佈式環境中,需要同步多個限流服務器的數據。可以使用集中式數據存儲如Redis來解決同步問題。

性能優化

對於限流器,主要關注兩個方面:

  • 多數據中心設置:由於延遲問題,大多數雲服務提供商在全球範圍內建立多個邊緣服務器位置。流量自動路由到最近的邊緣服務器以減少延遲。
  • 使用最終一致性模型同步數據:如果對最終一致性模型不熟悉,可以參考“設計鍵值存儲”章節。

    監控

    在限流器部署後,收集分析數據以檢查其有效性非常重要。主要檢查以下幾點:

  • 限流算法是否有效。
  • 限流規則是否有效。

這篇學習筆記詳細記錄了設計和實現限流器的各個方面,從基本概念到高級架構,涵蓋了關鍵知識點和重要數據。希望這些內容能夠幫助你更好地理解和應用限流器。

參考資料
ByteByteGo

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.