Capacity planning: dimensionando recursos para crescimento

1. Fundamentos do Capacity Planning na Arquitetura de Software

Capacity planning é o processo de determinar a quantidade de recursos computacionais (CPU, memória, armazenamento, rede) necessários para atender à demanda atual e futura de um sistema, evitando tanto o over-provisioning (excesso de capacidade, gerando desperdício financeiro) quanto o under-provisioning (falta de capacidade, causando degradação ou indisponibilidade). Na arquitetura de software, essa prática é essencial para alinhar capacidade com demanda, garantindo que o sistema opere dentro de SLAs aceitáveis.

A diferença entre capacity planning reativo e proativo é crucial. O reativo age somente após a ocorrência de problemas — como picos de latência ou timeout —, enquanto o proativo utiliza modelos preditivos e monitoramento contínuo para antecipar gargalos. Sistemas modernos exigem uma abordagem proativa, integrada a princípios de cost-aware architecture (arquitetura consciente de custos) e chaos engineering, que testa a resiliência do sistema sob condições extremas.

O planejamento de capacidade impacta diretamente três pilares: custos (evitar gastos desnecessários), resiliência (manter disponibilidade sob carga variável) e escalabilidade (crescer sem retrabalho arquitetural). Ignorá-lo leva a decisões como comprar servidores superdimensionados ou, pior, perder receita por quedas em horários de pico.

2. Métricas e Modelagem de Demanda

Para dimensionar corretamente, é preciso identificar métricas-chave:

  • Throughput: requisições por segundo (RPS) ou transações por minuto.
  • Latência: tempo de resposta (p50, p95, p99).
  • Concorrência: número de conexões simultâneas.
  • Uso de recursos: CPU (%), memória (GB), I/O de disco (IOPS) e largura de banda de rede.

A modelagem de demanda combina dados históricos com técnicas estatísticas. Séries temporais capturam padrões sazonais (ex.: Black Friday, horário comercial). Regressão linear projeta crescimento baseado em tendências passadas. Simulações de Monte Carlo consideram variabilidade aleatória, útil para cenários de risco.

Exemplo de coleta de métricas com Prometheus (simplificado):

# Métrica de throughput (requisições por segundo)
rate(http_requests_total[5m])

# Métrica de latência (percentil 99)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

Sazonalidade deve ser tratada: picos previsíveis (ex.: início do mês para sistemas financeiros) e imprevisíveis (ex.: viralização de um produto). Ignorar a sazonalidade leva a subdimensionamento em momentos críticos.

3. Estratégias de Dimensionamento: Vertical vs. Horizontal

Escalonamento vertical (scale-up): adicionar mais recursos a uma única máquina (mais CPU, RAM). É simples de implementar, mas tem limites físicos (hardware máximo disponível) e custos crescentes (servidores de alto desempenho são caros). Além disso, cria um single point of failure — se a máquina falha, todo o sistema cai.

Escalonamento horizontal (scale-out): adicionar mais instâncias de servidores, distribuindo a carga. Oferece elasticidade (pode crescer ou reduzir dinamicamente) e maior tolerância a falhas. Exige stateless design: cada requisição deve ser atendida por qualquer instância, sem depender de estado local. Exemplo de configuração de auto-scaling em Kubernetes:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-deployment
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Os trade-offs incluem maior complexidade operacional (orquestração, balanceamento de carga), latência de rede adicional (comunicação entre instâncias) e desafios de consistência de dados (especialmente em bancos de dados distribuídos). A escolha entre vertical e horizontal depende do perfil da aplicação: sistemas legados ou com estado fortemente acoplado podem preferir scale-up; sistemas cloud-native e microsserviços favorecem scale-out.

4. Ferramentas e Técnicas de Previsão de Capacidade

A teoria de filas (queueing theory) fornece modelos matemáticos para prever o comportamento do sistema sob carga. A Lei de Little relaciona o número médio de requisições no sistema (L), a taxa de chegada (λ) e o tempo médio de resposta (W): L = λ × W. Se o tempo de resposta aumenta, o número de requisições em fila cresce proporcionalmente. A utilização de recursos (U = λ / μ, onde μ é a capacidade de serviço) indica o quão próximo o sistema está do gargalo.

