直接用golang.org/x/time/rate能防崩,但90%限流失效源于实例未复用、key提取不准确、超时控制缺失;必须全局或按ip/用户复用rate.limiter,用sync.map缓存并自动清理,http中优先wait(ctx)而非allow(),分布式场景须改用redis+lua。

直接用 golang.org/x/time/rate 能防崩,但写错就等于没限——90% 的线上限流失效,都出在实例复用、key 提取和超时控制这三处。
rate.Limiter 实例不能每次请求 new
每个 rate.Limiter 实例维护独立的令牌桶状态。如果在 handler 里写 limiter := rate.NewLimiter(10, 20),100 个并发请求会生成 100 个桶,实际放行总量是 100 × 10 = 1000 QPS,完全失控。
- 全局统一限流(如网关总 QPS):定义一个包级变量,复用单实例
- 按用户/IP/路径差异化限流:用
sync.Map缓存,key 为"user:" + userID或"ip:" + realIP - 别用普通
map+mutex:高并发下锁竞争严重,sync.Map是唯一合理选择 - 新 key 必须配自动清理:对每个 key 启动
time.AfterFunc(30 * time.Minute, func() { syncMap.Delete(key) })
Allow() 和 Wait() 别用错场景
Allow() 是快照式非阻塞检查,只返回 bool;Wait() 会阻塞直到拿到令牌或 context 被 cancel。两者语义完全不同,混用会导致超时堆积或静默失败。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 对延迟敏感接口(如支付回调、实时搜索):用
Allow(),返回false后必须立刻return,否则业务逻辑仍会执行 - 可接受可控排队的后台任务:用
Wait(ctx),但ctx必须来自r.Context()并套context.WithTimeout(, 100*time.Millisecond) - 千万别写
Wait(context.Background()):一旦下游慢,令牌长期被占住,吞吐骤降,甚至请求永久挂起 - 需要预判等待时间(如前端提示“300ms 后重试”):改用
limiter.Reserve(),查OK()和Delay()
分布式部署必须换 Redis + Lua
rate.Limiter 只在当前进程内存生效。5 个 Pod 各跑一个 rate.NewLimiter(100, 200),入口总流量就是 500 QPS ——这不是 bug,是设计使然。跨实例限流必须依赖共享存储。
- Redis 是事实标准,etcd 次之;别信“本地缓存 + 定时同步”,时钟漂移会让配额错乱
- 必须用 Lua 脚本封装
INCR+EXPIRE+GET,拆成多次网络调用会因竞态导致计数错误 - key 命名要细粒度:
"limit:svc:user-get:12345",而不是笼统的"user-get" - 连接池要调大(
PoolSize: 50),超时设短(Timeout: 100ms),超时后建议直接放行,避免限流逻辑本身成瓶颈 - 健康检查接口(如
/health)务必跳过限流,否则 k8s probe 会反复失败
burst 和 rate 参数别按直觉设
rate.NewLimiter(10, 5) 表示长期稳定速率 ≈10 QPS,最多允许 5 个请求“借支”,不是“最多并发 5”。burst 设太小会拒掉所有毛刺,设太大则突发流量瞬间打穿下游。
-
rate.Limit单位是「令牌/秒」,不是“每 N 毫秒放 1 个”;rate.Every(200 * time.Millisecond)等价于5.0 - burst 建议 ≥
rate × 2(如 10 QPS 配burst=20),为 GC STW、网络抖动、冷启动留余量 - burst 别设成
rate × 5或更大:突发流量可能直接压垮数据库连接池或下游 API - 别把 burst 设为 1:退化成严格匀速,毫无弹性;设为 0 则
Allow()永远返回false
真正难的从来不是写通限流逻辑,而是 IP 提取是否真实(X-Real-IP 没配 TrustedProxies 就拿不到)、key 是否漏维度(比如忽略 query 参数或 header 中的 tenant ID)、Redis 故障时有没有降级开关——这些细节不处理好,限流就只是个心理安慰。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










