Golang实现请求限流的几种办法(小结)

2020-01-28 13:59:37于丽

Multirun start
     task id 0 , timeout
     task id 1 , timeout
     task id 2 , sleep 1 second
     Multissh finished. Process time 5s. Number of task is 3

如果修改并发限制为2:


chLimit := make(chan bool, 2)

运行结果:

Multirun start
    task id 0 , timeout
    task id 1 , timeout
    task id 2 , sleep 1 second
    Multissh finished. Process time 3s. Number of task is 3

使用计数器实现请求限流

限流的要求是在指定的时间间隔内,server 最多只能服务指定数量的请求。实现的原理是我们启动一个计数器,每次服务请求会把计数器加一,同时到达指定的时间间隔后会把计数器清零;这个计数器的实现代码如下所示:


type RequestLimitService struct {
  Interval time.Duration
  MaxCount int
  Lock   sync.Mutex
  ReqCount int
}
 
func NewRequestLimitService(interval time.Duration, maxCnt int) *RequestLimitService {
  reqLimit := &RequestLimitService{
    Interval: interval,
    MaxCount: maxCnt,
  }
 
  go func() {
    ticker := time.NewTicker(interval)
    for {
      <-ticker.C
      reqLimit.Lock.Lock()
      fmt.Println("Reset Count...")
      reqLimit.ReqCount = 0
      reqLimit.Lock.Unlock()
    }
  }()
 
  return reqLimit
}
 
func (reqLimit *RequestLimitService) Increase() {
  reqLimit.Lock.Lock()
  defer reqLimit.Lock.Unlock()
 
  reqLimit.ReqCount += 1
}
 
func (reqLimit *RequestLimitService) IsAvailable() bool {
  reqLimit.Lock.Lock()
  defer reqLimit.Lock.Unlock()
 
  return reqLimit.ReqCount < reqLimit.MaxCount
}

在服务请求的时候, 我们会对当前计数器和阈值进行比较,只有未超过阈值时才进行服务:


var RequestLimit = NewRequestLimitService(10 * time.Second, 5)
 
func helloHandler(w http.ResponseWriter, r *http.Request) {
  if RequestLimit.IsAvailable() {
    RequestLimit.Increase()
    fmt.Println(RequestLimit.ReqCount)
    io.WriteString(w, "Hello world!n")
  } else {
    fmt.Println("Reach request limiting!")
    io.WriteString(w, "Reach request limit!n")
  }
}
 
func main() {
  fmt.Println("Server Started!")
  http.HandleFunc("/", helloHandler)
  http.ListenAndServe(":8000", nil)
}

完整代码 url

使用golang官方包实现httpserver频率限制

使用golang来编写httpserver时,可以使用官方已经有实现好的包:


import(
  "fmt"
  "net"
  "golang.org/x/net/netutil"
)
 
func main() {
  l, err := net.Listen("tcp", "127.0.0.1:0")
  if err != nil {
    fmt.Fatalf("Listen: %v", err)
  }
  defer l.Close()
  l = LimitListener(l, max)
  
  http.Serve(l, http.HandlerFunc())
  
  //bla bla bla.................
}