Load testing valida se o sistema aguenta a carga esperada. Stress testing descobre onde ele quebra. São objetivos diferentes, técnicas diferentes, e insights diferentes. Este artigo explica quando e como estressar seu sistema de forma controlada.
Load testing pergunta "aguenta?". Stress testing pergunta "até onde aguenta?".
A Diferença Entre Load e Stress
Load Testing
Objetivo: Validar comportamento sob carga esperada
Carga: Normal a pico previsto
Duração: Horas (estado estável)
Resultado: Pass/Fail nos SLOs
Exemplo:
- Carga: 1000 req/s (pico esperado)
- Duração: 2 horas
- Critério: p95 < 500ms, error rate < 1%
Stress Testing
Objetivo: Encontrar limites e pontos de falha
Carga: Acima do esperado, crescente
Duração: Até degradação ou falha
Resultado: Capacidade máxima, modo de falha
Exemplo:
- Carga: 1000 → 2000 → 3000 → ... req/s
- Duração: Até primeiro gargalo
- Resultado: "Sistema aguenta 2500 req/s,
falha por connection pool em 2800"
Por Que Fazer Stress Testing
1. Conhecer a capacidade real
Sem stress test:
"Achamos que aguenta 1000 users"
Com stress test:
"Validamos que aguenta 3200 users,
gargalo é DB connections,
comportamento em overload: graceful degradation"
2. Entender o modo de falha
Perguntas que stress test responde:
- O que falha primeiro?
- Falha gradualmente ou catastroficamente?
- Recupera automaticamente?
- Quanto tempo para recuperar?
3. Validar mecanismos de proteção
Testa se funcionam:
- Rate limiting
- Circuit breakers
- Autoscaling
- Graceful degradation
- Queue backpressure
4. Preparar para o inesperado
Eventos que excedem previsão:
- Campanha viral inesperada
- Menção em TV/mídia
- Bot flood (acidental ou intencional)
- Recuperação de outage (thundering herd)
Tipos de Stress Test
1. Step-Up Stress
Perfil:
┌─────────────────────────────────┐
│ Carga │
│ ▲ ┌───┐ │
│ │ ┌─────┘ │ │
│ │ ┌─────┘ │ │
│ │ ┌─────┘ │ │
│ └─┴─────────────────────┴──▶ │
│ Tempo│
└─────────────────────────────────┘
Implementação (k6):
stages: [
{ duration: '10m', target: 1000 }, // Step 1
{ duration: '10m', target: 2000 }, // Step 2
{ duration: '10m', target: 3000 }, // Step 3
{ duration: '10m', target: 4000 }, // Step 4
]
Uso: Encontrar ponto de degradação gradualmente
2. Spike Test
Perfil:
┌─────────────────────────────────┐
│ Carga │
│ ▲ ┌───┐ │
│ │ │ │ │
│ │ │ │ │
│ │ ───────┘ └─────────── │
│ └────────────────────────▶ │
│ Tempo│
└─────────────────────────────────┘
Implementação (k6):
stages: [
{ duration: '5m', target: 500 }, // Normal
{ duration: '1m', target: 5000 }, // Spike
{ duration: '5m', target: 5000 }, // Sustain
{ duration: '1m', target: 500 }, // Drop
{ duration: '10m', target: 500 }, // Recovery
]
Uso: Validar resposta a pico súbito e recuperação
3. Sustained Overload
Perfil:
┌─────────────────────────────────┐
│ Carga │
│ ▲ │
│ │ ┌─────────────────────┐ │
│ │ │ │ │
│ │ │ Acima da capacidade│ │
│ └─┴─────────────────────┴──▶ │
│ Tempo│
└─────────────────────────────────┘
Implementação:
stages: [
{ duration: '5m', target: 3000 }, // Ramp
{ duration: '60m', target: 3000 }, // Sustain overload
]
Uso: Observar degradação prolongada, memory leaks
4. Breaking Point (Destructive)
Perfil:
┌─────────────────────────────────┐
│ Carga │
│ ▲ ╱ │
│ │ ╱ │
│ │ ╱ │
│ │ ╱ │
│ └──────────────╱───────────▶ │
│ Tempo│
└─────────────────────────────────┘
Implementação:
stages: [
{ duration: '60m', target: 10000 }, // Ramp contínuo
]
Uso: Encontrar limite absoluto (até OOM, timeout, crash)
Métricas Durante Stress Test
O que observar
Performance:
- Latência (p50, p95, p99)
- Throughput efetivo
- Error rate
- Timeout rate
Recursos:
- CPU (all pods/instances)
- Memory (e GC se aplicável)
- Conexões (DB, cache, external)
- I/O (disk, network)
Aplicação:
- Queue depths
- Thread pool usage
- Connection pool usage
- Active requests
Sistema:
- Pod/instance health
- Autoscaling events
- Circuit breaker states
Identificando o gargalo
Sintomas por tipo de gargalo:
CPU-bound:
- CPU em 100%
- Latência sobe linearmente
- Throughput estagna
Memory-bound:
- Memory crescendo
- GC frequente/longo
- OOM eventual
Connection-bound:
- Pool em 100%
- Timeouts aumentando
- Requests enfileirados
I/O-bound:
- CPU baixa
- Disk IOPS alto
- Network saturada
Executando Stress Test
Preparação
Checklist:
- [ ] Ambiente isolado (não afeta produção)
- [ ] Monitoramento completo ativo
- [ ] Alertas de produção silenciados
- [ ] Equipe ciente (SRE, infra)
- [ ] Rollback plan (se em staging compartilhado)
- [ ] Critérios de parada definidos
Durante o teste
Monitorar em tempo real:
- Dashboard de métricas
- Logs de erro
- Estado dos pods
- Autoscaling
Documentar:
- Timestamps de eventos
- Primeiro sinal de degradação
- Comportamento sob stress
- Erros observados
Critérios de parada
Parar quando:
- Error rate > 50%
- Latência > 30s
- OOM detectado
- Componente crítico down
- Dados corrompidos
Não parar apenas por:
- Degradação gradual
- Error rate moderado
- Latência alta mas responsivo
Interpretando Resultados
Curva de saturação
┌─────────────────────────────────┐
│ │
Latência │ ╱╱╱╱╱ │
ou │ ╱╱ │
Error % │ ╱ │
│ ╱ │
│ ────╱ "Knee" (ponto de │
│ inflexão) │
└─────────────────────────────────┘
Throughput →
Zona verde: Performance estável
Knee: Início de saturação
Zona vermelha: Degradação rápida
Documentando resultados
## Stress Test Report - 2024-01-20
### Configuração
- Ambiente: Staging (3x prod)
- Baseline: 1000 req/s
- Teste: Step-up até falha
### Resultados
| Carga | p95 | Error % | Observação |
|-------|-----|---------|------------|
| 1000 | 120ms | 0.1% | Normal |
| 1500 | 150ms | 0.2% | OK |
| 2000 | 200ms | 0.5% | OK |
| 2500 | 350ms | 1.2% | Início degradação |
| 3000 | 800ms | 5% | Degradação visível |
| 3500 | 2s | 15% | Severo |
| 4000 | Timeout | 40% | Falha |
### Análise
- Capacidade máxima sustentável: 2000 req/s
- Knee point: 2500 req/s
- Gargalo primário: DB connection pool
- Modo de falha: Graceful degradation até 3500,
depois cascata de timeouts
### Recomendações
1. Aumentar connection pool de 50 para 100
2. Implementar circuit breaker para DB
3. Considerar read replica para queries de leitura
4. Reteste após ajustes
Stress Testing em CI/CD
Quando incluir
Não em todo PR:
- Muito lento
- Recursos caros
Incluir em:
- Releases para produção
- Mudanças de infra
- Novos endpoints críticos
- Alterações em connection handling
Nightly:
- Stress test completo
- Relatório para review matinal
Automação
# Exemplo de pipeline
stress_test:
stage: test
only:
- main
- /^release-.*/
script:
- k6 run stress-test.js
- python analyze_results.py
artifacts:
paths:
- stress-report.html
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
Conclusão
Stress testing é essencial para:
- Conhecer limites - não adivinhar, saber
- Entender falhas - como, onde, quando
- Validar proteções - circuit breakers funcionam?
- Preparar incidentes - saber o que esperar
A diferença entre um sistema resiliente e um frágil é saber onde estão os limites antes de encontrá-los em produção.
Todo sistema quebra sob pressão suficiente. A questão é: você sabe onde e como?
Este artigo faz parte da série sobre a metodologia OCTOPUS de Performance Engineering.