Potrzebuję komponentu / klasy, który ogranicza wykonanie jakiejś metody do maksymalnej liczby wywołań M w ciągu N sekund (lub ms lub nanos, nie ma znaczenia).
Innymi słowy, muszę się upewnić, że moja metoda jest wykonywana nie więcej niż M razy w przesuwanym oknie trwającym N sekund.
Jeśli nie znasz istniejącej klasy, możesz zamieścić swoje rozwiązania / pomysły, jak byś to wdrożył.
java
throttling
vtrubnikov
źródło
źródło
Odpowiedzi:
Użyłbym bufora pierścieniowego ze znacznikami czasu o stałym rozmiarze M. Za każdym razem, gdy wywoływana jest metoda, sprawdzasz najstarszy wpis, a jeśli jest mniej niż N sekund w przeszłości, wykonujesz i dodajesz kolejny wpis, w przeciwnym razie śpisz za różnicę czasu.
źródło
To, co dla mnie zadziałało, to Google Guava RateLimiter .
źródło
tryAquire()
Mówiąc konkretnie, powinieneś być w stanie to zaimplementować za pomocą
DelayQueue
. Zainicjuj kolejkęM
Delayed
instancjami z opóźnieniem początkowo ustawionym na zero. Gdy przychodzą żądania do metody,take
token, który powoduje blokowanie metody do momentu spełnienia wymagania ograniczania przepustowości. Kiedy token zostanie zabrany,add
nowy żeton do kolejki z opóźnieniemN
.źródło
offer
i możliwy wzrost tablicy) i jest dla mnie trochę ciężki. Myślę, że dla innych może to być całkowicie w porządku.Przeczytaj informacje o zasobniku tokenów algorytmie tokenów. Zasadniczo masz wiadro z tokenami. Za każdym razem, gdy wykonujesz metodę, bierzesz token. Jeśli nie ma więcej tokenów, blokujesz, dopóki go nie zdobędziesz. W międzyczasie istnieje zewnętrzny aktor, który uzupełnia tokeny w ustalonych odstępach czasu.
Nie znam biblioteki, która mogłaby to zrobić (lub coś podobnego). Możesz zapisać tę logikę w swoim kodzie lub użyć AspectJ, aby dodać zachowanie.
źródło
Jeśli potrzebujesz ogranicznika szybkości przesuwanego okna opartego na Javie, który będzie działał w systemie rozproszonym, możesz rzucić okiem na projekt https://github.com/mokies/ratelimitj .
Konfiguracja wspierana przez Redis w celu ograniczenia żądań przez IP do 50 na minutę wyglądałaby następująco:
Więcej informacji na temat konfiguracji Redis można znaleźć pod adresem https://github.com/mokies/ratelimitj/tree/master/ratelimitj-redis .
źródło
To zależy od aplikacji.
Wyobraźmy sobie sytuację, w której wiele wątków chcesz token zrobić jakąś akcję szybkość ograniczona globalnie z żadnym wybuchu dozwolonym (tj chcesz ograniczyć 10 działań na 10 sekund, ale nie chcesz 10 Działania nastąpić w pierwszej sekundy, a następnie pozostanie 9 sekund zatrzymane).
Kolejka DelayedQueue ma wadę: kolejność, w której wątki żądają tokenów, może nie być kolejnością, w której ich żądanie zostało spełnione. Jeśli wiele wątków jest zablokowanych w oczekiwaniu na token, nie jest jasne, który z nich weźmie następny dostępny token. Moim zdaniem możesz nawet mieć wątki czekające wiecznie.
Jednym z rozwiązań jest zachowanie minimalnego odstępu czasu między dwoma kolejnymi akcjami i wykonywanie działań w tej samej kolejności, w jakiej zostały one zażądane.
Oto realizacja:
źródło
minTime
znaczy? Co to robi? czy możesz to wyjaśnić?minTime
to minimalny czas, jaki musi upłynąć po zużyciu tokenu, zanim będzie można wykorzystać następny token.Chociaż nie jest to to, o co prosiłeś,
ThreadPoolExecutor
co ma na celu ograniczenie do M jednoczesnych żądań zamiast M żądań w ciągu N sekund, może być również przydatne.źródło
Zaimplementowałem prosty algorytm dławienia. Wypróbuj ten link, http://krishnaprasadas.blogspot.in/2012/05/throttling-algorithm.html
Krótka informacja o algorytmie,
Ten algorytm wykorzystuje możliwości opóźnionej kolejki Java . Utwórz opóźniony obiekt z oczekiwanym opóźnieniem (tutaj 1000 / M dla milisekund TimeUnit ). Umieść ten sam obiekt w opóźnionej kolejce, która zapewni nam ruchome okno. Następnie przed każdym wywołaniem metody weź obiekt z kolejki, weź jest wywołanie blokujące, które powróci dopiero po określonym opóźnieniu, a po wywołaniu metody nie zapomnij umieścić obiektu w kolejce ze zaktualizowanym czasem (tutaj bieżące milisekundy) .
Tutaj możemy również mieć wiele opóźnionych obiektów z różnym opóźnieniem. Takie podejście zapewni również wysoką przepustowość.
źródło
Moja implementacja poniżej może obsłużyć dowolną precyzję czasu żądania, ma złożoność czasową O (1) dla każdego żądania, nie wymaga żadnego dodatkowego bufora, np. Złożoność przestrzeni O (1), a ponadto nie wymaga wątku w tle do zwolnienia tokenu, zamiast tego tokeny są zwalniane zgodnie z upływem czasu od ostatniego żądania.
źródło
Spróbuj zastosować to proste podejście:
}
źródło
Apache Camel obsługuje również mechanizm Throttler w następujący sposób:
źródło
To jest aktualizacja powyższego kodu LeakyBucket. Działa to dla ponad 1000 żądań na sekundę.
a najbardziej nieprzejrzyste z powyższych:
źródło
minTimeNano
znaczy? możesz wytłumaczyć?Oto trochę zaawansowana wersja prostego ogranicznika prędkości
I testy jednostkowe
źródło
Moje rozwiązanie: Prosta metoda użycia, którą można zmodyfikować, aby utworzyć klasę opakowania.
Weź z JAVA Thread Debounce and Throttle
źródło