如何避免Guava存放未使用的许可证?

wsewodh2  于 2021-06-27  发布在  Java
关注(0)|答案(0)|浏览(291)

我想有一个速率限制器,以避免溢出(绝对不超过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。我能知道我是否能避免它,或者把它减少到零吗?
谢谢你的帮助。

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题