Guía rápida de Guayaba RateLimiter

1. Información general

En este artículo, veremos la clase RateLimiter de la biblioteca de Guava .

La clase RateLimiter es una construcción que nos permite regular la velocidad a la que ocurre algún procesamiento. Si creamos un RateLimiter con N permisos, significa que el proceso puede emitir como máximo N permisos por segundo.

2. Dependencia de Maven

Usaremos la biblioteca de Guava:

 com.google.guava guava 29.0-jre 

La última versión se puede encontrar aquí.

3. Creación y uso de RateLimiter

Digamos que queremos limitar la velocidad de ejecución de doSomeLimitedOperation () a 2 veces por segundo.

Podemos crear una instancia de RateLimiter usando su método de fábrica create () :

RateLimiter rateLimiter = RateLimiter.create(2);

A continuación, para obtener un permiso de ejecución del RateLimiter, debemos llamar al método adquirido () :

rateLimiter.acquire(1);

Para comprobar que funciona, haremos 2 llamadas posteriores al método acelerado:

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

Para simplificar nuestras pruebas, supongamos que el método doSomeLimitedOperation () se completa de inmediato.

En tal caso, ambas invocaciones del método adquirido () no deben bloquearse y el tiempo transcurrido debe ser menor o menor de un segundo, porque ambos permisos se pueden adquirir inmediatamente:

assertThat(elapsedTimeSeconds <= 1);

Además, podemos adquirir todos los permisos en una llamada de adquisición () :

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

Esto puede resultar útil si, por ejemplo, necesitamos enviar 100 bytes por segundo. Podemos enviar cien veces un byte adquiriendo un permiso a la vez. Por otro lado, podemos enviar los 100 bytes a la vez adquiriendo los 100 permisos en una sola operación.

4. Adquisición de permisos de forma bloqueada

Ahora, consideremos un ejemplo un poco más complejo.

Crearemos un RateLimiter con 100 permisos. Luego ejecutaremos una acción que necesita adquirir 1000 permisos. De acuerdo con la especificación de RateLimiter, dicha acción necesitará al menos 10 segundos para completarse porque solo podemos ejecutar 100 unidades de acción por segundo:

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

Tenga en cuenta cómo estamos usando el método adquirir () aquí: este es un método de bloqueo y debemos tener cuidado al usarlo. Cuando se llama al método adquirido () , bloquea el hilo en ejecución hasta que haya un permiso disponible.

Llamar a adquirir () sin un argumento es lo mismo que llamarlo con uno como argumento : intentará adquirir un permiso.

5. Adquirir permisos con un tiempo de espera

La API RateLimiter también tiene un método de adquisición () muy útil que acepta un tiempo de espera y TimeUnit como argumentos.

Llamar a este método cuando no hay permisos disponibles hará que espere el tiempo especificado y luego se agote, si no hay suficientes permisos disponibles dentro del tiempo de espera.

Cuando no hay permisos disponibles dentro del tiempo de espera dado, devuelve falso. Si una adquisición () tiene éxito, devuelve verdadero:

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

Creamos un RateLimiter con un permiso, por lo que intentar adquirir dos permisos siempre hará que tryAcquire () devuelva falso.

6. Conclusión

En este tutorial rápido, echamos un vistazo a la construcción RateLimiter de la biblioteca Guava .

Aprendimos a usar RateLimtiter para limitar el número de permisos por segundo. Vimos cómo usar su API de bloqueo y también usamos un tiempo de espera explícito para adquirir el permiso.

Como siempre, la implementación de todos estos ejemplos y fragmentos de código se puede encontrar en el proyecto GitHub; este es un proyecto de Maven, por lo que debería ser fácil de importar y ejecutar tal como está.