System Design/02 - Componentes/Asynchronism2 min
Back Pressure
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
Back pressure é o mecanismo pelo qual um componente sobrecarregado sinaliza para trás que não consegue absorver mais trabalho — fazendo o produtor desacelerar em vez de continuar empurrando.
Sem ele, o excesso vira fila crescente, memória consumida e, por fim, colapso.
Por que a fila não resolve sozinha
Uma fila absorve pico — variação temporária. Se a taxa média de chegada excede a de processamento, a fila cresce indefinidamente:
chegada 1.000/s, processamento 800/s
→ +200 mensagens/s acumuladas
→ em 1 hora: 720.000 mensagens presas
→ latência da última mensagem: ~15 minutos
O sistema parece "no ar" enquanto entrega respostas cada vez mais velhas — modo de falha pior do que rejeitar.
Mecanismos
| Mecanismo | Como funciona |
|---|---|
| Fila limitada | Ao encher, bloqueia ou rejeita o produtor |
| Throttling / rate limit | Rejeita com 429 Too Many Requests |
| Load shedding | Descarta o trabalho de menor valor deliberadamente |
| Pull em vez de push | O consumidor puxa no seu ritmo (Kafka, Reactive Streams) |
| Semáforo | Limita concorrência (Bulkhead) |
| Timeout agressivo | Abandona trabalho que já não interessa a ninguém |
Trade-offs
Back pressure exige rejeitar trabalho — e isso parece errado até você ver 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 (429) é quase sempre melhor que aceitar e demorar: o cliente pode tentar outro caminho, e o sistema não gasta recursos em trabalho que vai expirar.
O risco de propagar back pressure é a paralisia em cascata: se A desacelera porque B desacelerou, e o cliente de A é o usuário, o usuário sente. Por isso costuma vir combinado com load shedding — em vez de desacelerar todos, sacrifica-se o tráfego menos importante.
Fila ilimitada é sempre um bug, mesmo quando parece generosidade: transforma um problema de capacidade visível num problema de memória invisível.
Exemplo prático
Um serviço de ingestão recebe eventos e grava num banco que aguenta 5.000 escritas/s. Chegam 8.000/s.
Sem back pressure: buffer em memória cresce, GC sofre, latência sobe, e o processo morre por OOM — perdendo tudo que estava em memória.
Com back pressure: o buffer é limitado a 10.000. Ao encher, o serviço responde 429 com Retry-After. O cliente reduz o ritmo. O sistema entrega 5.000/s de forma estável e rejeita o excesso previsivelmente — e a métrica de rejeição torna o déficit de capacidade visível antes de virar incidente.
Relacionado
Parte de Asynchronism · roadmap.sh/system-design