- Dcard 每天午夜都有大量使用者湧入抽卡,為了不讓伺服器過載,請設計一個 middleware:
- 限制每小時來自同一個 IP 的請求數量不得超過 1000
- 在 response headers 中加入剩餘的請求數量 (X-RateLimit-Remaining) 以及 rate limit 歸零的時間 (X-RateLimit-Reset)
- 如果超過限制的話就回傳 429 (Too Many Requests)
- 可以使用各種資料庫達成
npm install
npm build
-
Run with fixed window
npm run start:fixed-window
-
Run with sliding window
npm run start:sliding-window
-
Fixed window 以第一個請求往後一小時來劃分 window
-
Sliding window 以最後一個請求往前推一小時來劃分 window
-
我額外在 header 加上 X-RateLimit-Limit 來回傳 time window 中有多少請求額度, 以及 window 類型
- EX :
100;window=60;comment="fixed window"
代表每個 window 60 秒,並且每個 window 裡面允許 100 個請求
- EX :
-
sliding-window 不包含
X-RateLimit-Reset
因為會需要額外做計算 -
Race Condition 問題
- 目前 fixed window 不太受 Race Conditioin 影響
- 目前 sliding window 受 Race Conditioin 影響, 但整體來說仍可達到 rate limit 的效果,如要準確計算,應改善計算 remaining 的地方
- Do everything in Lua script
- 應考慮 script 的 atomic 特性會不會影響到整體運作效率
VirtualBox OS: Ubuntu 20.02 Memory: 8192 MB Processor: 8 Node12
使用 autocannon 測試 : 參數 connections 20 pipelining 4 duration 30 其餘都使用預設
先用 npm run
啟動 任一 server
然後再 npm run benchamark
這邊簡單測試一下單純兩種策略的差別,以及在此 middleware 之上再加入其他處理(例如:logger)的影響
可以看到 logger 的加入會明顯影響請求時間 (這邊可以透過不 log 被 limiter 擋下的請求來改善)
- fixed-window without logger
- fixed-window with logger
- sliding-window without logger
- sliding-window with logger
可以看到以相同時間內同一 IP 可以處理的請求數量來說 sliding-window 上的效果是跟 fixed-window 差不多的的(應該需要更深入的測試), 但實務上來說 sliding-window 可以避免瞬間流量過大
加入 logger 後可以看到對於可以處理的請求數量來說有明顯下降的趨勢(如果非必要,在設計上應考慮減少對於每個請求的前處理會做的事情)
下圖為將 logger 放在 rateLimit middleware 後的結果(只 log 被接受的請求),可以發現改善了不少
這邊把每個 connnection 都當成獨立的 client 來模擬不同客戶端同時請求的狀況(總共 20*8=160 個 client)
- fixed-window
- sliding-window
https://tools.ietf.org/id/draft-polli-ratelimit-headers-00.html