go-rate
https://pkg.go.dev/github.com/beefsack/go-rate#section-sourcefiles
用法
new():創(chuàng)建一個實例wait():用來阻塞等待try():返回兩個值,一個是表示是否可以立刻執(zhí)行,另一個是需要延遲多久執(zhí)行
實現(xiàn)
它的實現(xiàn)是,任何一段時間interval內,不能有超過limit個請求
維護一個隊列,隊列頭是最早的時間,隊列元素不會刪(相當于固定的token數(shù)),到了limit后就從頭部移動到尾部
假如當前隊列中數(shù)目不超過limit個(最一開始的情況)
后面的情況就是:每次對比下隊列中最早的時間和當前時間,最早時間超過了當前時間說明已經被處理過了相當于有空閑token了,所以可以處理(設置時間,移動到隊列尾),不用sleep;否則就sleep這個差值。
// Try returns true if under the rate limit, or false if over and the
// remaining time before the rate limit expires.
func (r *RateLimiter) Try() (ok bool, remaining time.Duration) {
r.mtx.Lock()
defer r.mtx.Unlock()
now := time.Now()
if l := r.times.Len(); l < r.limit {
r.times.PushBack(now)
return true, 0
}
frnt := r.times.Front()
if diff := now.Sub(frnt.Value.(time.Time)); diff < r.interval {
return false, r.interval - diff
}
frnt.Value = now
r.times.MoveToBack(frnt)
return true, 0
}
關鍵的操作是:if diff := now.Sub(frnt.Value.(time.Time)); diff < r.interval
走到這里隊列是已經滿了,必須擠掉一個人,且是擠掉最老的人,frnt是隊列中最老的時間,所以當前時間和他相比,只要當前時間比最老的時間老且超過的時間小于r.interval - diff。
設計的含義是:r.interval這段時間內只能有r.limit個元素,隊列長度最大就是r.limit;隊列從頭到尾時間是越來越新(大)。所以如果來一個新的請求,隊列又滿了,那么需要這個新請求的時間比最老的時間大且要大r.interval這么久,因為超過r.interval,這個最老的請求就可以移除了
aa
其他
它的處理不是時間片均勻的, 比如說設置1s有100個token,有100個線程來搶,cpu處理很快的話,可能0.1秒就處理完了剩下0.9秒都是閑的,這樣的話CPU峰值會高但其他時間可能很閑。即CPU的工作不是很均勻。
增加分時間段不同的限流的功能
隊列長度是動態(tài)變化的,不同的時間段,隊列長度不同