本主題為系列文章,分上下兩篇。本文主要介紹 time/rate 的具體使用方法,另外一篇文章 《golang 限流器 time/rate 實現剖析》 則著重介紹其內部實現原理。
限流器是後台服務中的非常重要的元件,可以用來限制請求速率,保護服務,以免服務過載。
限流器的實現方法有很多種,例如滑動視窗法、token bucket、leaky bucket 等。
其實 golang 標準庫中就自帶了限流演算法的實現,即 golang.org/x/time/rate。該限流器是基於token bucket(令牌桶)實現的。
簡單來說,令牌桶就是想象有乙個固定大小的桶,系統會以恆定速率向桶中放 token,桶滿則暫時不放。
而使用者則從桶中取 token,如果有剩餘 token 就可以一直取。如果沒有剩餘 token,則需要等到系統中被放置了 token 才行。
我們可以使用以下方法構造乙個限流器物件:
limiter :=
newlimiter(10
,1);
這裡有兩個引數:
那麼,對於以上例子來說,其構造出的限流器含義為,其令牌桶大小為 1, 以每秒 10 個 token 的速率向桶中放置 token。
除了直接指定每秒產生的 token 個數外,還可以用 every 方法來指定向 token 桶中放置 token 的間隔,例如:
limit :=
every
(100
* time.millisecond)
;limiter :=
newlimiter
(limit,1)
;
以上就表示每 100ms 往桶中放乙個 token。本質上也就是一秒鐘產生 10 個。
limiter 提供了三類方法供使用者消費 token,使用者可以每次消費乙個 token,也可以一次性消費多個 token。而每種方法代表了當 token 不足時,各自不同的對應手段。
func
(lim *limiter)
wait
(ctx context.context)
(err error
)func
(lim *limiter)
waitn
(ctx context.context, n int
)(err error
)
wait 實際上就是 waitn(ctx,1)。
當使用 wait 方法消費 token 時,如果此時桶內 token 陣列不足 (小於 n),那麼 wait 方法將會阻塞一段時間,直至 token 滿足條件。如果充足則直接返回。
這裡可以看到,wait 方法有乙個 context 引數。
我們可以設定 context 的 deadline 或者 timeout,來決定此次 wait 的最長時間。
func
(lim *limiter)
allow()
bool
func
(lim *limiter)
allown
(now time.time, n int
)bool
allow 實際上就是 allown(time.now(),1)。
allown 方法表示,截止到某一時刻,目前桶中數目是否至少為 n 個,滿足則返回 true,同時從桶中消費 n 個 token。反之返回不消費 token,false。
通常對應這樣的線上場景,如果請求速率過快,就直接丟掉某些請求。
func
(lim *limiter)
reserve()
*reservation
func
(lim *limiter)
reserven
(now time.time, n int
)*reservation
reserve 相當於 reserven(time.now(), 1)。
reserven 的用法就相對來說複雜一些,當呼叫完成後,無論 token 是否充足,都會返回乙個 reservation * 物件。
你可以呼叫該物件的 delay() 方法,該方法返回了需要等待的時間。如果等待時間為 0,則說明不用等待。
必須等到等待時間之後,才能進行接下來的工作。
或者,如果不想等待,可以呼叫 cancel() 方法,該方法會將 token 歸還。
舉乙個簡單的例子,我們可以這麼使用 reserve 方法。
r := lim.
reserve()
f !r.ok(
)time.
sleep
(r.delay()
)act()
// 執行相關邏輯
limiter 支援可以調整速率和桶大小:
有了這兩個方法,可以根據現有環境和條件,根據我們的需求,動態的改變 token 桶大小和速率。
golang 限流控制
限流 日常開發中,一般會遇到幾種場景需要限流,比如有個api server,需要限制單個使用者的呼叫頻率,避免使用者惡意刷介面或者突發大流量導致服務不可用等,這邊記錄幾個常用的限流方法。併發控制 簡單的併發控制,使用者的所有請求丟到乙個channel裡,再指定乙個帶緩衝區的channel為併發池,緩...
MSP430 TIMER A定時器設定示例
先記下來,以後看,說不定就會了呢 問題很多,咱啥都不懂,能看出歡迎討論哈 直接設定 ta0cctl0 ccie ccr0 interrupt enabled ta0ccr0 1000 意思是週期為1000ms 1hz ta0ctl tassel 2 mc 1 taclr 選擇時鐘源smclk,遞增模...
RedisTemplate 實現通用限流器
乙個安全的介面限流肯定少不了,登入尤其如此。比如驗證碼傳送,驗證碼驗證試錯,密碼登入試錯,這些雖然是不同的業務,但是目的都是乙個就是,對於某些使用者的某種行為在一段時間內的的允許次數進行限制 對於此我們抽象出來四個東西 接下來我們借助redis來實現這功能 redis中有一種資料型別 zset 簡單...