Spotify 速率限制實踐與 Envoy 濾波器選型

引言

在現代雲原生架構中,速率限制(Rate Limiting)是確保系統穩定性與資源合理分配的核心機制。隨著 Spotify 用戶規模擴張至 6.75 億月活躍用戶,並面對每日 1 億請求的高流量場景,傳統的速率限制方案已無法滿足其動態桶(如用戶 ID)與高基數場景的擴展需求。本文探討 Spotify 如何透過自研的 Time Cop 解決方案,結合 Envoy 濾波器與 CNCF 生態,實現可擴展、高可用的速率限制架構,並分析其技術選型與實踐經驗。

技術定義與核心概念

速率限制的定義

速率限制針對 L7 HTTP 請求,根據請求屬性(如 IP、路徑、用戶 ID)計算時間窗口內的請求數量,超出限制時拒絕請求。其關鍵概念包含:

  • 靜態桶:預設可識別的屬性(如 URL、上游集群)。
  • 動態桶:運行時確定的屬性(如 IP、用戶 ID)。

Envoy 的角色

Envoy 是 CNCF 認證的服務網關,提供高可擴展性與靈活性,支援自定義濾波器開發。Spotify 選擇 Envoy 作為核心基礎設施(Core Infrastructure)的關鍵組成部分,透過其擴展機制實現自研速率限制方案。

技術特性與應用場景

Time Cop 設計目標

Spotify 面對的挑戰包括:

  • 高基數動態桶(如用戶 ID)的處理需求。
  • 現有方案(本地限流、全侷限流、RLQS、雲服務)的侷限性。

Time Cop 的設計目標為:

  1. 降低系統嚴格性:僅針對異常流量(如超限請求)進行限制。
  2. 提升可擴展性:避免硬性限制影響正常用戶。

核心架構與實現

Time Cop 的核心架構包含:

  • 聚合器(Aggregator):使用一致性哈希(Consistent Hashing)將動態桶分發至不同聚合器,避免數據搬移。
  • 計數機制:僅定期報告請求計數(而非每請求通訊),減少內部請求數量。
  • 阻斷動作分發:透過 Google Cloud PubSub 向所有 Envoy 傳播阻斷動作,無需每個 Envoy 直接連接聚合器。

與 RLQS 相比,Time Cop 通過定期計數與分片機制,有效降低內部請求量與數據搬移成本。

技術選型與實現細節

濾波器開發語言選型

Spotify 對 Envoy 濾波器開發語言進行評估,最終選擇 Go 為主要實現語言,原因包括:

  • 支援背景處理(Go Routine)處理計數與聚合。
  • 提供原生 Envoy 指標,符合 DevOps 要求。
  • 開發效率高,符合組織內語言生態。

其他選項的比較:

  • C++:API 成熟但開發門檻高。
  • Lua:API 表面窄,不支援背景處理。
  • Wasm:處於實驗階段,文檔混亂。

實現細節

  • 使用 Go 編寫 Envoy Filter,透過 GBC(Go Buffer Channel)與聚合器通訊。
  • 透過 PubSub 分佈阻斷動作,確保所有 Envoy 及時更新。
  • 聚合器失效時,其他聚合器仍能處理邊緣案例(一致性哈希重定向)。

系統特性與權衡

可擴展性與容錯性

  • 可擴展性:透過聚合器分片與定期計數,降低系統負載。
  • 容錯性:單個聚合器失效時,其他聚合器仍能處理大部分流量。

性能優化

  • 減少內部請求數量(從「每請求」降至「每時間窗口」),降低延遲。
  • P50 延遲增加 3ms,P99 增加 11ms,全侷限流服務 timeout 8ms。

用戶體驗

鬆弛限制條件,避免正常用戶因偶發超限受影響。

核心結論

  1. 規模化速率限制困難:無現成方案完全符合需求,需自建解決方案。
  2. Envoy 濾波器開發限制:現有選項(Go、Lua、Wasm)均存在成熟度問題,C++ 為唯一穩定選擇,但開發成本高。
  3. 社區需求呼籲:希望出現非 C++ 的穩定濾波器開發選項,未來可能透過新功能(如動態模組)改善。

關鍵技術細節

  • 聚合器容錯機制:使用 Envoy 的 Cluster 健康檢查,支援主動健康檢查與平滑切換。
  • 跨平臺編譯問題:需手動調整編譯旗標,本地編譯較為可行。
  • 指標與監控:Go 濾波器指標命名不規範,需外部系統處理;C++ 版本預期改善指標管理能力。

後續行動

  • C++ 重寫進度:完成 90% 代碼遷移,持續優化。
  • 長期目標:平衡開發效率與系統穩定性,探索 Envoy 新功能(如動態模組)以簡化開發。
  • 社區貢獻:呼籲開發更成熟的非 C++ 濾波器選項,參與相關技術討論。