Limit是长期平均速率(token/秒),Burst是桶容量(最大token数),二者需匹配:Burst至少≥Limit,动态调速须同时SetLimit和SetBurst;限请求频次用rate,限带宽用juju/ratelimit;Allow()快速拒绝,Reserve()预占,Wait()阻塞等待并务必传超时context;IP限流需防map内存泄漏,应加TTL或LRU清理。

rate.Limiter 的 Limit 和 Burst 到底怎么设才不翻车
直接说结论:Limit 是长期平均速率(单位:token/秒),Burst 是桶容量(最大可攒多少 token),两者必须配合理解,不能只调大 Limit 就以为“立刻变快”。
常见错误是这么干:limiter.SetLimit(10) 后马上期望下一秒能 Allow() 10 次——但实际可能只成功 5 次。原因在于:桶里 token 不是瞬间补满的,它依赖 advance() 函数按时间推算,而初始 token 数 = 上次剩余 + Limit × 经过时间。如果刚从 5 QPS 切到 10 QPS,但距离上次调用还不到 1 秒,最多只多出不到 10 个 token,且受 Burst 上限压制。
-
Burst至少要 ≥Limit,否则新速率永远达不到(比如Limit=10但Burst=5,桶最多存 5 个 token,再快也白搭) - 想支持突发流量,
Burst可设为Limit × 2或更高(如 10 QPS 配Burst=20) - 动态调速时,应同时调
SetLimit()和SetBurst(),否则新Limit被旧Burst卡住
上传/下载限速该用 rate 还是 juju/ratelimit
标准库 golang.org/x/time/rate 专为“请求频次”设计(单位:次/秒),不适合字节级流控;而 github.com/juju/ratelimit 是为“数据吞吐”量身定制的(单位:字节/秒),二者定位不同,混用会出问题。
比如你用 rate.NewLimiter(1*1024*1024, 1*1024*1024) 去限上传流——它根本不知道“1MB”是字节数,只会当“1048576 次请求”,结果一读就失败或行为错乱。
- 限 HTTP 请求频率(如每 IP 每秒最多 5 次)→ 用
rate.Limiter - 限文件上传/下载带宽(如限制上传速度 ≤ 1MB/s)→ 用
ratelimit.NewBucketWithRate(fillRate, capacity) -
fillRate设成目标速率(如1 * 1024 * 1024),capacity建议 ≥fillRate,避免首包就被卡
Allow()、Reserve()、Wait() 三个方法怎么选
它们本质都是消费 token,但对“失败”的处理逻辑完全不同,选错会导致阻塞、超时或误拒。
Allow() 是最轻量的试探:无 token 立刻返回 false,适合快速拒绝;Reserve() 返回一个 Reservation,让你自己决定是否执行(可用于预占+延迟执行);Wait() 会阻塞直到拿到 token,适合不能丢弃请求的场景(如关键任务队列)。
- 做 API 限流并返回
429 Too Many Requests→ 用Allow() - 需要预留 token 并稍后执行(比如异步写日志前先锁资源)→ 用
Reserve()+OK()判断 +Cancel()或Delay() - 后台任务队列必须逐个处理,宁可等也不跳过 → 用
Wait(),但务必传带超时的context.Context,否则可能永久阻塞
基于 IP 的限流为什么容易内存泄漏
典型写法是用 map[string]*rate.Limiter 缓存每个 IP 的限流器,但没人清理不用的 IP,时间一长 map 越来越大,GC 压力飙升。
这不是 rate 包的问题,是你没管生命周期。官方文档明确提醒:Limiter 本身无状态,但 map 缓存需要主动维护。
- 加个定时清理 goroutine,定期扫描 map,删除超过 30 分钟没访问的 IP 条目
- 改用带 TTL 的缓存(如
github.com/bluele/gcache),设置自动过期 - 更稳妥的做法:用 LRU cache(如
github.com/hashicorp/golang-lru),限制最大 IP 数(如 10000),超了自动淘汰老条目
真正麻烦的从来不是“怎么加限流”,而是“怎么不让限流器自己变成瓶颈”。token 计算本身很快,但 map 无界增长、goroutine 泄漏、context 忘传超时——这些才是线上事故高频点。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











