接口限流
2026年1月18日 · 145 字 · 1 分钟
简单介绍令牌桶算法和golang官方的接口限流库
接口限流
令牌桶算法
r:每秒钟向通内放入r个令牌,即每隔1/r秒放一个令牌
b:桶的最大容量是b,桶满后试图再放入的令牌将会丢弃掉
当有人请求n个令牌的时候,如果桶中的令牌数小于n则请求方阻塞或者直接放弃,否则直接取走n个令牌
例子
假如r=10,b=5
那么每隔0.1秒产生一个令牌,则0.5秒桶就满了,之后生成就装不下去了,加入再0.7秒到0.8秒之间,有5个人想请求1个令牌,全部都可以顺利取走
那么加入0.9秒一直在生产令牌,那么还是只有5个令牌,0.9秒到1秒取走一个,那么1秒内就有处理了一个请求
场景
秒杀场景:如果有10个商品,那么就可以设置令牌的初始为10,谁手快就把令牌抢走了,如果谁不付款,就把令牌归还,谁再去抢
限制qps
golang官方的限流器
golang.org/x/time/rate 是 Go 官方提供的令牌桶算法限流器实现,被广泛应用于 Kubernetes 等大型开源项目中。
核心概念
- Limit: 事件发生的最大频率(每秒事件数),类型为
float64 - Limiter: 限流器核心结构,控制事件频率
- b (burst): 令牌桶的最大容量,允许突发流量
快速使用
import "golang.org/x/time/rate"
// 创建一个限流器: 每秒10个请求,突发容量100
limiter := rate.NewLimiter(rate.Limit(10), 100)
核心方法
1. Allow / AllowN - 非阻塞检查
// 检查是否允许当前请求通过(不阻塞)
if limiter.Allow() {
// 处理请求
}
// 检查是否允许n个请求通过
if limiter.AllowN(time.Now(), 5) {
// 处理5个请求
}
Allow 返回 true 表示有足够令牌,调用方可继续执行;返回 false 表示被限流。
2. Reserve / ReserveN - 预约令牌
// 预约一个令牌用于未来使用
r := limiter.Reserve()
if !r.OK() {
// 无法获取令牌
}
// 等待delay后使用令牌
time.Sleep(r.Delay())
// 执行操作...
// 可以取消预约
r.Cancel()
适用于需要预知等待时间并做出决策的场景。
3. Wait / WaitN - 阻塞等待(推荐)
// 等待获取1个令牌(阻塞,直到获取到或上下文取消)
err := limiter.Wait(ctx)
// 等待获取n个令牌
err := limiter.WaitN(ctx, 5)
这是最常用的方法,会阻塞直到获取到所需令牌或上下文超时。
动态调整限流
// 动态调整速率(从当前时间开始)
limiter.SetLimit(rate.Limit(20))
// 动态调整桶容量
limiter.SetBurst(200)
// 在指定时间点调整
limiter.SetLimitAt(time.Now(), rate.Limit(15))
limiter.SetBurstAt(time.Now(), 100)
获取限流器状态
// 获取当前速率限制
fmt.Println("Rate:", limiter.Limit()) // 如: 10
// 获取当前突发容量
fmt.Println("Burst:", limiter.Burst()) // 如: 100
// 获取当前可用令牌数
fmt.Println("Tokens:", limiter.Tokens())