Guava RateLimiterのクイックガイド
1. 概要
この記事では、GuavaライブラリのRateLimiterクラスについて説明します。
RateLimiterクラスは、何らかの処理が発生する速度を調整できるようにする構造です。 N個の許可でRateLimiterを作成する場合、プロセスは1秒あたり最大N個の許可を発行できることを意味します。
2. メーベン依存
3. RateLimiterの作成と使用
limit the rate of execution of the doSomeLimitedOperation() to 2 times per second.にしたいとしましょう
create()ファクトリメソッドを使用してRateLimiterインスタンスを作成できます。
RateLimiter rateLimiter = RateLimiter.create(2);
次に、RateLimiter,から実行許可を取得するには、acquire()メソッドを呼び出す必要があります。
rateLimiter.acquire(1);
それが機能することを確認するために、スロットルメソッドを2回続けて呼び出します。
long startTime = ZonedDateTime.now().getSecond();
rateLimiter.acquire(1);
doSomeLimitedOperation();
rateLimiter.acquire(1);
doSomeLimitedOperation();
long elapsedTimeSeconds = ZonedDateTime.now().getSecond() - startTime;
テストを簡素化するために、doSomeLimitedOperation()メソッドがすぐに完了すると仮定しましょう。
このような場合、acquire()メソッドの両方の呼び出しがブロックされないようにし、経過時間は1秒未満または1秒未満にする必要があります。両方の許可をすぐに取得できるためです。
assertThat(elapsedTimeSeconds <= 1);
さらに、1回のacquire()呼び出しですべての許可を取得できます。
@Test
public void givenLimitedResource_whenRequestOnce_thenShouldPermitWithoutBlocking() {
// given
RateLimiter rateLimiter = RateLimiter.create(100);
// when
long startTime = ZonedDateTime.now().getSecond();
rateLimiter.acquire(100);
doSomeLimitedOperation();
long elapsedTimeSeconds = ZonedDateTime.now().getSecond() - startTime;
// then
assertThat(elapsedTimeSeconds <= 1);
}
これは、たとえば、毎秒100バイトを送信する必要がある場合に役立ちます。 一度に1つの許可を取得して、1バイトを100回送信できます。 一方、100バイトすべてを一度に送信して、1回の操作で100個すべての許可を取得できます。
4. ブロッキング方法で許可を取得する
それでは、もう少し複雑な例を考えてみましょう。
100個の許可を持つRateLimiterを作成します。 次に、1000の許可を取得する必要があるアクションを実行します。 RateLimiter,の仕様によると、1秒あたり100ユニットのアクションしか実行できないため、このようなアクションは完了するまでに少なくとも10秒かかります。
@Test
public void givenLimitedResource_whenUseRateLimiter_thenShouldLimitPermits() {
// given
RateLimiter rateLimiter = RateLimiter.create(100);
// when
long startTime = ZonedDateTime.now().getSecond();
IntStream.range(0, 1000).forEach(i -> {
rateLimiter.acquire();
doSomeLimitedOperation();
});
long elapsedTimeSeconds = ZonedDateTime.now().getSecond() - startTime;
// then
assertThat(elapsedTimeSeconds >= 10);
}
ここでacquire()メソッドをどのように使用しているかに注意してください。これはブロッキングメソッドであり、使用するときは注意が必要です。 acquire()メソッドが呼び出されると、許可が使用可能になるまで実行中のスレッドをブロックします。
Calling the acquire() without an argument is the same as calling it with a one as an argument –1つの許可を取得しようとします。
5. タイムアウト付きの許可の取得
RateLimiter APIには、accepts a timeout and TimeUnit as arguments.という非常に便利なacquire()メソッドもあります。
使用可能な許可がないときにこのメソッドを呼び出すと、指定された時間待機してからタイムアウトになります–timeout.内に十分な使用可能な許可がない場合
指定されたタイムアウト内に使用可能な許可がない場合、false.を返します。acquire()が成功した場合、returnsはtrueです。
@Test
public void givenLimitedResource_whenTryAcquire_shouldNotBlockIndefinitely() {
// given
RateLimiter rateLimiter = RateLimiter.create(1);
// when
rateLimiter.acquire();
boolean result = rateLimiter.tryAcquire(2, 10, TimeUnit.MILLISECONDS);
// then
assertThat(result).isFalse();
}
1つの許可でRateLimiterを作成したため、2つの許可を取得しようとすると、常にtryAcquire()がfalse.を返します。
6. 結論
このクイックチュートリアルでは、GuavaライブラリのRateLimiterコンストラクトを確認しました。
RateLimtiterを使用して、1秒あたりの許可の数を制限する方法を学びました。 ブロッキングAPIの使用方法を確認し、明示的なタイムアウトを使用して許可を取得しました。
いつものように、これらすべての例とコードスニペットの実装はGitHub projectにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。