Guida rapida a Guava RateLimiter

1. Panoramica

In questo articolo, esamineremo la classe RateLimiter dalla libreria Guava .

La classe RateLimiter è un costrutto che ci consente di regolare la velocità con cui avvengono alcune elaborazioni. Se creiamo un RateLimiter con N permessi, significa che il processo può emettere al massimo N permessi al secondo.

2. Dipendenza da Maven

Useremo la libreria di Guava:

 com.google.guava guava 29.0-jre 

L'ultima versione può essere trovata qui.

3. Creazione e utilizzo di RateLimiter

Supponiamo di voler limitare la velocità di esecuzione di doSomeLimitedOperation () a 2 volte al secondo.

Possiamo creare un'istanza RateLimiter usando il suo metodo factory create () :

RateLimiter rateLimiter = RateLimiter.create(2);

Successivamente, per ottenere un permesso di esecuzione da RateLimiter, dobbiamo chiamare il metodo acquis () :

rateLimiter.acquire(1);

Per verificare che funzioni, effettueremo 2 chiamate successive al metodo throttled:

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

Per semplificare i nostri test, supponiamo che il metodo doSomeLimitedOperation () venga completato immediatamente.

In tal caso, entrambe le invocazioni del metodo acquis () non dovrebbero bloccarsi e il tempo trascorso dovrebbe essere inferiore o inferiore a un secondo, poiché entrambi i permessi possono essere acquisiti immediatamente:

assertThat(elapsedTimeSeconds <= 1);

Inoltre, possiamo acquisire tutti i permessi in una chiamata ad acquisire () :

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

Questo può essere utile se, ad esempio, dobbiamo inviare 100 byte al secondo. Possiamo inviare cento volte un byte acquisendo un permesso alla volta. D'altra parte, possiamo inviare tutti i 100 byte contemporaneamente acquisendo tutti i 100 permessi in un'unica operazione.

4. Acquisizione di permessi in modo bloccante

Consideriamo ora un esempio leggermente più complesso.

Creeremo un RateLimiter con 100 permessi. Quindi eseguiremo un'azione che deve acquisire 1000 permessi. Secondo le specifiche del RateLimiter, tale azione richiederà almeno 10 secondi per essere completata perché siamo in grado di eseguire solo 100 unità di azione al secondo:

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

Nota, come stiamo usando il metodo acquis () qui: questo è un metodo di blocco e dovremmo essere cauti quando lo usiamo. Quando il metodo acquis () viene chiamato, blocca il thread in esecuzione fino a quando non è disponibile un permesso.

Chiamare l' acquisizione () senza un argomento equivale a chiamarlo con uno come argomento : proverà ad acquisire un permesso.

5. Acquisizione di permessi con un timeout

L' API RateLimiter ha anche un metodo acquisire () molto utile che accetta un timeout e TimeUnit come argomenti.

Chiamare questo metodo quando non ci sono permessi disponibili lo farà attendere il tempo specificato e quindi il timeout, se non ci sono abbastanza permessi disponibili entro il timeout.

Quando non ci sono permessi disponibili entro il timeout specificato, restituisce false. Se un'acquisizione () ha esito positivo, restituisce 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(); }

Abbiamo creato un RateLimiter con un permesso, quindi il tentativo di acquisire due permessi farà sempre sì che tryAcquire () restituisca false.

6. Conclusione

In questo rapido tutorial, abbiamo dato un'occhiata al costrutto RateLimiter dalla libreria Guava .

Abbiamo imparato come utilizzare RateLimtiter per limitare il numero di permessi al secondo. Abbiamo visto come utilizzare la sua API di blocco e abbiamo anche utilizzato un timeout esplicito per acquisire il permesso.

Come sempre, l'implementazione di tutti questi esempi e frammenti di codice può essere trovata nel progetto GitHub: questo è un progetto Maven, quindi dovrebbe essere facile da importare ed eseguire così com'è.