Cvgo 提供了一个简单的令牌桶限流器,匀速向桶中添加令牌,服务请求时从桶中获取令牌,根据是否获取到了令牌来决定是否执行后续逻辑。 相关文献
使用示例
限制 100 TPS 为例
package main
import (
"fmt"
"cvgo/kit/gokit"
"time"
)
func main() {
// 填充令牌
var restrictor = gokit.NewTokenBucket(time.Millisecond*10, 100)
// 填充令牌是异步的,睡眠一会便能获取到令牌
time.Sleep(time.Second * 1)
// 取令牌
token := restrictor.TakeToken()
if token {
fmt.Println("获得令牌")
} else {
fmt.Println("没有令牌,请稍后再试")
}
}
把允许的最大访问比做一个桶,匀速向桶中添加令牌,服务请求时需要从桶中获取令牌,如果没有令牌不执行业务逻辑,可以选择等待,或者放弃。
填充令牌:gokit.NewTokenBucket(fillInterval time.Duration, cap int)
- fillInterval: 每隔多久往桶中填充一个令牌
- cap: 桶容量
例如gokit.NewTokenBucket(time.Millisecond*10, 100)
就是每 10ms 填充一个令牌,1 秒刚好放进来 100 个,也就是 100 TPS
获取令牌:gokit.TakeToken(await ...bool)
- await: 获取不到令牌时的行为。传 true 时如果桶中没有令牌则会阻塞线程,等待桶中有令牌的时候才解除阻塞,即把流量挡着等有空位一个放一个进来。 传 false 时不会阻塞等待,直接返回现在有没有令牌,即服务熔断。
最佳实践
设置限流器
你可以在程序启动时调用 Restrictor = gokit.NewTokenBucket()
填充令牌,一般我会创建一个 boot
包,这个包下面专门写一些程序启动时的初始化逻辑。
然后将 boot.Restrictor
作为全局变量。
对业务 限流
在开发 Web 服务时你可以对单个接口调用 gokit.TakeToken()
来实现限流。也可以结合
自定义中间件
来对一组路由或全局路由(整个服务)进行限流。