Kurzanleitung zum Guava RateLimiter

1. Übersicht

In diesem Artikel betrachten wir die RateLimiter- Klasse aus der Guava- Bibliothek.

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

2. Maven-Abhängigkeit

Wir werden Guavas Bibliothek benutzen:

 com.google.guava guava 29.0-jre 

Die neueste Version finden Sie hier.

3. Erstellen und Verwenden von RateLimiter

Angenommen , wir möchten die Ausführungsrate von doSomeLimitedOperation () auf 2 Mal pro Sekunde begrenzen .

Wir können eine RateLimiter- Instanz mit der Factory-Methode create () erstellen :

RateLimiter rateLimiter = RateLimiter.create(2);

Um eine Ausführungserlaubnis vom RateLimiter zu erhalten, müssen wir als nächstes die Methode purchase () aufrufen :

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 doSomeLimitedOperation () sofort abgeschlossen wird.

In diesem Fall sollten beide Aufrufe der Methode purchase () 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 einem Acquise () -Aufruf erwerben :

@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 wir beispielsweise 100 Bytes pro Sekunde senden 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 und alle 100 Genehmigungen in einer Operation abrufen.

4. Erteilung von Genehmigungen auf blockierende Weise

Betrachten wir nun ein etwas komplexeres Beispiel.

Wir erstellen einen RateLimiter mit 100 Genehmigungen. Dann führen wir eine Aktion aus, für die 1000 Genehmigungen erforderlich sind. Gemäß der Spezifikation des RateLimiter 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 die Methode purchase () verwenden - dies ist eine Blockierungsmethode und wir sollten vorsichtig sein, wenn wir sie verwenden. Wenn die Methode purchase () aufgerufen wird, blockiert sie den ausführenden Thread, bis eine Genehmigung verfügbar ist.

Das Aufrufen von purchase () ohne Argument ist dasselbe wie das Aufrufen mit einer Eins als Argument - es wird versucht, eine Erlaubnis zu erhalten.

5. Erwerb von Genehmigungen mit einer Zeitüberschreitung

Die RateLimiter- API verfügt auch über eine sehr nützliche Methode begehren () , die ein Timeout und TimeUnit als Argumente akzeptiert .

Wenn Sie diese Methode aufrufen, wenn keine Genehmigungen verfügbar sind, wartet sie auf die angegebene Zeit und führt dann zu einer Zeitüberschreitung - wenn innerhalb des Zeitlimits nicht genügend Genehmigungen verfügbar sind .

Wenn innerhalb des angegebenen Zeitlimits keine Genehmigungen verfügbar sind, wird false zurückgegeben. Wenn ein acquire () erfolgreich ist , es gibt wahr:

@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 haben einen RateLimiter mit einer Berechtigung erstellt. Wenn Sie also versuchen, zwei Berechtigungen zu erhalten, wird tryAcquire () immer mit false zurückgegeben.

6. Fazit

In diesem kurzen Tutorial haben wir uns das RateLimiter- Konstrukt aus der Guava- Bibliothek angesehen.

Wir haben gelernt, wie Sie mit dem RateLimtiter die Anzahl der Genehmigungen pro Sekunde begrenzen. Wir haben gesehen, wie die Blockierungs-API verwendet wird, und wir haben auch eine explizite Zeitüberschreitung verwendet, um die Genehmigung zu erhalten.

Wie immer befindet sich die Implementierung all dieser Beispiele und Codefragmente im GitHub-Projekt - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.