golang限流器
阿新 • • 發佈:2020-09-06
服務限流
在突發的流量下,通過限制使用者訪問的流量,保證服務能夠正常執行
常見的限流思路
- 排隊
- 應用場景:秒殺搶購,使用者點選搶購之後,進行排隊,直到搶到或售罄為止
- 拒絕
- 應用場景:除秒殺之外的任何場景
限流演算法
- 計數器限流演算法
- 漏桶限流演算法
- 令牌桶限流演算法
計數器限流演算法
- 在單位時間內進行計數,如果大於設定的最大值,則進行拒絕
- 如果過了單位時間,則重新進行計數
package main import ( "fmt" "sync/atomic" "time" ) type CounterLimit struct{ counter int64 //計數器 limit int64 //指定時間視窗內允許的最大請求數 intervalNano int64 //指定的時間視窗 unixNano int64 //unix時間戳,單位為納秒 } func NewCounterLimit(interval time.Duration, limit int64) *CounterLimit { return &CounterLimit{ counter: 0, limit: limit, intervalNano: int64(interval), unixNano: time.Now().UnixNano(), } } func (c*CounterLimit) Allow() bool { now := time.Now().UnixNano() if now-c.unixNano > c.intervalNano { //如果當前過了當前的時間視窗,則重新進行計數 atomic.StoreInt64(&c.counter, 0) atomic.StoreInt64(&c.unixNano, now) return true } atomic.AddInt64(&c.counter, 1) return c.counter < c.limit //判斷是否要進行限流 } func main() { limit := NewCounterLimit(time.Second, 100) m := make(map[int]bool) for i := 0; i < 1000; i++ { allow := limit.Allow() if allow { //fmt.Printf("i=%d is allow\n", i) m[i] = true } else { //fmt.Printf("i=%d is not allow\n", i) m[i] = false } } for i := 0; i < 1000; i++ { fmt.Printf("i=%d allow=%v\n", i, m[i]) } }
計數器限流演算法
優點:
實現非常簡單
缺點:
突發流量會出現毛刺現象
比如一秒限流100個請求, 前100ms內處理完了100個請求,後900ms時間內沒有請求處理
計數不準確