Back-End

27 mar, 2026

A ilusão da escalabilidade: sistemas que escalam pior depois de crescer

Publicidade

Todo sistema escala bem. No começo. Nesse período são poucos usuários, pouca carga e pouca complexidade.

Tudo funciona. Rápido e Simples.

Até parar de funcionar.

O problema não aparece no início

As decisões que você toma no começo… geralmente são boas. Código simples, queries diretas e chamadas síncronas.

Tipo isso:

async function getUserDashboard(userId) {
  const user = await db.getUser(userId);
  const orders = await db.getOrders(userId);
  const recommendations = await getRecommendations(userId);

  return { user, orders, recommendations };
}

Funciona perfeitamente. Com 100 usuários. Mas e com 100 mil? A história muda.

O primeiro gargalo: chamadas em cascata

Esse código parece inofensivo. Mas ele é sequencial. Agora imagina: cada chamada leva 100ms.

Você acabou de criar uma resposta de 300ms. Sem perceber. Qual seria a solução óbvia?

Paralelizar.

async function getUserDashboard(userId) {
  const [user, orders, recommendations] = await Promise.all([
    db.getUser(userId),
    db.getOrders(userId),
    getRecommendations(userId)
  ]);

  return { user, orders, recommendations };
}

Isso até melhora. Mas não resolve tudo. Porque o problema não era só código. Era arquitetura.

O banco vira gargalo antes de você perceber

No começo, você consulta direto.

SELECT * FROM orders WHERE user_id = 123;

E funciona. Até o volume crescer. Agora você tem: Tabela grande, índices insuficientes e queries pesadas

E aí aparece: Timeout, Lock, Deadlock E o clássico: “Mas essa query sempre funcionou…”

E funcionava, sim. Com menos dados.

O erro clássico: escalar na aplicação, ignorar o banco

Muitos times tentam resolver assim: Mais instâncias, mais pods e mais CPU. Mas o gargalo está aqui:

SELECT * FROM transactions ORDER BY created_at DESC;

Sem índice. Você escala tudo. Menos o que importa.

Cache: solução ou novo problema?

A primeira reação é cache.

const cached = await redis.get(`user:${userId}`);

if (cached) return JSON.parse(cached);

Resolve? Sim, resolve. Mas cria novos problemas? Sim, cria!

Agora você precisa lidar com: Cache inválido, dados desatualizados e estratégia de expiração

E o clássico bug: “Atualizei, mas o usuário ainda vê o dado antigo”

O monólito que escala… até não escalar mais

Monólitos funcionam muito bem no início. Deploy simples, debug fácil e fluxo claro.

Mas aí cresce.

E você começa a ver isso:

if (user.type === 'premium') {
  // regra A
} else if (user.type === 'enterprise') {
  // regra B
} else {
  // regra C
}

Ou seja regras misturadas, domínios acoplados e código difícil de evoluir

E qualquer mudança… Quebra outra coisa.

Aí vem a decisão: “Vamos quebrar em microservices”.

E nasce algo assim:

user-service
order-service
payment-service

Agora seu problema não é mais escala. É comunicação.

await axios.get('user-service');
await axios.get('order-service');
await axios.get('payment-service');

Ou seja, latência, retry e falha em cascata.

A explicação é simples, você saiu de um gargalo e entrou em outro.

O efeito dominó da escalabilidade

Um serviço começa a ficar lento. A fila aumenta, o timeout cresce e o retry dispara.

E de repente: Sistema inteiro degradado.

Você não tem mais um problema local. Tem um problema sistêmico.

O dado cresce mais rápido que o código

Código cresce linearmente. Os dados crescem exponencialmente. e isso muda tudo.

Exemplo:

SELECT COUNT(*) FROM events;

Com mil registros? Instantâneo.

Com bilhões? Problema.

Agora você precisa:

  • Sharding
  • Particionamento
  • Arquivamento

Essas são coisas que você não pensou no início.

 

Observabilidade chega tarde demais

No começo, log resolve.

console.log('processing order', order.id);

Mas, e depois? Não resolve mais.

Você precisa de:

  • Tracing
  • Métricas
  • Alertas

Porque o problema não é mais “o que aconteceu”.

É “onde aconteceu”.

A armadilha da escalabilidade

Você acha que está escalando. Mas na verdade…

Está acumulando complexidade. E complexidade desacelera.

O você sabe o que times maduros fazem diferente?  Eles não escalam tudo.

Eles identificam gargalos reais. Antes de otimizar, eles medem.

Antes de distribuir, eles simplificam.

Exemplo:

if (slowQuery) {
  addIndex();
}

Não: “vamos migrar tudo para microservices”. É importante lembrar que escalar não é adicionar. É remover gargalos. Às vezes, a melhor otimização é:

  • Remover query
  • Simplificar fluxo
  • Reduzir dependência
  • Não adicionar tecnologia.

Em resumo

Seu sistema não escala mal por falta de tecnologia. Ele escala mal por decisões que funcionavam… Só que em outra escala.

E o mais perigoso? Elas continuam lá. Rodando.

Até o dia que não aguentam mais. E quando isso acontece… Escalar deixa de ser evolução.

Vira sobrevivência.