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)
}