1. 程式人生 > 實用技巧 >golang限流器

golang限流器

服務限流

在突發的流量下,通過限制使用者訪問的流量,保證服務能夠正常執行

 常見的限流思路

  •  排隊
  •  應用場景:秒殺搶購,使用者點選搶購之後,進行排隊,直到搶到或售罄為止
  •  拒絕
  •  應用場景:除秒殺之外的任何場景

 限流演算法

  •  計數器限流演算法
  •  漏桶限流演算法
  •  令牌桶限流演算法

計數器限流演算法

  • 在單位時間內進行計數,如果大於設定的最大值,則進行拒絕
  • 如果過了單位時間,則重新進行計數

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時間內沒有請求處理

  計數不準確