Go 实现单机请求限流
我们服务器对外提供接口时,通常有一些自身限制比如存储或者中间件等性能,或者是担心调用方无脑并发,我们一般要做限流措施。
通常我们限制qps,比如约定调用方,10s内最多打过来1000次请求。10s和1000次就是我们做限流的主要限制参数。
利用Go写一个限流程序很容易,如下:
limitflow.go
定义一个结构:
- 一个时间区间(需要定时清0,time.Tick非常方便)
- 限制次数
- 请求次数
- 锁(修改内部属性,这个场景读写比相似,不需要显示写读写锁,读写锁更耗性能)
package limitflow
import (
  "fmt"
  "sync"
  "time"
)
type FlowLimit struct {
  l        sync.Mutex
  interval time.Duration
  total    int64
  reqnum   int64
}
func NewFlowLimit(interval time.Duration, total int64) *FlowLimit {
  flowlimit := &FlowLimit{
    interval: interval,
    total:    total,
  }
  go func() {
    // 定时器
    tick := time.Tick(interval)
    for {
      <-tick
      flowlimit.l.Lock()
      fmt.Println("tick...")
      // 重置0
      flowlimit.reqnum = 0
      flowlimit.l.Unlock()
    }
  }()
  return flowlimit
}
// 请求数+1
func (limit *FlowLimit) Increase() {
  limit.l.Lock()
  defer limit.l.Unlock()
  limit.reqnum += 1
}
// 满足限流否
func (limit *FlowLimit) AccessOk() bool {
  limit.l.Lock()
  defer limit.l.Unlock()
  return limit.reqnum < limit.total
}
做一个web服务,模拟一个接口请求
test.go
package main
import (
  "fmt"
  "net/http"
  "time"
  "limitflow"
)
// 测试 new一个限流A
var limitA = limitflow.NewFlowLimit(10*time.Second, 3)
func main() {
  server()
}
func testFunc(w http.ResponseWriter, req *http.Request) {
  if limitA.AccessOk() {
    limitA.Increase()
    fmt.Fprintln(w, "welcome")
  } else {
    fmt.Fprintln(w, "flow limit")
  }
}
func server() {
  http.HandleFunc("/test", testFunc)
  http.ListenAndServe(":8777", nil)
}