我想有一个速率限制器,以避免溢出(绝对不超过n个电话在t期间)。我尝试了guava的RateLimitor,并创建了以下测试用例。
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));
}
}
}
不幸的是,测试失败了。
阅读GuavaRateLimitor的源代码,我们有以下方法:
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。我能知道我是否能避免它,或者把它减少到零吗?
谢谢你的帮助。
暂无答案!
目前还没有任何答案,快来回答吧!