This repo is an IP rate limit middleware practice by Go.
System Prerequisites
- Go 1.15 or latter
git clone https://github.com/hjcian/go-ip-rate-limiter.git
cd go-ip-rate-limiter
go install
go test ./... -v
go run main.go
假設:自第一次 Request 起算,每個 IP 每分鐘僅能接受 60 個 requests
- 在一分鐘內第 n 個 request,X-Ratelimit-Limit-Used 則顯示 n
- n <= 60
$ curl -I http://localhost:8080/foobar
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Ratelimit-Limit-Ip: ::1
X-Ratelimit-Limit-Per-Minute: 60
X-Ratelimit-Limit-Remaining: 59
X-Ratelimit-Limit-Reset: 1604828729
X-Ratelimit-Limit-Used: 1
Date: Sun, 08 Nov 2020 09:47:00 GMT
Content-Length: 13
- 在一分鐘內第 61 個 request 則顯示 Error Status Code 429
$ curl -I http://localhost:8080/foobar
HTTP/1.1 429 Too Many Requests
X-Ratelimit-Limit-Ip: ::1
X-Ratelimit-Limit-Per-Minute: 60
X-Ratelimit-Limit-Remaining: 0
X-Ratelimit-Limit-Reset: 1604828820
X-Ratelimit-Limit-Used: 60
Date: Sun, 08 Nov 2020 09:47:21 GMT
Header name | Description |
---|---|
X-Ratelimit-Limit-Ip | client 的 IP |
X-Ratelimit-Limit-Per-Minute | 預設的上限 (rate limit) |
X-Ratelimit-Limit-Remaining | 此分鐘的 fixed window 內還剩下的額度 |
X-Ratelimit-Limit-Reset | 下一次重置的 UNIX time |
X-Ratelimit-Limit-Used | 此分鐘的 fixed window 內已使用的額度 |
- 採用 Fixed window 策略來實作 IP rate limit
- 採用 in-memory 的物件實作基本概念
IPRateLimiter
- 此為一個 goroutine-safed 物件,負責管理 IP 與
RateLimiter
的對應 - 透過
GetLimiter(ip)
方法提供取得 IP 的RateLimiter
,得在 middleware 的 routine 中使用 - goroutine-safed 的考量則是有 同一個新IP 並發地存取 server 時,避免在新建
RateLimiter
時出現 race condition
RateLimiter
- 此為一個 goroutine-safed 物件,為每一個 IP 自己的 fixed-window limits
- 負責管理該 IP 的使用額度,並透過
Allow()
方法來檢查是否可用 - goroutine-safed 的考量則是有 同一個新IP 並發地存取 server 時,避免記數出現 race condition (可能會少記到)
- GitHub’s Rate Limiting Documentation for Developers
- Rate Limiting HTTP Requests in Go based on IP address
- golang/time/rate/rate.go
- 做一些 Load testing 了解目前的 locking implementation 對吞吐量影響多少
limiter := ipLimiter.GetLimiter(ip) isAllow, statusSnapshot := limiter.Allow()
GetLimiter(ip)
有 lock 避免 goroutines 搶 ipLimiter 物件Allow()
有 lock 避免同個 IP 的 requests 搶內部的 limiter 物件
- 目前未限制 IP 總量或使用 LRU 策略,
ipLimiter
物件可能會儲存過多的 IP 佔用記憶體,應考慮- 有支背景執行的 goroutine 檢查
ipLimiter
內是否已有 IP 物件已可 reset,若可則清除 - 使用外部資料庫系統儲存
- 有支背景執行的 goroutine 檢查