Kurzanleitung zum Guava RateLimiter

Kurzanleitung zum Guava RateLimiter

1. Überblick

In diesem Artikel betrachten wir dieRateLimiter-Klasse aus derGuava-Bibliothek.

Die KlasseRateLimiter ist ein Konstrukt, mit dem wir die Geschwindigkeit regulieren können, mit der eine Verarbeitung stattfindet. Wenn wir einRateLimiter mit N Genehmigungen erstellen, bedeutet dies, dass der Prozess höchstens N Genehmigungen pro Sekunde ausstellen kann.

2. Maven-Abhängigkeit

Wir werden die Bibliothek von Guava verwenden:


    com.google.guava
    guava
    22.0

Die neueste Version finden Sie unterhere.

3. Erstellen und Verwenden vonRateLimiter

Nehmen wir an, wir wollenlimit the rate of execution of the doSomeLimitedOperation() to 2 times per second.

Wir können eineRateLimiter-Instanz mit der Factory-Methodecreate()erstellen:

RateLimiter rateLimiter = RateLimiter.create(2);

Als nächstes müssen wir die Methodeacquire() aufrufen, um eine Ausführungserlaubnis vonRateLimiter,zu erhalten:

rateLimiter.acquire(1);

Um zu überprüfen, ob dies funktioniert, führen wir zwei nachfolgende Aufrufe der gedrosselten Methode durch:

long startTime = ZonedDateTime.now().getSecond();
rateLimiter.acquire(1);
doSomeLimitedOperation();
rateLimiter.acquire(1);
doSomeLimitedOperation();
long elapsedTimeSeconds = ZonedDateTime.now().getSecond() - startTime;

Nehmen wir zur Vereinfachung unserer Tests an, dass die Methode vondoSomeLimitedOperation()ofort abgeschlossen ist.

In diesem Fall sollten beide Aufrufe deracquire()-Methode nicht blockieren und die verstrichene Zeit sollte weniger als oder weniger als eine Sekunde betragen - da beide Genehmigungen sofort erworben werden können:

assertThat(elapsedTimeSeconds <= 1);

Zusätzlich können wir alle Genehmigungen in einemacquire()Anruf erhalten:

@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);
}

Dies kann nützlich sein, wenn beispielsweise 100 Bytes pro Sekunde gesendet werden müssen. Wir können einhundert Mal ein Byte senden, um jeweils eine Genehmigung zu erhalten. Andererseits können wir alle 100 Bytes gleichzeitig senden, um alle 100 Genehmigungen in einer Operation zu erhalten.

4. Blockieren von Genehmigungen

Betrachten wir nun ein etwas komplexeres Beispiel.

Wir erstellen einRateLimiter mit 100 Genehmigungen. Dann führen wir eine Aktion aus, für die 1000 Genehmigungen erforderlich sind. Gemäß der Spezifikation vonRateLimiter, dauert eine solche Aktion mindestens 10 Sekunden, da wir nur 100 Aktionseinheiten pro Sekunde ausführen können:

@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);
}

Beachten Sie, wie wir hier dieacquire()-Methode verwenden - dies ist eine Blockierungsmethode und wir sollten vorsichtig sein, wenn wir sie verwenden. Wenn dieacquire()-Methode aufgerufen wird, blockiert sie den ausführenden Thread, bis eine Genehmigung verfügbar ist.

Calling the acquire() without an argument is the same as calling it with a one as an argument - Es wird versucht, eine Genehmigung zu erhalten.

5. Genehmigungen mit Timeout einholen

DieRateLimiter API hat auch eine sehr nützlicheacquire() Methode, dieaccepts a timeout and TimeUnit as arguments.

Wenn Sie diese Methode aufrufen, wenn keine Genehmigungen verfügbar sind, wartet sie auf die angegebene Zeit und läuft dann ab - wenn innerhalb dertimeout. nicht genügend Genehmigungen verfügbar sind

Wenn innerhalb des angegebenen Zeitlimits keine Genehmigungen verfügbar sind, wirdfalse. zurückgegeben. Wenn einacquire() erfolgreich ist, istreturnswahr:

@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();
}

Wir habenRateLimiter mit einer Erlaubnis erstellt. Wenn Sie also versuchen, zwei Genehmigungen zu erhalten, werdentryAcquire() immerfalse. zurückgeben

6. Fazit

In diesem kurzen Tutorial haben wir uns das KonstruktRateLimiteraus der BibliothekGuavaangesehen.

Wir haben gelernt, wie man dieRateLimtiter verwendet, um die Anzahl der Genehmigungen pro Sekunde zu begrenzen. Wir haben gesehen, wie die Blockierungs-API verwendet wird, und wir haben auch ein explizites Timeout verwendet, um die Genehmigung zu erhalten.

Wie immer finden Sie die Implementierung all dieser Beispiele und Codefragmente inGitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein.