Todos os artigos
168 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Dicas

Auto scaling: quando escalar horizontalmente

Auto scaling: entenda quando escalar horizontalmente, os principais benefícios, limitações e situações em que realmente vale a pena.

Auto scaling: quando escalar horizontalmente
COVER · Dicas

A Black Friday começou e o time configurou o autoscaling para subir réplicas quando a CPU passasse de 70%. Funcionou — o cluster inflou para 40 pods. O problema: a latência continuou péssima. A CPU estava baixa porque os requests estavam todos parados esperando uma query lenta no banco, e o banco era uma instância só. Escalar horizontalmente multiplicou consumidores de um gargalo que não escalava. Autoscaling não conserta arquitetura ruim; ele amplifica o que você já tem, para o bem e para o mal.

Este artigo é sobre decidir quando escalar horizontalmente faz sentido e quando é só queimar dinheiro. Se o seu plano é distribuir o tráfego entre várias réplicas, leia também como um load balancer distribui requisições com segurança — autoscaling sem um balanceador saudável na frente não entrega nada.

Vertical vs horizontal: não é a mesma decisão

Escalar vertical é trocar a máquina por uma maior: mais CPU, mais RAM. Simples, sem mudança de código, mas tem teto físico e cada upgrade costuma exigir restart (downtime). Escalar horizontal é adicionar mais instâncias da mesma aplicação atrás de um balanceador. Não tem teto prático, mas exige que a aplicação tolere rodar em N cópias ao mesmo tempo.

A regra mental que uso: vertical resolve "minha máquina é pequena demais", horizontal resolve "preciso de mais máquinas". São problemas diferentes. Muita gente parte para horizontal quando o que precisava era trocar uma instância subdimensionada por uma maior — e aí carrega a complexidade de coordenação sem motivo.

O que autoscaling realmente resolve

Autoscaling resolve carga variável: tráfego que sobe e desce ao longo do dia, picos previsíveis (campanhas) e imprevisíveis (viralização). Você paga por capacidade próxima da demanda real em vez de provisionar para o pico o tempo todo.

O que autoscaling não resolve:

  • Query lenta. Mais réplicas = mais conexões batendo no mesmo banco gargalado. Você escala o problema.
  • Memory leak. Réplicas novas vazam igual; você só atrasa o OOM e paga mais por isso.
  • Deadlock ou lock contention. Mais consumidores brigando pelo mesmo lock pioram a situação.

Se a métrica que dispara o scaling é sintoma de um gargalo single-point, autoscaling vai piorar, não melhorar. Diagnostique antes de escalar.

Statelessness é pré-requisito, não detalhe

Para uma aplicação escalar horizontalmente sem bugs bizarros, cada instância precisa ser intercambiável. Isso significa: nenhum estado de sessão na memória do processo, nenhum arquivo gravado no disco local que outra réplica precise ler, nenhuma suposição de "sempre cai no mesmo pod".

Onde mora o estado, então:

  • Sessão → Redis, ou JWT stateless.
  • Uploads/arquivos → object storage (S3 e afins), nunca disco local da instância.
  • Cache → store compartilhado, não memória do processo (ou cache local que tolere inconsistência).

Se você liga autoscaling numa aplicação stateful, o sintoma clássico é o usuário ser deslogado a cada request porque o balanceador o jogou num pod que não tem a sessão dele. Sem sticky sessions hackeadas — resolva o estado na origem.

Em qual métrica escalar (CPU é uma armadilha)

CPU é o default de todo tutorial e quase sempre a métrica errada. Aplicação I/O-bound — que é a maioria das web apps — passa o tempo esperando banco e APIs externas, com CPU baixa enquanto a latência explode. Escalar por CPU nesse caso só dispara tarde demais, ou nunca.

Métricas melhores, por ordem de preferência:

  • Latência de request (p95/p99): é o que o usuário sente. Se o p95 passa do SLA, escale.
  • Profundidade de fila: para workers, o tamanho da fila é o sinal mais honesto de "não estou dando conta".
  • Requests por segundo por instância: se você sabe quantos RPS uma réplica aguenta com folga, escalar por RPS é previsível.
  • CPU: válida só para cargas genuinamente CPU-bound (processamento de imagem, compressão, cripto).

Scale-up e scale-down não são simétricos

Subir réplica deve ser rápido e agressivo: o tráfego já está aí, atrasar custa SLA. Descer deve ser lento e conservador. Se você remove réplicas no primeiro respiro da carga, entra em flapping — sobe, desce, sobe, desce — e cada ciclo paga cold start, derruba conexões e bagunça o cache.

Por isso existem cooldowns assimétricos:

behavior:
  scaleUp:
    stabilizationWindowSeconds: 0      # sobe na hora
    policies:
      - type: Pods
        value: 4
        periodSeconds: 30
  scaleDown:
    stabilizationWindowSeconds: 300    # espera 5 min de calmaria antes de descer
    policies:
      - type: Pods
        value: 1
        periodSeconds: 60

Suba rápido, desça devagar. O custo de uma réplica a mais por alguns minutos é trivial perto do custo de flapping.

Armadilhas de custo e quando NÃO autoescalar

Autoscaling sem teto (maxReplicas) é um cheque em branco: um loop de retry mal feito ou um ataque podem inflar o cluster até a fatura assustar. Sempre defina um máximo. Outra armadilha: escalar a aplicação mas não o banco — você multiplica conexões e estoura o pool do Postgres, derrubando tudo.

Quando não autoescalar:

  • Carga estável e previsível. Capacidade fixa é mais simples e mais barata; autoscaling adiciona complexidade sem ganho.
  • Banco como gargalo real. Conserte a query, adicione índice, coloque cache. Escalar a app não toca no problema.
  • Aplicação stateful que você não pode (ainda) tornar stateless. Resolva o estado primeiro.

O que decidir antes de ligar o autoscaling

Antes de ativar autoscaling, responda três coisas: a aplicação é stateless de verdade? A métrica de scaling reflete a dor do usuário (latência/fila), e não um proxy enganoso como CPU em carga I/O-bound? E o gargalo está mesmo na camada que vai escalar — ou está no banco lá embaixo? Configure scale-up agressivo, scale-down conservador com cooldown, e um maxReplicas que protege a fatura. Autoscaling é uma ferramenta excelente para carga variável e uma forma cara de mascarar problemas de arquitetura. Saber a diferença é o trabalho inteiro.

Perguntas frequentes

Devo escalar por CPU ou por latência?

Latência (p95/p99) na grande maioria das web apps, porque elas são I/O-bound e ficam esperando banco e APIs com CPU baixa. CPU só faz sentido em cargas genuinamente CPU-bound, como processamento de imagem ou compressão. Escalar por CPU numa app I/O-bound dispara tarde ou nunca.

Autoscaling resolve uma query lenta?

Não, piora. Mais réplicas significam mais conexões batendo no mesmo banco gargalado, e você escala o problema em vez da solução. Conserte a query, adicione índice ou cache antes de pensar em escalar a aplicação.

Por que minhas réplicas ficam subindo e descendo o tempo todo?

Isso é flapping, causado por cooldowns simétricos ou ausentes. Configure scale-up rápido e scale-down lento, com uma janela de estabilização de vários minutos antes de remover réplicas, para não reagir a cada oscilação momentânea da carga.

Preciso de load balancer para fazer autoscaling?

Sim. Réplicas só recebem tráfego se algo na frente distribuir as requisições entre elas. Sem um load balancer saudável e health checks corretos, subir réplicas não entrega capacidade nenhuma ao usuário.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil