Necesito un componente / clase que acelere la ejecución de algún método al máximo de llamadas M en N segundos (o ms o nanos, no importa).
En otras palabras, necesito asegurarme de que mi método se ejecute no más de M veces en una ventana deslizante de N segundos.
Si no conoce la clase existente, no dude en publicar sus soluciones / ideas sobre cómo implementaría esto.
java
throttling
vtrubnikov
fuente
fuente
Respuestas:
Usaría un búfer en anillo de marcas de tiempo con un tamaño fijo de M. Cada vez que se llama al método, verifica la entrada más antigua, y si es menos de N segundos en el pasado, ejecuta y agrega otra entrada, de lo contrario duerme Por la diferencia horaria.
fuente
Lo que funcionó fuera de la caja para mí fue Google Guava RateLimiter .
fuente
tryAquire()
En términos concretos, debería poder implementar esto con a
DelayQueue
. Inicialice la cola conM
Delayed
instancias con su retraso inicialmente establecido en cero. A medida que entran solicitudes al método,take
un token, que hace que el método se bloquee hasta que se cumpla el requisito de limitación. Cuando se ha tomadoadd
una ficha , una nueva ficha a la cola con un retraso deN
.fuente
offer
y un posible crecimiento de la matriz), y todo es un poco pesado para mí. Supongo que para otros esto podría estar perfectamente bien.Lea sobre el algoritmo de depósito de token . Básicamente, tienes un cubo con tokens. Cada vez que ejecutas el método, tomas un token. Si no hay más fichas, bloqueas hasta que obtengas una. Mientras tanto, hay algún actor externo que repone las fichas en un intervalo fijo.
No conozco una biblioteca para hacer esto (o algo similar). Puede escribir esta lógica en su código o usar AspectJ para agregar el comportamiento.
fuente
Si necesita un limitador de velocidad de ventana deslizante basado en Java que opere en un sistema distribuido, puede echar un vistazo al proyecto https://github.com/mokies/ratelimitj .
Una configuración respaldada por Redis, para limitar las solicitudes por IP a 50 por minuto, se vería así:
Consulte https://github.com/mokies/ratelimitj/tree/master/ratelimitj-redis para obtener más detalles sobre la configuración de Redis.
fuente
Esto depende de la aplicación.
Imagínese el caso en el que varios subprocesos quieren un token para hacer un poco de acción a nivel mundial de la velocidad limitada a ninguna ráfaga permitido (es decir, que desea limitar a 10 acciones por cada 10 segundos, pero no desea que 10 acciones que sucedan en el primer segundo y luego permanecer 9 segundos detenidos).
El DelayedQueue tiene una desventaja: el orden en el que los subprocesos solicitan tokens podría no ser el orden en el que reciben su solicitud. Si se bloquean varios subprocesos esperando un token, no está claro cuál tomará el siguiente token disponible. Incluso podría tener hilos esperando para siempre, en mi punto de vista.
Una solución es tener un intervalo de tiempo mínimo entre dos acciones consecutivas y tomar acciones en el mismo orden en que se solicitaron.
Aquí hay una implementación:
fuente
minTime
significa aquí? ¿Qué hace? ¿Puedes explicar sobre eso?minTime
es la cantidad mínima de tiempo que debe pasar después de que se consuma un token antes de que se pueda consumir el siguiente token.Aunque no es lo que pidió,
ThreadPoolExecutor
que está diseñado para limitar M solicitudes simultáneas en lugar de M solicitudes en N segundos, también podría ser útil.fuente
He implementado un algoritmo de aceleración simple. Pruebe este enlace, http://krishnaprasadas.blogspot.in/2012/05/throttling-algorithm.html
Un breve sobre el algoritmo,
Este algoritmo utiliza la capacidad de Java Delayed Queue . Cree un objeto retrasado con el retraso esperado (aquí 1000 / M para milisegundos TimeUnit ). Ponga el mismo objeto en la cola retrasada que nos proporcionará la ventana móvil. Luego, antes de que cada llamada al método tome el objeto de la cola, la toma es una llamada de bloqueo que regresará solo después del retraso especificado, y después de la llamada al método, no olvide poner el objeto en la cola con el tiempo actualizado (aquí milisegundos actuales) .
Aquí también podemos tener múltiples objetos retrasados con diferentes retrasos. Este enfoque también proporcionará un alto rendimiento.
fuente
Mi implementación a continuación puede manejar una precisión de tiempo de solicitud arbitraria, tiene una complejidad de tiempo O (1) para cada solicitud, no requiere ningún búfer adicional, por ejemplo, complejidad de espacio O (1), además no requiere subproceso de fondo para liberar el token, en su lugar los tokens se liberan según el tiempo transcurrido desde la última solicitud.
fuente
Intente usar este enfoque simple:
}
fuente
Apache Camel también es compatible con el mecanismo Throttler de la siguiente manera:
fuente
Esta es una actualización del código LeakyBucket anterior. Esto funciona para más de 1000 solicitudes por segundo.
y la unidad de prueba de arriba:
fuente
minTimeNano
significa aquí? ¿puedes explicar?Aquí hay una pequeña versión avanzada del limitador de velocidad simple
Y pruebas unitarias
fuente
Mi solución: un método util simple, puede modificarlo para crear una clase de contenedor.
Tome de JAVA Thread Debounce y Throttle
fuente