如何解决如何避免 Guava RateLimiter 存储未使用的许可证?
我想要一个速率限制器来避免溢出(在 T 持续时间内绝对不超过 N 个调用)。我使用 Guava 的 RateLimiter 进行了尝试,并创建了以下测试用例。
import com.google.common.util.concurrent.RateLimiter;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import static java.time.Duration.between;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static org.assertj.core.api.Assertions.assertthat;
import static org.assertj.core.api.Assertions.assertthatCode;
class RateLimiterTest {
@Test
void test_guava_rate_limit() throws Exception {
final int queryPerSecond = 10;
final Random random = new Random(System.nanoTime());
final RateLimiter rateLimiter = RateLimiter.create(queryPerSecond);
final List<Instant> emitTimes = new ArrayList<>();
final int maxSleepIntervalInNanoseconds = 1000 / queryPerSecond * 2;
for (int i = 0; i < 10 * queryPerSecond; i++) {
MILLISECONDS.sleep(random.nextInt(maxSleepIntervalInNanoseconds));
rateLimiter.acquire();
emitTimes.add(Instant.Now());
}
for (int i = 0; i < emitTimes.size() - queryPerSecond - 1; i++) {
final Duration timetook = between(emitTimes.get(i),emitTimes.get(i + queryPerSecond + 1));
assertthat(timetook)
.isGreaterThanorEqualTo(Duration.ofSeconds(1));
}
}
}
不幸的是,测试失败了。
阅读Guava的RateLimiter源码,我们有以下方法:
public static RateLimiter create(double permitsPerSecond) {
/*
* The default RateLimiter configuration can save the unused permits of up to one second. This
* is to avoid unnecessary stalls in situations like this: A RateLimiter of 1qps,and 4 threads,* all calling acquire() at these moments:
*
* T0 at 0 seconds
* T1 at 1.05 seconds
* T2 at 2 seconds
* T3 at 3 seconds
*
* Due to the slight delay of T1,T2 would have to sleep till 2.05 seconds,and T3 would also
* have to sleep till 3.05 seconds.
*/
return create(permitsPerSecond,SleepingStopwatch.createFromSystemTimer());
}
和
@VisibleForTesting
static RateLimiter create(double permitsPerSecond,SleepingStopwatch stopwatch) {
RateLimiter rateLimiter = new SmoothBursty(stopwatch,1.0 /* maxBurstSeconds */);
rateLimiter.setRate(permitsPerSecond);
return rateLimiter;
}
我怀疑这个问题是由于源代码中提到的“保存的许可证”造成的。默认的 'maxBurstSeconds' 为 1s。我可以知道我是否可以避免它,或者将其减少到零?
提前感谢您的帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。