Eu preciso de um componente / classe que limita a execução de algum método para o máximo de chamadas M em N segundos (ou ms ou nanos, não importa).
Em outras palavras, preciso garantir que meu método seja executado não mais que M vezes em uma janela deslizante de N segundos.
Se você não conhece a classe existente, sinta-se à vontade para postar suas soluções / idéias sobre como implementar isso.
java
throttling
vtrubnikov
fonte
fonte
Respostas:
Eu usaria um buffer de anel de registros de data e hora com um tamanho fixo de M. Cada vez que o método é chamado, você verifica a entrada mais antiga e, se há menos de N segundos no passado, você executa e adiciona outra entrada, caso contrário, dorme para a diferença horária.
fonte
O que funcionou imediatamente para mim foi o Google Guava RateLimiter .
fonte
tryAquire()
Em termos concretos, você deve conseguir implementá-lo com a
DelayQueue
. Inicialize a fila comM
Delayed
instâncias com o atraso definido inicialmente como zero. À medida que as solicitações ao método chegam,take
um token, que faz com que o método seja bloqueado até que o requisito de limitação seja atendido. Quando um token é obtido,add
um novo token para a fila com um atraso deN
.fonte
offer
e possível crescimento da matriz) e é meio pesado para mim. Eu acho que para outros isso pode ser perfeitamente aceitável.Leia o algoritmo de bucket de token . Basicamente, você tem um balde com tokens. Toda vez que você executa o método, você recebe um token. Se não houver mais tokens, você bloqueia até obter um. Enquanto isso, há algum ator externo que reabastece os tokens em um intervalo fixo.
Não conheço uma biblioteca para fazer isso (ou algo semelhante). Você pode escrever essa lógica no seu código ou usar o AspectJ para adicionar o comportamento.
fonte
Se você precisar de um limitador de taxa de janela deslizante baseado em Java que funcione em um sistema distribuído, consulte o projeto https://github.com/mokies/ratelimitj .
Uma configuração suportada pelo Redis, para limitar solicitações por IP a 50 por minuto, seria assim:
Consulte https://github.com/mokies/ratelimitj/tree/master/ratelimitj-redis para obter mais detalhes sobre a configuração do Redis.
fonte
Isso depende da aplicação.
Imagine o caso em que vários encadeamentos desejam que um token realize alguma ação com taxa global limitada, sem permissão permitida (ou seja, você deseja limitar 10 ações por 10 segundos, mas não deseja que 10 ações aconteçam no primeiro segundo e permaneça 9 segundos parados).
O DelayedQueue tem uma desvantagem: a ordem na qual os tokens de solicitação de threads podem não ser a ordem em que eles recebem sua solicitação. Se vários threads estiverem bloqueados aguardando um token, não está claro qual deles utilizará o próximo token disponível. Você pode até ter tópicos esperando para sempre, no meu ponto de vista.
Uma solução é ter um intervalo mínimo de tempo entre duas ações consecutivas e executar ações na mesma ordem em que foram solicitadas.
Aqui está uma implementação:
fonte
minTime
significa aqui? O que isso faz? você pode explicar isso?minTime
é o tempo mínimo que precisa passar depois que um token é consumido antes que o próximo token possa ser consumido.Embora não seja o que você pediu,
ThreadPoolExecutor
que foi projetado para limitar solicitações M simultâneas em vez de solicitações M em N segundos, também pode ser útil.fonte
Eu implementei um algoritmo de limitação simples.Tente este link, http://krishnaprasadas.blogspot.in/2012/05/throttling-algorithm.html
Um breve sobre o algoritmo,
Esse algoritmo utiliza o recurso da fila Java atrasada . Crie um objeto atrasado com o atraso esperado (aqui 1000 / M para TimeUnit de milissegundos ). Coloque o mesmo objeto na fila atrasada que internamente fornece a janela móvel para nós. Então, antes de cada chamada de método pegar o objeto da fila, take é uma chamada de bloqueio que retornará somente após o atraso especificado e, após a chamada do método, não se esqueça de colocar o objeto na fila com tempo atualizado (aqui milissegundos atuais) .
Aqui também podemos ter vários objetos atrasados com atraso diferente. Essa abordagem também fornecerá alto rendimento.
fonte
Minha implementação abaixo pode lidar com precisão de tempo de solicitação arbitrária, possui complexidade de tempo O (1) para cada solicitação, não requer nenhum buffer adicional, por exemplo, complexidade de espaço O (1), além de não exigir que o thread em segundo plano libere o token. os tokens são liberados de acordo com o tempo decorrido desde a última solicitação.
fonte
Tente usar esta abordagem simples:
}
fonte
O Apache Camel também suporta vem com o mecanismo Throttler da seguinte maneira:
fonte
Esta é uma atualização para o código LeakyBucket acima. Isso funciona para mais de 1000 solicitações por segundo.
e o mais unittest para acima:
fonte
minTimeNano
significa aqui? você pode explicar?Aqui está uma versão um pouco avançada do limitador de taxa simples
E testes de unidade
fonte
Minha solução: Um método utilitário simples, você pode modificá-lo para criar uma classe de wrapper.
Retirar do debounce e acelerador de threads JAVA
fonte