J'ai besoin d'un composant / classe qui limite l'exécution d'une méthode à un maximum d'appels M en N secondes (ou ms ou nanos, peu importe).
En d'autres termes, je dois m'assurer que ma méthode n'est pas exécutée plus de M fois dans une fenêtre glissante de N secondes.
Si vous ne connaissez pas la classe existante, n'hésitez pas à publier vos solutions / idées sur la manière dont vous implémenteriez cela.
java
throttling
vtrubnikov
la source
la source
Réponses:
J'utiliserais un tampon en anneau d'horodatages avec une taille fixe de M. Chaque fois que la méthode est appelée, vous vérifiez l'entrée la plus ancienne, et si c'est moins de N secondes dans le passé, vous exécutez et ajoutez une autre entrée, sinon vous dormez pour le décalage horaire.
la source
Ce qui a fonctionné pour moi, c'est Google Guava RateLimiter .
la source
tryAquire()
Concrètement, vous devriez pouvoir l'implémenter avec un
DelayQueue
. Initialisez la file d'attente avec desM
Delayed
instances dont le délai initialement défini sur zéro. À mesure que les demandes adressées à la méthode arrivent,take
un jeton entraîne le blocage de la méthode jusqu'à ce que l'exigence de limitation soit satisfaite. Lorsqu'un jeton a été pris,add
un nouveau jeton dans la file d'attente avec un délai deN
.la source
offer
et de croissance possible du tableau), et c'est un peu lourd pour moi. Je suppose que pour d'autres, cela pourrait être parfaitement correct.Renseignez-vous sur l' algorithme du compartiment Token . Fondamentalement, vous avez un seau avec des jetons. Chaque fois que vous exécutez la méthode, vous prenez un jeton. S'il n'y a plus de jetons, vous bloquez jusqu'à ce que vous en obteniez un. Pendant ce temps, il y a un acteur externe qui reconstitue les jetons à un intervalle fixe.
Je ne connais pas de bibliothèque pour faire cela (ou quoi que ce soit de similaire). Vous pouvez écrire cette logique dans votre code ou utiliser AspectJ pour ajouter le comportement.
la source
Si vous avez besoin d'un limiteur de vitesse à fenêtre glissante basé sur Java qui fonctionnera sur un système distribué, vous pouvez jeter un œil au projet https://github.com/mokies/ratelimitj .
Une configuration basée sur Redis, pour limiter les demandes par IP à 50 par minute, ressemblerait à ceci:
Voir https://github.com/mokies/ratelimitj/tree/master/ratelimitj-redis pour plus de détails sur la configuration de Redis.
la source
Cela dépend de l'application.
Imaginez le cas dans lequel plusieurs threads veulent qu'un jeton effectue une action à débit global limité sans rafale autorisée (c'est-à-dire que vous voulez limiter 10 actions toutes les 10 secondes mais vous ne voulez pas que 10 actions se produisent dans la première seconde, puis restent 9 secondes arrêtées).
Le DelayedQueue a un inconvénient: l'ordre dans lequel les threads demandent des jetons peut ne pas être l'ordre dans lequel ils obtiennent leur demande exécutée. Si plusieurs threads sont bloqués en attente d'un jeton, il n'est pas clair lequel prendra le prochain jeton disponible. Vous pourriez même avoir des fils en attente pour toujours, à mon avis.
Une solution consiste à avoir un intervalle de temps minimum entre deux actions consécutives et à effectuer les actions dans le même ordre que celui demandé.
Voici une implémentation:
la source
minTime
dire ici? Qu'est ce que ça fait? pouvez-vous expliquer à ce sujet?minTime
est le laps de temps minimum qui doit s'écouler après la consommation d'un jeton avant que le jeton suivant puisse être consommé.Bien que ce ne soit pas ce que vous avez demandé,
ThreadPoolExecutor
qui est conçu pour limiter à M requêtes simultanées au lieu de M requêtes en N secondes, peut également être utile.la source
J'ai implémenté un algorithme de limitation simple. Essayez ce lien, http://krishnaprasadas.blogspot.in/2012/05/throttling-algorithm.html
Un bref sur l'algorithme,
Cet algorithme utilise la capacité de Java Delayed Queue . Créez un objet retardé avec le retard attendu (ici 1000 / M pour TimeUnit milliseconde ). Mettez le même objet dans la file d'attente retardée qui nous fournira la fenêtre en mouvement. Ensuite, avant chaque appel de méthode, prenez l'objet de la file d'attente, take est un appel bloquant qui ne reviendra qu'après le délai spécifié, et après l'appel de méthode, n'oubliez pas de mettre l'objet dans la file d'attente avec le temps mis à jour (ici les millisecondes actuelles) .
Ici, nous pouvons également avoir plusieurs objets retardés avec un retard différent. Cette approche fournira également un débit élevé.
la source
Mon implémentation ci-dessous peut gérer une précision de temps de requête arbitraire, elle a une complexité de temps O (1) pour chaque requête, ne nécessite aucun tampon supplémentaire, par exemple la complexité de l'espace O (1), en outre, elle ne nécessite pas de thread d'arrière-plan pour libérer le jeton, à la place les jetons sont libérés en fonction du temps écoulé depuis la dernière demande.
la source
Essayez d'utiliser cette approche simple:
}
la source
Apache Camel prend également en charge le mécanisme Throttler comme suit:
la source
Ceci est une mise à jour du code LeakyBucket ci-dessus. Cela fonctionne pour plus de 1000 requêtes par seconde.
et le unittest pour ci-dessus:
la source
minTimeNano
signifie ici? peux-tu expliquer?Voici une petite version avancée du limiteur de débit simple
Et tests unitaires
la source
Ma solution: Une méthode util simple, vous pouvez la modifier pour créer une classe wrapper.
Prenez de JAVA Thread Debounce et Throttle
la source