Ferramentas de monitoramento como Prometheus (coleta de métricas), Grafana (visualização) e JMeter (testes de carga) são essenciais. Para previsão avançada, modelos de machine learning como ARIMA (AutoRegressive Integrated Moving Average) ou Prophet (do Facebook) analisam séries temporais e projetam demanda futura.

Exemplo de previsão com Prophet (pseudo-código):

from prophet import Prophet
model = Prophet()
model.fit(historical_data)
future = model.make_future_dataframe(periods=30)
forecast = model.predict(future)

Essas previsões alimentam decisões de provisionamento, como aumentar réplicas antes de campanhas de marketing.

5. Planejamento para Crescimento em Ambientes Cloud-Nativos

Em nuvem, o auto-scaling é a principal ferramenta. Pode ser baseado em métricas (CPU, memória, fila de mensagens) ou em schedules (horários conhecidos de pico). É importante definir capacity buffers — capacidade extra para absorver picos sem degradação —, mas controlados para não gerar custos desnecessários.

Zonas de disponibilidade (AZs) e regiões múltiplas aumentam a resiliência, mas exigem replicação de dados e balanceamento de carga global. O custo deve ser gerenciado com reserved instances (para carga base), spot instances (para carga elástica e tolerante a falhas) e savings plans.

Exemplo de política de auto-scaling baseada em métrica customizada (fila SQS):

# Métrica: tamanho da fila de mensagens
aws autoscaling put-scaling-policy \
  --policy-name sqs-policy \
  --auto-scaling-group-name my-asg \
  --scaling-adjustment 2 \
  --adjustment-type ChangeInCapacity \
  --cooldown 300

Uma abordagem cost-aware dimensiona recursos para o cenário médio, com margem para picos, em vez de provisionar para o pico máximo — reduzindo custos sem sacrificar disponibilidade.

6. Testes de Capacidade e Validação Contínua

Testes de capacidade validam se o sistema suporta a carga projetada:

  • Load testing: simula carga esperada (ex.: 1000 RPS) e mede métricas.
  • Stress testing: aplica carga além do limite para identificar ponto de ruptura.
  • Endurance testing: mantém carga constante por horas/dias para detectar vazamentos de memória ou degradação.

Cenários realistas devem considerar padrões de uso reais (ex.: pico de login às 9h). Ferramentas como k6 ou Locust permitem scripts customizados.

Canary releases e gradual ramp-up (aumento progressivo de tráfego) validam a capacidade em produção sem risco total. Chaos engineering introduz falhas controladas (ex.: derrubar uma instância) para testar se o sistema redistribui a carga adequadamente.

Exemplo de teste de carga com k6:

import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  http.get('https://api.exemplo.com/endpoint');
  sleep(1);
}

export let options = {
  stages: [
    { duration: '2m', target: 100 },   // ramp-up
    { duration: '5m', target: 100 },   // steady state
    { duration: '2m', target: 0 },     // ramp-down
  ],
};

7. Documentação, Revisão e Governança do Plano de Capacidade

Um capacity plan documentado deve conter:

  • Baseline: métricas atuais (uso de CPU, throughput, latência).
  • Projeções: crescimento esperado (ex.: +20% de usuários em 6 meses).
  • Ações de contingência: gatilhos para escalar, contatos de suporte, procedimentos de rollback.

Revisões periódicas (trimestrais ou semestrais) ajustam o plano com base em mudanças de negócio (novos produtos, aquisições) e tecnologia (migração para nuvem, novas versões de software). A governança envolve arquitetos (definem estratégia), operações (implementam e monitoram) e financeiro (aprovam orçamento). Sem essa colaboração, o planejamento se torna reativo e ineficaz.

O objetivo final é que o capacity planning seja um processo contínuo, não um evento único — integrado ao ciclo de vida do software, desde o design até a operação.

Referências