Golang限流首选rate.Limiter令牌桶实现,支持HTTP中间件统一管控、多维度差异化配置及Redis分布式协同,需配合监控告警确保有效性。

用 Golang 实现请求限流,核心是控制单位时间内处理的请求数量,防止后端被突发流量打垮。最常用、最实用的方式是令牌桶(Token Bucket)和漏桶(Leaky Bucket),Golang 标准库 golang.org/x/time/rate 提供了基于令牌桶的高效实现,开箱即用、线程安全、内存占用低。
使用 rate.Limiter 快速接入限流
rate.Limiter 是 Go 官方维护的轻量级限流器,适合 HTTP 中间件、RPC 服务入口、数据库连接池前置等场景。
- 创建限流器:
limiter := rate.NewLimiter(rate.Limit(100), 5)表示每秒最多允许 100 个请求,初始可突发 5 个(burst 值) - 在 handler 中检查:
if !limiter.Allow() { http.Error(w, "Too Many Requests", http.StatusTooManyRequests); return } - 更严谨的做法是用
WaitN(ctx, n)阻塞等待(适合后台任务),或ReserveN()判断是否能预留 N 个令牌(适合批量操作)
HTTP 中间件方式统一限流
把限流逻辑抽成中间件,避免每个 handler 重复写判断,也便于按路径、用户、IP 等维度差异化配置。
- 为不同路由注册独立限流器,例如
/api/pay用严格限流(10 QPS),/api/status用宽松限流(1000 QPS) - 结合
http.Request.RemoteAddr或解析 JWT 获取用户 ID,实现“单用户每秒最多 5 次”——用sync.Map或 Redis 缓存每个 key 对应的 limiter 实例(注意定期清理过期 key) - 返回标准限流头:
w.Header().Set("X-RateLimit-Limit", "100")、"X-RateLimit-Remaining"、"Retry-After"
应对分布式场景:多实例共享限流状态
单机 rate.Limiter 无法跨进程同步,高可用服务通常部署多个副本,此时需外部协调。
立即学习“go语言免费学习笔记(深入)”;
- 用 Redis + Lua 脚本实现原子性限流(如 INCR + EXPIRE 组合),推荐使用
github.com/bsm/redislock或直接调用redis.Client.Eval() - 更成熟的方案是集成 Sentinel(阿里开源)或 Concurrency Limit(Netflix 的 concurrency-limits-go),它们支持动态调整阈值、自动熔断、指标上报
- 注意网络延迟影响:Redis 限流会增加 RT,建议设置超时(如 5ms)并降级为本地 limiter(fail-open 策略)
监控与可观测性不能少
限流不是设完就完事,必须知道它什么时候起作用、是否误伤正常流量、瓶颈在哪。
- 记录被拒绝的请求日志,字段至少包含路径、IP、时间、限流器名称,方便排查
- 用 Prometheus 暴露指标,例如
http_requests_limited_total{route="/api/user", reason="burst"} - 搭配 Grafana 看板观察 QPS 曲线与限流触发率,若长期 >80% 触发,说明阈值设低了或真有攻击










