System Design/05 - Reliability Patterns/Availability2 min
Throttling
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
Limitar deliberadamente o consumo de recursos por cliente, para preservar o serviço para todos. É Back Pressure aplicado na fronteira.
Algoritmos
| Algoritmo | Comportamento |
|---|---|
| Token bucket | Permite rajada até o tamanho do balde; repõe a taxa constante |
| Leaky bucket | Saída sempre constante; suaviza o tráfego |
| Fixed window | Simples; sofre com o efeito de borda (2x no limite da janela) |
| Sliding window | Preciso, mais caro em estado |
Token bucket é o padrão na maioria das APIs por permitir rajada legítima sem perder o controle da média.
Como comunicar
HTTP 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
Rejeitar sem dizer quando tentar de novo praticamente garante Retry Storm.
Trade-offs
Throttling exige rejeitar trabalho, e isso parece errado até se comparar com a alternativa. A escolha real não é "aceitar tudo ou rejeitar alguns"; é "rejeitar alguns explicitamente" ou "degradar para todos e cair".
Rejeitar cedo e rápido é quase sempre melhor que aceitar e demorar: o cliente pode reagir, e o sistema não gasta recursos em trabalho que vai expirar.
Os pontos de atenção:
Onde contar. Rate limit por instância, com N instâncias, dá um limite efetivo N vezes maior. Contagem distribuída (Redis) é precisa e adiciona latência e uma dependência no caminho crítico.
Por quem contar. Por IP quebra com NAT — um escritório inteiro compartilha um IP. Por chave de API ou usuário é o correto; IP serve como defesa complementar contra anônimos.
Limite justo. Muito baixo prejudica uso legítimo; muito alto não protege. Definir a partir de percentis do tráfego real é melhor que arbitrar.
E há a alternativa a rejeitar: degradar. Servir resposta cacheada, versão simplificada ou dados parciais preserva mais valor que um 429 — quando o caso permite.
Exemplo prático
plano gratuito: 100 req/min, rajada de 20
plano pago: 5.000 req/min, rajada de 500
interno: sem limite
Um cliente do plano gratuito com um laço defeituoso é contido em 100 requisições por minuto. Sem o limite, ele consumiria a capacidade compartilhada e degradaria todos os demais — o Noisy Neighbor clássico.
O Retry-After na resposta é o que transforma a rejeição em cooperação: o cliente espera o tempo indicado em vez de repetir imediatamente e amplificar o problema.
Relacionado
Parte de Availability · roadmap.sh/system-design