You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Guava RateLimiter设置每秒10个许可却无法全部获取的问题

Guava RateLimiter 为何设置10QPS却无法全部立即获取令牌?

问题场景

我正在使用Guava 32.1.1版本的RateLimiter,代码如下:

int permitsPerSecond = 10;
RateLimiter rateLimiter = RateLimiter.create(permitsPerSecond);
Stopwatch stopwatch = Stopwatch.createStarted();
int i = 0;
for (; i < permitsPerSecond; i++) {
    boolean tryAcquired = rateLimiter.tryAcquire();
    System.out.println("tryAcquired: " + tryAcquired);
}
System.out.println("Time elapsed: " + stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
System.out.println("No. of permit requests processed: " + i);

得到的输出为:

tryAcquired: true
tryAcquired: false
tryAcquired: false
tryAcquired: false
tryAcquired: false
Time elapsed: 2
No. of permit requests processed: 5

设置permitsPerSecond为10,为何不是所有tryAcquire()调用都返回true?

核心原因

Guava默认的RateLimiter.create(permitsPerSecond)是SmoothBursty实现,它的令牌生成逻辑是匀速增量发放,而非初始化时一次性填满令牌桶,结合tryAcquire()的特性导致了这个结果:

  • 令牌匀速生成:10QPS意味着每100毫秒生成1个令牌,令牌不会在RateLimiter初始化时就一次性生成10个存入桶中。
  • 无参tryAcquire()是立即尝试:这个方法等价于tryAcquire(0, TimeUnit.SECONDS),不会等待令牌生成,拿不到就直接返回false。

你的循环在2毫秒内就完成了多次调用,此时除了第一个请求能成功获取令牌(RateLimiter对首次请求做了突发优化,允许立即通过),后续请求的令牌还未生成,所以全部返回false。

调整方案

如果需要让所有请求都能获取令牌,可以根据需求选择:

  • 使用rateLimiter.acquire()替代tryAcquire():这个方法会阻塞等待,直到拿到令牌,10次请求会耗时约1秒(等待所有令牌生成)。
  • 初始化时设置突发容量:使用RateLimiter.create(permitsPerSecond, burstSeconds),指定突发秒数,让令牌桶初始预存permitsPerSecond * burstSeconds个令牌,比如RateLimiter.create(10, 1)会初始生成10个令牌,此时循环的10次tryAcquire()都会返回true。

内容的提问来源于stack exchange,提问作者RRM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:10:13