Algoritmo de limitador atual
Atualmente, existem dois algoritmos comuns de limitadores de corrente: algoritmo de balde de token e algoritmo de balde com vazamento. A principal diferença é que o algoritmo de balde com vazamento pode limitar a taxa de solicitação à força e as solicitações de explosão suaves, enquanto o algoritmo de balde de token permite uma certa quantidade de solicitações de explosão ao limitar a taxa média.
Abaixo estão dois diagramas de algoritmo encontrados na Internet, que podem ser facilmente distinguidos das características desses dois algoritmos.
Algoritmo de balde de vazamento
Algoritmo de balde de token
Para interfaces, um certo número de solicitações de explosão geralmente pode ser processado e apenas a taxa média é necessária para limitar, portanto, o algoritmo de balde de token é mais comum.
Token Bucket Algorithm Tool Ratelimiter
A classe de implementação do algoritmo do balde de token que eu uso mais comumente usada é o Ratelimiter do Google Guava. A goiaba não apenas implementa o algoritmo de balde de token, mas também cache, novas aulas de coleção, classes de ferramentas simultâneas, aulas de processamento de strings etc. É um poderoso conjunto de ferramentas
A API Ratelimiter pode visualizar a introdução do guava ratelimiter em rede de programação simultânea
Análise do código fonte do ratelimiter
Por padrão, os atributos mais principais do Ratelimiter são dois próximos FreeticketMicros. O horário do token pode ser obtido na próxima vez e o número de tokens no balde armazenado.
Determine se deve obter o token:
Toda vez que você recebe um token, calcule o tempo mais rápido para obter o token na próxima vez com base no número de tokens no balde. Ao determinar se o recurso pode ser obtido, basta comparar o NextFreeticketMicros com o horário atual.
Obtenha operação de token:
Para obter o token, calcule o número de novos tokens com base nos próximos freeticketmicros e no horário atual, escreva o número de token do balde de token atual e recalcule o próximo FreeticketMicros. Se houver um token no balde, escreva a hora atual e reduza o número de tokens obtidos por esta solicitação.
Assim como a classe AQS em Java, o núcleo de Ratelimiter é o método TryAcquire
public boolean TryAcquire (INT permissões, tempo limite de longo prazo, unidade de unidade de tempo) {// Tente obter o tempo máximo de espera de tempo limite de tempo limite = max (unit.tomicros (tempo limite), 0); // Verifique se o número de recursos obtidos é o CheolPerMits (Permissões) corretos; Longo MicrotoWait; // bloqueio sincronizado (mutex ()) {// Tempo atual nowMicros = stopwatch.readMicros (); // julga se o recurso pode ser obtido dentro do tempo limite se (! Canacquire (NowMicros, timeoutMicros)) {return false; } else {// O recurso pode ser obtido, recalculou o recurso e retornou o tempo de sono exigido pelo Thread atual microStowait = reservatório e comprimento (permissões, agoraMicros); }} // o sono StopWatch.sleepmicrosuninterruptível (MicroStowait); retornar true; }Determine se deve obter o token:
CANOLEAN PRIVADO CANACQUIRE (Long NowMicros, TimeoutMicros longo) {// No primeiro tempo de recurso pode ser obtido - o tempo de espera <= o horário atual pode ser obtido antes que o recurso possa ser obtido devolução de retorno que não está disponível (NowMicros) - Timeoutmicros <= NowMicros;}Classe de implementação padrão do RatElimiter QueryearliestAvailable é levar a variável de membro NextFreeticketMicros
Pegue o token e calcule a operação de tempo de espera necessária:
Final Longo ReserveArDGGetWaitLength (Int Permissões, Long NowMicros) {// Obtenha tempo para obter a próxima vez em que há muito tempo disponível = ReservearliestAvailable (Permissões, NowMicros); // Calcule o tempo de sono necessário para que o thread atual retorne Max (MomentAvilable - NowMicros, 0);} Final Long ReservearliestAvailable (int requerkPermits, Long NowMicros) {// Recalcula o número de tokens no balde StororedPermits ReSync (NowMicros); Long ReturnValue = NextFreeticketMicros; // o número de tokens consumido desta vez StororedPerMitStend = min (requerirPermits, this.StoredPerMits); // Recalcula o tempo para obter a próxima vez que a próxima freeticketmicros dupla FreshperMits = requerirPermits - StoredPerMitstospend; WaitMicros longo = StororDerMitStowaittime (this.StoredPerMits, StoredPerMitstospend) + (longo) (freshPerMits * stableIntervalMicros); this.NextfreeticketMicros = longMath.saturatedAdd (NextFreeticketMicros, WaitMicros); // reduz o número de tokens no balde this.storedPermits -= storedPerMitstostend; return retornValue; }Implementar um interceptador atual de limite atual do MVC de primavera
Implementar um HandlerInterceptor, crie um limitador de corrente Ratelimiter no construtor
public SimpleRatelImitIntercept (taxa int) {if (taxa> 0) globalratelimiter = ratelimiter.create (taxa); caso contrário, jogue novo RuntimeException ("Taxa deve maior que zero");}Chame o método TryAcquire do limitador atual em prendmão para determinar se a taxa de limite o excedeu
Public Boolean Prehandle (solicitação httpServletRequest, resposta httpSertletResponse, manipulador de objetos) lança exceção {if (! globalratelimiter.TryAcquire ()) {LoggerUtil.log (request.getRequesturi ()+"Solicitação Exceda a taxa de limitador atual"); retornar falso; } retornar true; }Configure o interceptador de limite atual no Dispatcher-Servlet.xml
<mvc: interceptores> <!-Interceptador de limite atual-> <mvc: interceptor> <mvc: mapeamento path = "/**"/> <ean> <construtor-arg index = "0" value = "$ {totalrate}"/> </bean> </mvc: intercetor> </mvrate} "/> </bean>Versão complexa do interceptador de limite atual do MVC da primavera
Use propriedades para passar na expressão de URL interceptada -> taxa de taxa
<mvc: interceptor> <mvc: mapeamento de caminho = "/**"/> <iBean> <!-URL único limite de corrente-> <propriedade name = "urlProperties"> <ports> <propra key = "/get/{id}"> 1 </prop. Crie um limitador de corrente Ratelimiter correspondente para cada expressão de URL. A expressão de URL é encapsulada como org.springframework.web.servlet.mvc.condition.patternsRequestCondition. PatternSRequestCondition é uma classe usada no DispatcheserServlet da SpringMVC para corresponder solicitações e controladores. Pode determinar se a solicitação está em conformidade com essas expressões de URL.
No método interceptador de pré -manuse
// O caminho da solicitação atual string lookuppath = urlpathhelper.getLookuppathForReQuest (request); // itera sobre o padringSRequestCondition correspondente a todas as expressões de URL (PatternSReQuestCondition PatternSReQuestCondition: urlratemap.KeySet ()) {// Faz uma lista PatternSRequestCondition.GetMatchingPatterns (Lookuppath); if (! Matches.isEmpty ()) {// Se a correspondência for bem -sucedida, obtenha o token do limitador de corrente correspondente if (urlratemap.get (padrão -rEQuestcondition) .TryAcQuire ()) {LoggerUtil.log (LookUppath + "solicitado a" + JONER.On (""). limitador "); } else {// falhou ao obter o token loggerutil.log (lookuppath + "solicitação excede" + juner.on (","). junção (padronSRequestCondition.getPatterns ()) + "taxa de limitador de corrente"); retornar falso; }}}Classes de implementação específicas
Por favor, veja o Github
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.