Toda vez que alguém diz que “isso não escala”, vale desconfiar. Na prática, quase sempre existe um gargalo específico e nomeável por trás da frase — cache mal usado, ausência de um lock, I/O randômico. Raramente é a tecnologia em si.

Este é um roteiro curto para trocar uma afirmação genérica por uma investigação concreta: identificar o gargalo e entender o trade-off de cada solução.

1. Investigue o cache antes de adicioná-lo

Cache esconde o sintoma, não resolve a causa de uma performance ruim. Às vezes ele só adia o problema: cache miss, invalidação mal feita, dado stale servido pro usuário errado. Isso não quer dizer que cache é ruim — quer dizer que ele não substitui entender por que a aplicação está lenta antes de jogar uma camada de cache por cima.

Antes de chegar nisso, vale a pena esgotar o básico em PHP: opcache configurado direito e um FastCGI bem ajustado já resolvem boa parte do que as pessoas tentam consertar com cache.

2. Dê contexto à escala do banco

Um case real: a DigitalOcean rodou uma fila dentro do próprio banco (MySQL) por quase cinco anos, entre 2012 e 2017. Só depois que o negócio cresceu 10.000%, com mais de 15 mil conexões simultâneas, a arquitetura começou a engargalar de verdade — e foi só aí que redesenharam os serviços consumidores da fila e moveram tudo pro RabbitMQ.

Ou seja: banco relacional aguentou uma escala considerável antes de precisar de outra peça na arquitetura. Da próxima vez que alguém falar que “banco relacional não escala” sem dar contexto — qual escala, qual gargalo, qual trade-off — vale desconfiar.

Uma ferramenta prática que entra nesse tipo de discussão é o lock. Salvar mais de um dado ao mesmo tempo pode, e vai, causar race condition. Nesses casos, o caminho menos otimista é travar o dado enquanto ele é usado — mesmo que isso custe performance. Não é um erro de design, é uma troca consciente: você está pagando latência pra garantir consistência, e isso só faz sentido quando o dado realmente exige essa garantia.

3. Escolha a fila pelo problema

Kafka foi construído pra transacionar dados leves — mensagens pequenas — com velocidade como foco central do design. Duas estratégias fazem a maior parte do trabalho:

  • Zero-copy read: evita cópias desnecessárias de dados entre kernel e user space na hora de servir uma leitura.
  • Sequential I/O: escreve e lê no disco de forma sequencial em vez de randômica, o que é ordens de magnitude mais rápido em discos tradicionais — e ainda ajuda em SSD.

Isso não torna o Kafka “melhor” que o RabbitMQ. A escolha entre os dois não é sobre qual é mais rápido, é sobre qual modelo de garantia, replay e ordenação o seu problema pede. RabbitMQ com routing, exchanges e dead-letter queue continua sendo a fila “clássica” — e entender o que tem por trás dela ajuda bastante quem já usa filas no dia a dia e quer saber o motivo das escolhas do framework.

4. Termine com uma pergunta melhor

Da próxima vez que “isso não escala” aparecer numa conversa, troque a frase por uma pergunta melhor: qual é o gargalo específico, e qual o trade-off de resolvê-lo agora? Cache, banco e fila raramente são o problema — o problema é não saber nomear o que realmente está pesando.