天天看點

元件分享之後端元件——基于Golang實作的漏桶式速率限制算法(并發限定子產品)ratelimit

元件分享之後端元件——基于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
    }
}      

本文聲明:

元件分享之後端元件——基于Golang實作的漏桶式速率限制算法(并發限定子產品)ratelimit

88x31.png

​​知識共享許可協定​​