Go官方的限流器 time


Go官方的限流器 time/rate 如何使用

本主題為系列文章,分上下兩篇。本文主要介紹time/rate的具體使用方法,下一篇文章將會著重介紹其內部實現原理。

限流器是後臺服務中的非常重要的組件,可以用來限制請求速率,保護服務,以免服務過載。限流器的實現方法有很多種,例如滑動窗口法、Token Bucket、Leaky Bucket等。

其實golang標準庫中就自帶了限流算法的實現,即golang.org/x/time/rate。該限流器是基於Token Bucket(令牌桶)實現的。

簡單來說,令牌桶就是想象有一個固定大小的桶,系統會以恆定速率向桶中放Token,桶滿則暫時不放。而用戶則從桶中取Token,如果有剩餘Token就可以一直取。如果沒有剩餘Token,則需要等到系統中被放置了Token才行。

本文則主要集中介紹下該組件的具體使用方法:

構造一個限流器

我們可以使用以下方法構造一個限流器對象:

<code>limiter := NewLimiter(10, 1);/<code>

這裡有兩個參數:

  1. 第一個參數是r Limit。代表每秒可以向Token桶中產生多少token。Limit實際上是float64的別名。
  2. 第二個參數是b int。b代表Token桶的容量大小。

那麼,對於以上例子來說,其構造出的限流器含義為,其令牌桶大小為1, 以每秒10個Token的速率向桶中放置Token。

除了直接指定每秒產生的Token個數外,還可以用Every方法來指定向Token桶中放置Token的間隔,例如:

<code>limit := Every(100 * time.Millisecond);
limiter := NewLimiter(limit, 1);/<code>

以上就表示每100ms往桶中放一個Token。本質上也就是一秒鐘產生10個。

Limiter提供了三類方法供用戶消費Token,用戶可以每次消費一個Token,也可以一次性消費多個Token。而每種方法代表了當Token不足時,各自不同的對應手段。

Wait/WaitN

<code>func (lim *Limiter) Wait(ctx context.Context) (err error)
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)/<code>

Wait實際上就是WaitN(ctx,1)。

當使用Wait方法消費Token時,如果此時桶內Token數組不足(小於N),那麼Wait方法將會阻塞一段時間,直至Token滿足條件。如果充足則直接返回。

這裡可以看到,Wait方法有一個context參數。我們可以設置context的Deadline或者Timeout,來決定此次Wait的最長時間。

Allow/AllowN

<code>func (lim *Limiter) Allow() bool
func (lim *Limiter) AllowN(now time.Time, n int) bool/<code>

Allow實際上就是AllowN(time.Now(),1)。

AllowN方法表示,截止到某一時刻,目前桶中數目是否至少為n個,滿足則返回true,同時從桶中消費n個token。反之返回不消費Token,false。

通常對應這樣的線上場景,如果請求速率過快,就直接丟到某些請求。

Reserve/ReserveN

<code>func (lim *Limiter) Reserve() *Reservation
func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation/<code>

Reserve相當於ReserveN(time.Now(), 1)。

ReserveN的用法就相對來說複雜一些,當調用完成後,無論Token是否充足,都會返回一個Reservation*對象。

你可以調用該對象的Delay()方法,該方法返回了需要等待的時間。如果等待時間為0,則說明不用等待。必須等到等待時間之後,才能進行接下來的工作。

或者,如果不想等待,可以調用Cancel()方法,該方法會將Token歸還。

舉一個簡單的例子,我們可以這麼使用Reserve方法。

<code>r := lim.Reserve()
f !r.OK() {
// Not allowed to act! Did you remember to set lim.burst to be > 0 ?
return
}
time.Sleep(r.Delay())
Act() // 執行相關邏輯/<code>

動態調整速率

Limiter支持可以調整速率和桶大小:

  1. SetLimit(Limit) 改變放入Token的速率
  2. SetBurst(int) 改變Token桶大小

有了這兩個方法,可以根據現有環境和條件,根據我們的需求,動態的改變Token桶大小和速率。


分享到:


相關文章: