Ich benötige eine Komponente / Klasse, die die Ausführung einer Methode auf maximal M Aufrufe in N Sekunden drosselt (oder ms oder nanos spielt keine Rolle).
Mit anderen Worten, ich muss sicherstellen, dass meine Methode nicht mehr als M Mal in einem Schiebefenster von N Sekunden ausgeführt wird.
Wenn Sie die vorhandene Klasse nicht kennen, können Sie Ihre Lösungen / Ideen veröffentlichen, wie Sie dies implementieren würden.
java
throttling
vtrubnikov
quelle
quelle
Antworten:
Ich würde einen Ringpuffer mit Zeitstempeln mit einer festen Größe von M verwenden. Bei jedem Aufruf der Methode überprüfen Sie den ältesten Eintrag. Wenn er in der Vergangenheit weniger als N Sekunden beträgt, führen Sie einen weiteren Eintrag aus und fügen ihn hinzu, andernfalls schlafen Sie für den Zeitunterschied.
quelle
Was für mich sofort funktioniert hat, war Google Guava RateLimiter .
quelle
tryAquire()
Konkret sollten Sie dies mit a umsetzen können
DelayQueue
. Initialisieren Sie die Warteschlange mitM
Delayed
Instanzen, deren Verzögerung anfänglich auf Null gesetzt ist. Wenn Anforderungen an die Methode eingehen,take
ein Token, das bewirkt, dass die Methode blockiert wird, bis die Drosselungsanforderung erfüllt ist. Wenn ein Token genommen wurde, wirdadd
ein neues Token mit einer Verzögerung von in die Warteschlange gestelltN
.quelle
offer
und mögliches Array-Wachstum bedeutet), und es ist alles ziemlich schwer für mich. Ich denke für andere könnte dies vollkommen in Ordnung sein.Informieren Sie sich über den Token-Bucket- Algorithmus. Grundsätzlich haben Sie einen Eimer mit Token darin. Jedes Mal, wenn Sie die Methode ausführen, nehmen Sie ein Token. Wenn keine Token mehr vorhanden sind, blocken Sie, bis Sie einen erhalten. In der Zwischenzeit gibt es einen externen Akteur, der die Token in einem festgelegten Intervall auffüllt.
Mir ist keine Bibliothek dafür bekannt (oder ähnliches). Sie können diese Logik in Ihren Code schreiben oder AspectJ verwenden, um das Verhalten hinzuzufügen.
quelle
Wenn Sie einen Java-basierten Schieberegler für die Schiebefensterrate benötigen, der auf einem verteilten System funktioniert, sollten Sie sich das Projekt https://github.com/mokies/ratelimitj ansehen .
Eine von Redis unterstützte Konfiguration zum Begrenzen von IP-Anforderungen auf 50 pro Minute würde folgendermaßen aussehen:
Weitere Informationen zur Redis-Konfiguration finden Sie unter https://github.com/mokies/ratelimitj/tree/master/ratelimitj-redis .
quelle
Dies hängt von der Anwendung ab.
Stellen Sie sich den Fall , in dem mehrere Threads ein Token wollen einige tun global geschwindigkeits begrenzte Aktion mit keiner Burst erlaubt (dh Sie 10 Aktionen pro 10 Sekunden begrenzen wollen , aber Sie wollen nicht mehr als 10 Aktionen in der ersten Sekunde passieren und dann bleiben 9 Sekunden gestoppt).
Die DelayedQueue hat einen Nachteil: Die Reihenfolge, in der Threads Token anfordern, entspricht möglicherweise nicht der Reihenfolge, in der sie ihre Anforderung erfüllen. Wenn mehrere Threads blockiert sind und auf ein Token warten, ist nicht klar, welcher das nächste verfügbare Token nimmt. Aus meiner Sicht könnten sogar Threads für immer warten.
Eine Lösung besteht darin, ein Mindestintervall zwischen zwei aufeinander folgenden Aktionen einzuhalten und die Aktionen in derselben Reihenfolge auszuführen, in der sie angefordert wurden.
Hier ist eine Implementierung:
quelle
minTime
bedeutet hier Was tut es? Kannst du das erklären?minTime
ist die Mindestzeit, die nach dem Verbrauch eines Tokens vergehen muss, bevor der nächste Token verbraucht werden kann.Obwohl es nicht das ist, was Sie gefragt haben
ThreadPoolExecutor
, das darauf ausgelegt ist, M gleichzeitige Anforderungen anstelle von M Anforderungen in N Sekunden zu begrenzen, könnte es auch nützlich sein.quelle
Ich habe einen einfachen Drosselungsalgorithmus implementiert. Versuchen Sie diesen Link, http://krishnaprasadas.blogspot.in/2012/05/throttling-algorithm.html
Ein kurzer Überblick über den Algorithmus,
Dieser Algorithmus nutzt die Fähigkeit der Java Delayed Queue . Erstellen Sie ein verzögertes Objekt mit der erwarteten Verzögerung (hier 1000 / M für Millisekunden TimeUnit ). Stellen Sie dasselbe Objekt in die verzögerte Warteschlange, die intern das bewegliche Fenster für uns bereitstellt. Dann vor jedem Methodenaufruf nehmen das Objekt die Warteschlange bilden, nehmen ist ein blockierender Aufruf , die erst nach der angegebenen Verzögerung zurück, und nach dem Methodenaufruf nicht vergessen , mit aktualisierten Zeit das Objekt in die Warteschlange einzureihen (hier aktuelle Millisekunden) .
Hier können wir auch mehrere verzögerte Objekte mit unterschiedlicher Verzögerung haben. Dieser Ansatz bietet auch einen hohen Durchsatz.
quelle
Meine Implementierung unten kann eine beliebige Genauigkeit der Anforderungszeit verarbeiten. Sie hat eine O (1) -Zeitkomplexität für jede Anforderung, benötigt keinen zusätzlichen Puffer, z. B. O (1) -Komplexität, und erfordert keinen Hintergrundthread, um stattdessen Token freizugeben Token werden gemäß der seit der letzten Anforderung verstrichenen Zeit freigegeben.
quelle
Versuchen Sie diesen einfachen Ansatz zu verwenden:
}}
quelle
Apache Camel unterstützt außerdem den folgenden Throttler- Mechanismus:
quelle
Dies ist ein Update des obigen LeakyBucket-Codes. Dies funktioniert für mehr als 1000 Anfragen pro Sekunde.
und das Unittest für oben:
quelle
minTimeNano
bedeutet hier? können Sie erklären?Hier ist eine etwas erweiterte Version des einfachen Ratenbegrenzers
Und Unit-Tests
quelle
Meine Lösung: Eine einfache util-Methode, die Sie ändern können, um eine Wrapper-Klasse zu erstellen.
Nehmen Sie von JAVA Thread Debounce und Throttle
quelle