元件分享之後端元件——基于Golang實作的漏桶式速率限制算法(并發限定子產品)ratelimit
背景
近期正在探索前端、後端、系統端各類常用元件與工具,對其一些常見的元件進行再次整理一下,形成标準化元件專題,後續該專題将包含各類語言中的一些常用元件。歡迎大家進行持續關注。
元件基本資訊
- 元件:ratelimit
- 開源協定:MIT license
内容
本節我們分享一個基于Golang實作的漏桶式速率限制算法ratelimit(并發限定子產品)。該實作根據請求之間的時間間隔來填充bucket,而不是需要間隔時鐘來離散地填充bucket。建立具有每秒執行的最大操作數的速率限制器。每次操作前調用Take()。Take會一直睡到你能繼續。
當然我們也可以使用golang官方的庫golang.org/x/time/rate來進行實作自己的并發限定算法包,本節中我們分享的這個速率限制器本身引入的開銷最小,如果我們需要一些更加複雜的最好使用官方庫。
以下是其網友們的對比結果
func TestQPS(t *testing.T) {
testLimiterQPS(t, 1000000)
testLimiterQPS(t, 2000000)
testLimiterQPS(t, 3000000)
}
func testLimiterQPS(t *testing.T, rate int) {
limiter := ratelimit.New(rate)
timer := time.After(time.Millisecond * 2000)
i := 0
for {
select {
case <-timer:
expEvents := 2*rate
if i > expEvents {
t.Errorf("Received number of events is bigger than expected. Got: %d; Expected: %d", i, expEvents)
}
expEventsPercent := (float64(i) / float64(expEvents)) * 100
if expEventsPercent < 90 {
t.Errorf("Received number of events is lesser than expected. Got: %d (%.2f%%); Expected: %d", i, expEventsPercent, expEvents)
}
return
default:
limiter.Take()
i++
}
}
}
--- FAIL: TestQPS (6.00s)
ratelimit_test.go:36: Received number of events is lesser than expected. Got: 1563616 (78.18%); Expected: 2000000
ratelimit_test.go:36: Received number of events is lesser than expected. Got: 2601158 (65.03%); Expected: 4000000
ratelimit_test.go:36: Received number of events is lesser than expected. Got: 3215368 (53.59%); Expected: 6000000
FAIL
FAIL github.com/uber-go/ratelimit 6.003s
更多對比可以參考這裡
使用方式如下:
1、安裝
go get github.com/uber-go/ratelimit
2、使用案例
import (
"fmt"
"time"
"go.uber.org/ratelimit"
)
func main() {
rl := ratelimit.New(100) // per second
prev := time.Now()
for i := 0; i < 10; i++ {
now := rl.Take()
fmt.Println(i, now.Sub(prev))
prev = now
}
}
本文聲明:
88x31.png
知識共享許可協定