guava ratelimiter 是线程安全的令牌桶实现,需单例使用、禁用频繁创建,动态调速用 setrate 会清空令牌;漏桶需组合队列与定时器实现;tryacquire 失败常见于预热、单位误用或错误异常处理;go 的 rate.limiter 默认漏桶语义且控制更精细。

Java 里用 RateLimiter 实现令牌桶,别直接 new
Guava 的 RateLimiter 是最常用的令牌桶实现,但它不是线程安全的“万能对象”——创建后不能随意修改速率,且内部状态依赖于系统时钟。实际用的时候,得把它当单例或配置化对象来管。
- 初始化必须用
RateLimiter.create(double permitsPerSecond),别自己写构造函数(它没 public 构造) - 如果需要动态调速,得用
setRate(double),但注意:这会清空当前未消耗的令牌,并可能触发突发流量(因为重置了内部时间窗口) - 不要在每次请求都
new RateLimiter.create(10),对象创建开销小,但丢失了限流上下文,等同于没限流 - 对响应时间敏感的服务,慎用
acquire();它会阻塞直到拿到令牌,建议优先用tryAcquire(long timeout, TimeUnit)配合降级逻辑
漏桶算法在 Netty 或 Spring WebFlux 中怎么落地
漏桶强调恒定输出速率,天然适合 IO 层做缓冲。但 Java 生态里没有开箱即用的“标准漏桶类”,得靠组合实现:用队列 + 定时任务/调度器模拟“匀速漏水”。
- Netty 场景下,更推荐用
ChannelHandler+HashedWheelTimer控制出站消息节奏,而不是在业务层塞个 BlockingQueue - Spring WebFlux 里想做漏桶,别碰
Flux.bufferTimeout()—— 它按时间和数量双触发,行为不等于漏桶;应该用Flux.windowTimeout()配合flatMap限频,再加个计数器控制每窗口最大发多少 - 漏桶对突发容忍低,容易堆积请求导致 OOM,务必给缓冲队列设上限(比如
new ArrayBlockingQueue(100)),并定义拒绝策略(如返回 429) - 注意系统时钟漂移:如果用
ScheduledExecutorService每 100ms “漏一次”,而 JVM 时钟被 NTP 调整过,可能造成漏速不准
tryAcquire() 返回 false 却没报错?检查这三个地方
这是最常被忽略的“假成功”场景:代码写了 if (!limiter.tryAcquire()) { return error(); },但线上还是压垮了服务。问题往往不在算法,而在用法。
- 没考虑预热期:
RateLimiter.create(10).tryAcquire()刚启动时允许突发(最多 10 个令牌瞬间获取),这不是 bug,是设计——但如果你的下游扛不住突刺,就得手动调RateLimiter.create(10, 0, TimeUnit.SECONDS)关掉预热 - 时间单位传错:
tryAcquire(1, 1, TimeUnit.MINUTES)看着像“等 1 分钟”,其实是“最多等 1 个时间单位”,而TimeUnit.MINUTES的 1 等于 60 秒,容易误判超时逻辑 - 没区分“不可用”和“拒绝”:
tryAcquire()返回 false 只代表此刻无令牌,不代表系统故障;但很多人把它当异常处理,直接抛RuntimeException,结果把限流变成了雪崩导火索
Go 的 golang.org/x/time/rate.Limiter 和 Java 版本质区别在哪
Go 标准扩展库的 Limiter 默认就是漏桶语义(虽然文档写“token bucket”,但实现是匀速填充 + 最大积压限制),而且它把“等待”和“检查”彻底拆开,比 Guava 更可控。
- Java 的
acquire()是阻塞式同步调用;Go 的Limiter.ReserveN()返回一个*Reservation,你得自己调Delay()或Cancel(),这给了业务层精细控制权 - Go 版默认启用“burst”参数(即令牌桶容量),但 Java 版的 burst 是隐式计算出来的(基于预热时间和速率),没法直接配
- Go 的
AllowN(time.Now(), n)是非阻塞纯判断,类似 Java 的tryAcquire(n),但不会影响后续调用的令牌生成节奏;而 Java 的tryAcquire(n)如果失败,会跳过这次填充周期,间接拖慢后续恢复速度 - 跨语言部署时要注意:Go 的
Limiter不共享状态,Java 的RateLimiter也不共享——分布式限流必须另上 Redis + Lua 或集中式规则中心,别指望单机类解决集群问题










