Rate Limiting
Controlar a taxa de requisições que um cliente pode fazer a um serviço em um dado período — protegendo contra abuso, DDoS de baixa intensidade e consumo excessivo de recursos compartilhados.
Intenção
Rate limiting impõe um teto à velocidade com que um cliente pode consumir um serviço, garantindo que nenhum cliente — por engano ou má-fé — possa monopolizar os recursos e degradar a experiência dos demais.
Sem rate limiting, um único cliente que dispara um loop infinito de requisições, um bot de scraping agressivo ou um ataque volumétrico pode saturar completamente a capacidade de processamento do serviço, tornando-o indisponível para todos. Rate limiting é a primeira linha de defesa contra esse tipo de sobrecarga — mais simples e mais eficaz do que dimensionar a infraestrutura para absorver qualquer pico possível.
Problema
Serviços expostos a múltiplos clientes enfrentam desafios que rate limiting resolve diretamente:
- Abuso e raspagem (scraping): bots que fazem milhares de requisições por segundo para extrair dados, testar senhas por força bruta ou simplesmente sobrecarregar o serviço.
- Clientes com bugs: um cliente que entra em loop de retry sem backoff pode gerar mais requisições do que toda a base de clientes normal combinada.
- Consumo desproporcional de APIs pagas: num modelo de custo por requisição, um único cliente com comportamento errático pode gerar custos inesperados para o provedor.
- Proteção de endpoints custosos: geração de relatórios, envio de e-mails, consultas de banco complexas — operações que consomem recursos significativos precisam ser limitadas independentemente das demais.
Como funciona
Algoritmos principais
Token Bucket
Um bucket armazena até N tokens (capacidade máxima). Tokens são adicionados a uma taxa fixa (ex.: 10 tokens por segundo). Cada requisição consome um token; se o bucket estiver vazio, a requisição é rejeitada. Se o bucket estiver cheio e nenhuma requisição chegar, tokens acumulam até o limite máximo.
Vantagem: permite bursts legítimos — um cliente inativo acumula tokens e pode fazer N requisições em rajada quando precisar. Desvantagem: um burst até N pode acontecer a qualquer momento, o que pode sobrecarregar o serviço downstream que não está preparado para picos.
Leaky Bucket
Requisições entram numa fila e são processadas a uma taxa constante (ex.: 10 req/segundo), independente do ritmo de chegada. Se a fila encher, novas requisições são rejeitadas. A "torneira" vaza em ritmo constante — daí o nome.
Vantagem: suaviza bursts, protegendo o sistema downstream de picos. Desvantagem: requisições válidas em burst esperam na fila, aumentando a latência percebida.
Fixed Window Counter
Conta requisições dentro de uma janela fixa (ex.: 100 req por minuto, janela reseta todo minuto no segundo :00). Simples de implementar com um contador atômico e TTL.
Problema clássico: um cliente pode fazer 100 requisições nos últimos 5 segundos de uma janela e 100 nos primeiros 5 segundos da próxima — 200 requisições em 10 segundos, o dobro do limite pretendido.
Sliding Window Log
Registra o timestamp de cada requisição numa lista. Para cada nova requisição, remove da lista os timestamps mais antigos que N segundos e conta os restantes. Se o count excede o limite, rejeita. Mais preciso que Fixed Window, mas consome mais memória (um timestamp por requisição por cliente).
Sliding Window Counter
Híbrido eficiente: mantém o contador da janela atual e da janela anterior, calculando uma aproximação proporcional ao overlap com a janela anterior. Ex.: se a janela anterior teve 80 requisições, a janela atual tem 20 e estamos a 30% da janela atual, o contador estimado é 80 × 0.7 + 20 = 76.
Muito usado em produção: memória constante (dois contadores por cliente), sem a vulnerabilidade de burst da Fixed Window e com boa precisão.
Dimensões de rate limiting
Rate limiting pode ser aplicado em múltiplas dimensões, combinadas conforme o caso de uso:
Por IP — proteção básica contra bots; penaliza usuários
atrás de NAT corporativo (ver armadilhas)
Por usuário — limite por conta autenticada; mais justo
Por API key — controle granular para integrações e parceiros
Por endpoint — limites diferentes para /login (5/min) vs
/search (100/min)
Por tenant — em SaaS multi-tenant, limitar por organização
Combinado — por IP E por usuário E por endpoint simultaneamente
Implementação com Redis
Redis é o padrão para rate limiting em ambientes distribuídos (múltiplas instâncias de servidor). O contador precisa ser compartilhado — se cada instância mantiver o próprio contador, o cliente pode fazer N requisições por instância, multiplicando o limite pelo número de instâncias.
-- Fixed Window com Redis (Lua script para atomicidade)
local key = "rl:" .. client_id .. ":" .. window_start
local count = redis.call("INCR", key)
if count == 1 then
redis.call("EXPIRE", key, window_size_seconds)
end
if count > limit then
return 429
end
return 200
Quando usar
- APIs públicas: qualquer API exposta à internet deve ter rate limiting. Sem ele, um único cliente mal-configurado ou mal-intencionado pode derrubar o serviço inteiro.
-
Endpoints de autenticação: limitação agressiva em
/login,/forgot-passworde verificação de OTP é a proteção básica contra força bruta — 5 tentativas por minuto por IP é um ponto de partida razoável. - Operações custosas: geração de relatórios em PDF, exportação de dados, envio de e-mails em massa, chamadas a APIs externas pagas. Rate limiting protege tanto o custo operacional quanto a disponibilidade.
Quando ter cuidado
- Rate limiting muito agressivo em APIs internas: serviços internos que chamam uns aos outros em alta frequência podem sofrer degradação artificial por limites mal dimensionados. Monitorar e calibrar com base em dados reais de produção antes de reduzir limites.
- Limitar apenas por IP em contextos corporativos: centenas de funcionários de uma empresa podem compartilhar um único IP público — rate limiting por IP os trata como um único cliente. Prefira limitar por usuário autenticado nesses contextos.
Prós e contras
Prós
- Protege a disponibilidade do serviço contra abuso, bugs de cliente e ataques volumétricos de baixa intensidade.
- Garante equidade entre clientes: nenhum cliente individual monopoliza os recursos compartilhados.
- Protege custos operacionais em APIs pagas por requisição ou por operação custosa.
- Relativamente simples de implementar com Redis e idiomático em API Gateways (Kong, AWS API Gateway, Nginx).
Contras
- Clientes legítimos podem ser penalizados se os limites forem mal dimensionados ou se compartilharem IP com outros clientes.
- Não é defesa suficiente contra ataques DDoS volumétricos de alta intensidade — para isso, WAF e CDN com proteção DDoS são necessários.
- Requer estado distribuído (Redis) em ambientes com múltiplas instâncias, adicionando latência e dependência de infraestrutura.
- Limites fixos não se adaptam a variações legítimas de carga — um algoritmo mais sofisticado (ex.: Token Bucket com burst generoso) é mais justo.
Armadilhas comuns
1. Fixed Window com burst na virada
O problema mais clássico de rate limiting: 100 requisições nos últimos 5 segundos de uma janela mais 100 nos primeiros 5 segundos da próxima somam 200 em 10 segundos, embora o limite seja 100/minuto. Use Sliding Window Counter para mitigar — é a opção com melhor equilíbrio entre precisão, custo de memória e simplicidade de implementação.
2. Rate limiting por IP em redes corporativas
Uma empresa com 500 funcionários pode ter todos eles saindo pela mesma faixa de IP pública via NAT. Rate limiting agressivo por IP faz com que um funcionário que faz requisições normais seja bloqueado por culpa do comportamento de um colega. Sempre ofereça limites por usuário autenticado como alternativa.
3. Sem headers informativos na resposta 429
Uma resposta 429 Too Many Requests sem headers informativos deixa
o cliente às cegas: ele não sabe quantas requisições restam, quando o limite
reseta ou quanto tempo esperar. O resultado são retry loops com backoff arbitrário
ou, pior, retry imediato que piora a sobrecarga.
Sempre inclua: Retry-After (segundos até poder
tentar de novo), X-RateLimit-Limit (limite configurado),
X-RateLimit-Remaining (requisições restantes na janela atual) e
X-RateLimit-Reset (timestamp Unix do próximo reset).
4. Rate limiting só na borda sem proteção nos serviços internos
Se o rate limiting existe apenas no API Gateway, serviços internos que se chamam diretamente (sem passar pelo gateway) ficam desprotegidos. Um bug em um serviço A que faz chamadas em loop para o serviço B pode derrubar B mesmo com o gateway protegendo o tráfego externo. Considere rate limiting em nível de serviço para comunicação interna crítica.
Arquiteturas e padrões relacionados
O API Gateway é o local mais comum para implementar rate limiting em microsserviços — centralizando a política em um único ponto em vez de duplicar a lógica em cada serviço. Kong, AWS API Gateway, NGINX e Traefik oferecem rate limiting como funcionalidade nativa configurável.
Circuit Breaker e Rate Limiting são complementares: o Rate Limiting protege um serviço de sobrecarga causada por muitos clientes, enquanto o Circuit Breaker protege um cliente de continuar chamando um serviço que já está com falha. Juntos, formam uma camada robusta de resiliência.
Retries após receber 429 devem respeitar o Retry-After
e ser idempotentes — o servidor deve estar preparado para receber
a mesma requisição mais de uma vez sem efeitos colaterais indesejados.