番石榴的速率限制每分钟而不是秒?

2022-09-03 18:36:09

我正在尝试对用户可以使用我的 REST API 创建的帐户数量进行速率限制。

我本来希望使用番石榴,只允许一个IP在10分钟内创建5个帐户,但该方法只需要指定“每秒”的许可数量。RateLimiterRateLimiter.createdouble

有没有办法将速率限制器配置为以大于一秒的粒度释放许可证?


答案 1

来自 javadoc:RateLimiter.create

当传入请求速率超过允许PerSecond时,速率限制器将每秒释放一个许可证。(1.0 / permitsPerSecond)

因此,您可以将“小于”设置为每秒释放许可的频率低于每秒一次。permitsPerSecond1.0

在您的特定情况下,十分钟内五个帐户简化为每两分钟一个帐户,即每 120 秒一个帐户。你会通过.1.0/120permitsPerSecond

在您的使用案例中,您可能希望适应帐户创建的突发请求。该规范似乎没有定义未使用的许可证会发生什么情况,但默认实现 ,似乎允许累积到某个最大值以满足突发。这个类不是公开的,所以没有javadoc文档,但是SmoothRateLimiter源代码有一个冗长的注释,详细讨论了当前的行为。RateLimiterSmoothRateLimiter


答案 2

Guava库中有一个名为“Guava”的类,它实现了所需的行为,但它具有包本地访问权限,因此我们无法直接使用它。还有一个 Github 问题可以公开访问该类:https://github.com/google/guava/issues/1974SmoothRateLimiter.SmoothBursty

如果您不愿意等到他们发布新版本的速率限制器,则可以使用反射来实例化速率限制器。像这样的东西应该工作:SmoothBursty

Class<?> sleepingStopwatchClass = Class.forName("com.google.common.util.concurrent.RateLimiter$SleepingStopwatch");
Method createStopwatchMethod = sleepingStopwatchClass.getDeclaredMethod("createFromSystemTimer");
createStopwatchMethod.setAccessible(true);
Object stopwatch = createStopwatchMethod.invoke(null);

Class<?> burstyRateLimiterClass = Class.forName("com.google.common.util.concurrent.SmoothRateLimiter$SmoothBursty");
Constructor<?> burstyRateLimiterConstructor = burstyRateLimiterClass.getDeclaredConstructors()[0];
burstyRateLimiterConstructor.setAccessible(true);

RateLimiter result = (RateLimiter) burstyRateLimiterConstructor.newInstance(stopwatch, maxBurstSeconds);
result.setRate(permitsPerSecond);
return result;

是的,新版本的番石榴可能会阻止你的代码,但如果你愿意接受这种风险,这可能是要走的路。


推荐