Guava RateLimiterのクイックガイド

Guava RateLimiterのクイックガイド

1. 概要

この記事では、GuavaライブラリのRateLimiterクラスについて説明します。

RateLimiterクラスは、何らかの処理が発生する速度を調整できるようにする構造です。 N個の許可でRateLimiterを作成する場合、プロセスは1秒あたり最大N個の許可を発行できることを意味します。

2. メーベン依存

Guavaのライブラリを使用します。


    com.google.guava
    guava
    22.0

最新バージョンはhereで見つけることができます。

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プロジェクトであるため、そのままインポートして実行するのは簡単です。