O endpoint ficou lento. O reflexo é quase automático: aumentar RAM, subir a CPU, pedir uma instância maior. Às vezes isso funciona. Muitas vezes só adia o diagnóstico e encarece o mesmo desenho.
Escalabilidade não é potência bruta. É a capacidade do sistema de acompanhar a demanda sem transformar cada pico em incidente. Se você mede só “a máquina está cheia”, trata sintoma. Se mede tempo de resposta e o que acontece dentro de cada requisição, começa a ver o problema.
O que a métrica está pedindo
Em aplicação web, a métrica que o usuário sente é o tempo de resposta. Query lenta, relatório pesado e envio de e-mail na mesma request aparecem todos como “o site travou”. Do lado do servidor, CPU alta e memória saturada são consequências, não o mapa.
Antes de comprar recurso, pergunte: o que esta requisição precisa terminar antes de responder? Se a resposta inclui trabalho que o usuário não precisa esperar — e-mail, thumbnail, exportação, chamada a um parceiro lento —, o gargalo não é falta de RAM. É o desenho síncrono.
Um sistema mais rápido também é mais barato de escalar. Cada requisição que libera o processo cedo devolve capacidade para a próxima. Escalar um endpoint que segura o worker por oito segundos custa mais do que escalar um que responde em oitenta milissegundos e deixa o resto para depois.
Vertical: um servidor mais gordo
Escalabilidade vertical é acrescentar recurso na mesma caixa: mais núcleos, mais memória, disco mais rápido. O modelo mental é simples. O código quase não muda. O banco que “não aguenta” ganha buffer. O PHP-FPM ganha filhos. O problema parece resolvido na fatura.
O limite aparece cedo. Existe um teto de hardware. Existe um teto de preço. Existe um teto de risco: uma máquina só continua sendo um ponto único de falha, agora mais caro. E existe um teto conceitual: se cada request faz I/O externo e espera, mais CPU não encurta a espera da rede.
Vertical ainda é o primeiro passo certo em muitos casos. Um servidor subdimensionado, um pool de processos minúsculo, um MySQL sem memória para índices quentes — aí sim, RAM resolve. O erro não é usar vertical. É usá-la como substituto de arquitetura.
Horizontal: mais peças, não uma peça maior
Escalabilidade horizontal é acrescentar instâncias: mais processos, mais workers, mais servidores atrás de um balanceador. Cada peça faz uma fatia do trabalho. A demanda sobe, você replica. A demanda desce, você reduz.
Horizontal exige outra disciplina. Estado local vira problema. Sessão em arquivo no disco da máquina A não existe na máquina B. Cache em memória de um processo não serve ao outro. Upload gravado em /tmp some no próximo hop. Sem esse cuidado, “vários servidores” só multiplica inconsistência.
A recompensa é o eixo certo de crescimento. Workers de fila podem crescer sem crescer a API. Leitura pode crescer sem crescer escrita. Relatório pode crescer sem prender o checkout.
flowchart TD
A[Request lenta] --> B{O usuário precisa esperar?}
B -->|Sim, é o núcleo| C[Medir e otimizar]
C --> D{Gargalo é CPU/RAM?}
D -->|Sim| E[Escala vertical]
D -->|Não| F[Separar o trabalho]
B -->|Não| F
F --> G[Publicar na fila]
G --> H[API responde cedo]
H --> I[Workers horizontais]
classDef ouro fill:#FBF5E4,stroke:#C9A227,color:#0B1F18,stroke-width:1.4px
classDef verde fill:#F3FAF7,stroke:#1E7A57,color:#0B1F18,stroke-width:1.4px
classDef fim fill:#14513B,stroke:#0F3328,color:#FBFAF6,stroke-width:1.4px
class A ouro
class B,C,D,F,G verde
class E,H,I fim
Quando adicionar RAM é o movimento errado
RAM é o movimento errado quando o tempo está em espera, não em computação. Enviar e-mail SMTP, gerar PDF, chamar gateway, percorrer milhares de linhas para um relatório “na hora” — nada disso some porque a máquina ganhou 16 GB.
Também é o movimento errado quando você ainda não sabe o teto atual. Sem perfil, sem log de duração por rota, sem olhar fila de processos, “mais RAM” é um palpite caro. Já vi pool de PHP com poucos filhos e memória ociosa: o servidor não estava pequeno; estava mal configurado. Já vi query sem índice fazendo full scan: o banco pedia índice, não instância maior.
Há um terceiro caso, mais sutil. O sistema cresce em usuários, mas o trabalho por request também cresce — mais jobs no mesmo request, mais integrações síncronas, mais “já que estamos aqui”. Vertical cobre o crescimento por um trimestre. Depois o mesmo desenho volta a doer, só que a conta já é alta e o medo de mudar também.
Fila e assíncrono: o truque que destrava o horizontal
Mensageria não é um adorno de arquitetura. É o mecanismo que transforma “uma request faz tudo” em “uma request registra a intenção”. Publicar numa fila é, em geral, milissegundos. Enviar o e-mail pode ser segundos. A API devolve 202 ou 200 com “vamos avisar”, e o worker trata o restante.
Isso habilita horizontal de verdade. A API escala com o tráfego de cliques. Os workers escalam com o volume de tarefas. Se a fila enche, você sobe consumidores, não a máquina do front. Se o e-mail do provedor atrasar, o checkout não atrasar junto.
O mesmo padrão vale para relatório pesado, redimensionamento de imagem, recálculo de ranking, sincronização com ERP. Tudo que é lento e não precisa estar na resposta imediata pode sair do caminho crítico. Tudo que precisa estar — saldo, autorização, idempotência do pagamento — permanece síncrono, medido e curto.
| Situação | Primeiro movimento | Por quê |
|---|---|---|
| Pool de processos saturado, CPU baixa | Ajustar pool ou vertical leve | Capacidade ociosa mal usada |
| Query lenta, mesmo com pouca carga | Índice, plano, cache pontual | Hardware não corrige N+1 |
| E-mail ou PDF na request | Fila + worker | Espera externa no caminho crítico |
| Pico de leitura, escrita estável | Réplicas / mais instâncias | Eixo de crescimento diferente |
| Uma caixa só, medo de cair | Horizontal + estado externo | Vertical não remove SPOF |
Três perguntas antes de escalar
- Qual é o percentil de tempo de resposta que dói — p50, p95, p99?
- Onde esse tempo é gasto: CPU, disco, lock, rede, espera de terceiro?
- Esse trabalho precisa terminar para o usuário receber a resposta?
Se você não responde as três, vertical é chute. Se responde e o trabalho não precisa estar na request, horizontal via fila costuma ser o caminho. Se o trabalho precisa e é CPU de verdade, aí sim, máquina maior ou algoritmo melhor.
Escalar bem é escolher o eixo. Para cima, quando o recurso da caixa é o limite. Para o lado, quando a unidade de trabalho já pode ser repetida. A pressa de “só sobe a RAM” mistura os dois e deixa a arquitetura presa numa conta que só cresce.
Na Programming One essa conversa aparece no código: o projeto cresce até o servidor único não bastar, e a solução deixa de ser “mais RAM” para virar processo, fila e réplica.
Leia também: Mensageria: por que filas melhoram a resposta e Load balancer, Nginx e vários servidores.