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.




