Go并发限流核心用rate.Limiter实现令牌桶算法,支持接口级限流(Allow/Wait)、多goroutine统一排队、用户维度细粒度限流及分布式方案,需避免重复创建、合理选型阻塞策略并添加监控头与日志。
在 Go 中实现并发任务限流,核心是控制单位时间内执行的任务数量或请求频率,避免系统过载。最常用、最自然的方式是使用 golang.org/x/time/rate 包(即 令牌桶算法),它轻量、线程安全、精度高,适合接口限流、后台任务节制等场景。
每个请求到来时尝试获取一个令牌,获取失败则拒绝或等待。适用于 HTTP 中间件或 RPC 入口:
请求,初始桶容量为 10(允许短时突发)limiter := rate.NewLimiter(100, 10)
if !limiter.Allow() { http.Error(w, "Too Many Requests", http.StatusTooManyRequests); return }
Wait 阻塞等待可用令牌(适合后台任务),或 Reserve 判断后手动 sleep(精细控制超时)当启动大量 goroutine 执行外部调用(如批量发短信、调第三方 API)时,不能靠单个 limiter 拦截入口,而需在任务执行前统一“排队”:
var taskLimiter = rate.NewLimiter(5, 10) // 每秒最多 5 个任务,最多积压 10 个
taskLimiter.Wait(ctx) —— 自动阻塞直到拿到令牌context.WithTimeout 可避免无限等待,例如:ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
err := taskLimiter.Wait(ctx)
if err != nil { /* 超时跳过该任务 */ }
单一全局限流无法满足多租户或用户级配额需求。此时需用 sync.Map 或带 TTL 的内存缓存(如 github.com/go-redis/redis)维护每个 key 的独立限流器:
map[string]*rate.Limiter + sync.RWMutex 管理(注意:rate.Limiter 本身可复用,但 map 非线程安全)github.com/uber-go/ratelimit(滑动窗口)或结合 Redis 的 INCR + EXPIRE 实现分布式限流(跨进程/实例)限流不是加个 if 就完事,几个关键细节容易被忽略:
Wait 或 ReserveN
X-RateLimit-Limit、X-RateLimit-Remaining、Retry-After,方便客户端感知