Backpressure é o problema que surge quando o produtor de um sistema distribuído cria dados em velocidade maior do que o consumidor consegue processar. Sem controle, a fila entre os dois cresce até estourar memória e derrubar o serviço. Este artigo explica o mecanismo e as técnicas práticas de contenção.
O que é backpressure na prática
Backpressure é o problema que ocorre quando o produtor produz em uma velocidade que o consumidor não consegue acompanhar. Em inglês, o termo significa literalmente "pressão nas costas": o fluxo de entrada empurra dados contra uma parte do sistema que não dá conta de processá-los.
Esse padrão aparece em qualquer relação de produtor e consumidor. Um web crawler que baixa páginas enquanto outro módulo analisa e indexa é um exemplo. O upload de um vídeo por um usuário, seguido de armazenamento e compressão, é outro. O padrão também aparece em ferramentas de automação como o n8n, que executa workflows onde um passo produz dados para o próximo consumir.
Considere um produtor que encontra 100 sites por minuto e envia tudo para o consumidor, que só consegue armazenar e indexar 10 por minuto. Em dez minutos o descasamento é de 900 páginas. Se nada for feito, esse número só cresce.
Por que a fila sozinha não resolve o problema
A solução instintiva é colocar uma fila entre produtor e consumidor. A fila funciona como buffer: absorve picos e dá ao sistema uma vazão mais contínua. Mas a fila tem um limite físico de memória, medido em bytes, e o descasamento de velocidade continua existindo.
Com o tempo surgem efeitos secundários. Os jobs envelhecem: se o produtor enche a fila em um mês e o consumidor leva dez meses para processar, o site que estava na frente já mudou quando chegar a vez dele. A informação se torna obsoleta antes de ser tratada.
Eventualmente a fila cresce tanto que o uso de memória derruba o sistema inteiro. Adicionar mais capacidade à fila ou criar mais filas apenas empurra o problema para frente, sem eliminar a causa.
Onde está o gargalo de verdade
Antes de qualquer otimização, você precisa localizar o gargalo real. O consumidor pode processar apenas 10 sites por minuto porque o banco de dados só aceita gravações nessa velocidade. Nesse caso, jogar mais hardware no consumidor não muda nada.
Essa é a lição central de backpressure em system design: medir antes de escalar. Se o gargalo é o banco, a resposta é batch insert, índice ou troca de tecnologia de persistência, e não mais réplicas do consumidor.
Existem também alívios baratos que valem antes de qualquer compra de infraestrutura:
- Podar jobs antigos (stale jobs): uma varredura periódica remove da fila tudo que expirou, falhou ou não faz mais sentido processar.
- Priorizar a fila: itens críticos saem primeiro, e o atraso recai sobre o que pode esperar.
- Processar em lotes (batches): processar 10 sites de uma vez e gravar com um batch insert aumenta a vazão com o mesmo hardware, porque reduz o número de requisições ao banco.
Essas três medidas são mais fáceis e mais baratas do que simplesmente adicionar máquinas, e em muitos casos já reduzem o lag a níveis aceitáveis.
Fila bounded e admission control
A primeira solução estrutural é tornar a fila bounded, ou seja, limitada: ela tem um tamanho máximo e não cresce infinitamente. Quando a fila enche, o problema migra para o produtor, que precisa lidar com a recusa. Isso parece trocar seis por meia dúzia, mas garante que o sistema não vai estourar.
Os riscos ficam do lado do produtor: ele pode perder itens se a lógica de retry estiver mal feita, ou estourar a própria memória se tentar reenviar para sempre. Mesmo assim, fila limitada é considerada boa prática na literatura de system design.
A segunda técnica é o admission control: um ponto de decisão que rejeita novos jobs quando a fila está cheia demais. Você pode implementar no próprio produtor ou como um middleware que consulta o tamanho da fila antes de aceitar trabalho. A mensagem é simples: tem muita coisa na fila, esse job não entra.
Rate limit, escala horizontal e o papel do retry
O rate limit ataca o problema na origem. Se você sabe que o consumidor processa 10 itens por minuto, limite o produtor à mesma taxa. Produzir mais rápido só queima recurso computacional e adiciona pressão que o sistema não consegue absorver.
Depois de alinhar as velocidades, a alavanca seguinte é escala horizontal: rodar o consumidor em dois, três ou mais servidores, formando um cluster, e paralelizar também a fila para suportar a vazão maior. É possível configurar auto scaling baseado no tamanho da fila, embora essa configuração seja trabalhosa no contexto de filas.
Um cuidado importante: a política de retry entre produtor e fila pode agravar o problema. Retry é necessário, mas uma política que tenta muitas vezes seguidas adiciona ainda mais pressão ao sistema justamente quando ele está sobrecarregado. Prefira backoff exponencial e limite de tentativas. Monitoramento e alertas sobre o tamanho da fila completam o conjunto.
Como implementar backpressure com BullMQ e Redis
A técnica de low watermark e high watermark mostra o mecanismo em código. O produtor consulta o tamanho da fila no Redis, banco de dados em memória usado como infraestrutura de fila. Se o número de jobs passa do high watermark (por exemplo, 100), o produtor pausa e só verifica a fila de tempos em tempos. Quando o tamanho cai abaixo do low watermark (30), ele retoma a produção.
No vídeo que originou este artigo, o canal do Augusto Galego demonstrou o efeito em duas versões de um script em JavaScript rodando em um único arquivo. Na versão sem controle, a contagem chegou a 922 jobs aceitos contra 123 processados, com um lag de 799 itens. Na versão com watermarks, usando a biblioteca BullMQ sobre um Redis no Docker, o tamanho da fila subiu até 93, parou, desceu até perto de 30 e voltou a oscilar dentro dessa faixa. O lag nunca fica grande.
Em produção as peças não rodariam no mesmo servidor nem em um index.js, mas o mecanismo é o mesmo: o produtor sempre pergunta à fila quanto trabalho ela ainda aguenta antes de enviar o próximo item.
Perguntas frequentes sobre backpressure
- Backpressure é um bug? Não é um bug, é uma consequência natural de um produtor mais rápido que o consumidor. Vira incidente quando ninguém implementa contenção e a fila cresce até esgotar a memória.
- Qual a diferença entre rate limit e admission control? O rate limit restringe a velocidade de produção de forma contínua. O admission control decide, job a job, se aceita ou rejeita trabalho novo com base no estado atual da fila. Os dois podem coexistir.
- Fila infinita ou fila limitada: qual usar? Fila limitada (bounded). Fila sem limite esconde o problema até a memória acabar, enquanto a limitada transfere a pressão para o produtor, que pode pausar ou rejeitar de forma controlada.
- Quando devo escalar o hardware em vez de otimizar código? Depois de localizar o gargalo e aplicar as medidas baratas: poda de jobs antigos, priorização, processamento em lotes e watermarks. Se o lag ainda for inaceitável, adicione consumidores e paralelize a fila.
Transforme suas aulas técnicas em artigos
O conceito que você acabou de ler nasceu em uma aula de system design de onze minutos no YouTube. Conteúdo assim costuma ficar preso no formato de vídeo, difícil de citar, buscar e revisar depois.
Se você também ensina em vídeo e quer esse conhecimento em formato de artigo, o fluxo do Skala Blog é direto: você cola a URL do vídeo, a plataforma transcreve e gera um artigo estruturado como este, pronto para sua revisão antes de publicar.
Fork this article
Start a new branch from the same video, shaped your way. You keep the credit; the original keeps the attribution.
A fork in another language is filed as a translation of this article, so the two pages point at each other. You can unlink it later from the editor.
0/240
You are creating
- Format
- For
- Language
- Source
- Your angle
You will be asked to sign in before it is generated.
Buy credits