Introdução aos Testes de Performance
Testes de performance são testes não-funcionais que avaliam quão bem um sistema se comporta sob diferentes condições de carga, volume e estresse. São críticos para garantir que aplicações atendam aos requisitos de velocidade, escalabilidade e estabilidade.
Por Que Testes de Performance São Essenciais?
| Impacto | Dados |
|---|---|
| Receita | 1 segundo de delay = 7{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} menos conversões |
| Usuários | 53{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} abandonam site se >3s para carregar |
| Receita Amazon | 1 segundo de delay = $1.6B/ano em vendas |
| 500ms extra = 20{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} menos buscas |
Tipos de Testes de Performance
1. Load Testing (Teste de Carga)
Verifica o comportamento do sistema sob condições de carga esperadas em produção.
Objetivos:
- Medir tempos de resposta
- Verificar throughput máximo
- Identificar bottlenecks
- Validar SLAs
Exemplo de Cenário:
Carga esperada: 1000 usuários simultâneos
Horário de pico: 10:00-12:00 e 14:00-16:00
Transações por hora: 10.000
2. Stress Testing (Teste de Estresse)
Avalia os limites do sistema além da capacidade normal.
Objetivos:
- Identificar ponto de quebra
- Medir degradação graciosa
- Verificar recovery
- Testar failovers
Cenário:
Normal: 1000 usuários
Stress: 2000 → 3000 → 5000 → 8000 → 10000 usuários
Objetivo: Encontrar onde o sistema quebra
3. Spike Testing (Teste de Pico)
Avalia reações a picos súbitos de carga.
Carga normal: 1000 usuários
Pico: 5000 usuários em 5 segundos
Recovery: 1000 usuários
Padrão: On-off-on-off
4. Soak Testing (Teste de Resistência)
Executa carga sustentada por período prolongado.
Problemas Detectados:
- Memory leaks
- Connection pool exhaustion
- Log rotation issues
- Database connection limits
- Disk space issues
Duração: 8-24+ horas contínuas
5. Endurance Testing
Similar ao Soak, mas com foco em validação de SLAs por longo período.
Métricas de Performance
Métricas Principais
| Métrica | Descrição | Target Típico |
|---|---|---|
| Response Time (Avg) | Tempo médio de resposta | <2s para web, <500ms para API |
| Response Time (P95) | 95º percentil | <3s |
| Response Time (P99) | 99º percentil | <5s |
| Throughput | Requisições por segundo | Conforme especificado |
| Error Rate | {6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de requisições com erro | <1{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} |
| CPU Usage | Utilização de CPU | <80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} |
| Memory Usage | Utilização de memória | <85{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} |
| Network I/O | Largura de banda | Dentro de capacidade |
| Disk I/O | Operações de disco | <70{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} capacidade |
Como Medir Percentis
Lista de tempos de resposta (ms):
[120, 150, 180, 200, 220, 250, 280, 300, 350, 400, 500, 600, 800, 1000]
Média: 334ms
Mediana (P50): 275ms
P95: 800ms (5{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} acima = 800ms)
P99: 1000ms (1{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} acima = 1000ms)
Ferramentas de Teste de Performance
1. Apache JMeter
Melhor para: Projetos enterprise, testes complexos
Instalação e Configuração
# Download JMeter
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.6.3.tgz
tar -xzf apache-jmeter-5.6.3.tgz
# Executar (requer Java 8+)
cd apache-jmeter-5.6.3/bin
./jmeter.sh
Exemplo de Plano de Teste (GUI)
Test Plan
├── Thread Group (Users: 100, Ramp-up: 10s, Loop: 10)
│ ├── HTTP Request Defaults (Server: api.exemplo.com)
│ │ └── Path: /api/produtos
│ ├── HTTP Cookie Manager
│ ├── Listeners
│ │ ├── Summary Report
│ │ ├── View Results Tree
│ │ └── Graph Results
Script JMeter (CLI)
API Load Test
100
10
10
api.exemplo.com
GET
/api/produtos
# Executar via CLI
./jmeter.sh -n -t api_test.jmx -l results.jtl -e -o html_report
2. k6 (Grafana k6)
Melhor para: DevOps, scripts em JS, CI/CD integrado
Instalação
# macOS
brew install k6
# Linux
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
Script k6 – Load Test Básico
// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
// Métricas customizadas
const errorRate = new Rate('errors');
const responseTime = new Trend('response_time');
export const options = {
stages: [
{ duration: '2m', target: 100 }, // Ramp-up
{ duration: '5m', target: 100 }, // Steady state
{ duration: '2m', target: 200 }, // Stress
{ duration: '5m', target: 200 }, // Steady state
{ duration: '2m', target: 0 }, // Ramp-down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} das req < 500ms
http_req_failed: ['rate<0.01'], // < 1{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de falhas
errors: ['rate<0.1'], // < 10{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de erros
},
};
const BASE_URL = 'https://api.exemplo.com';
export default function () {
// Login para obter token
const loginRes = http.post(${BASE_URL}/auth/login, {
email: 'usuario@teste.com',
password: 'senha123',
});
check(loginRes, {
'login status 200': (r) => r.status === 200,
'token received': (r) => r.json('token') !== undefined,
});
const token = loginRes.json('token');
// Listar produtos com token
const productsRes = http.get(${BASE_URL}/api/produtos, {
headers: {
'Authorization': Bearer ${token},
},
});
responseTime.add(productsRes.timings.duration);
errorRate.add(productsRes.status !== 200);
check(productsRes, {
'products status 200': (r) => r.status === 200,
'products returned': (r) => r.json('data').length > 0,
});
sleep(1);
}
Script k6 – Spike Test
// spike-test.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
scenarios: {
spike_test: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '10s', target: 100 }, // Normal
{ duration: '30s', target: 1000 }, // SPIKE!
{ duration: '30s', target: 1000 }, // Hold
{ duration: '10s', target: 100 }, // Recovery
{ duration: '10s', target: 0 }, // Cooldown
],
},
},
thresholds: {
http_req_duration: ['p(95)<1000'],
},
};
export default function () {
const res = http.get('https://api.exemplo.com/health');
check(res, { 'status OK': (r) => r.status === 200 });
}
3. Gatling
Melhor para: Scala/Java, relatórios detalhados, CI/CD
Instalação
# Download
wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.10.5/gatling-charts-highcharts-bundle-3.10.5.zip
unzip gatling-charts-highcharts-bundle-3.10.5.zip
Script Gatling (Scala)
// src/test/scala/LoadSimulation.scala
package simulations
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class LoadSimulation extends Simulation {
val baseUrl = "https://api.exemplo.com"
val httpConfig = http
.baseUrl(baseUrl)
.acceptHeader("application/json")
.contentTypeHeader("application/json")
val userFeeder = csv("users.csv").random
val scn = scenario("API Load Test")
.feed(userFeeder)
.exec(
http("Login")
.post("/auth/login")
.body(StringBody("""{"email":"${email}","password":"${password}"}"""))
.check(jsonPath("$.token").saveAs("authToken"))
)
.pause(1)
.exec(
http("Get Products")
.get("/api/produtos")
.header("Authorization", "Bearer ${authToken}")
.check(status.is(200))
)
.pause(1)
.exec(
http("Get Product Details")
.get("/api/produtos/1")
.header("Authorization", "Bearer ${authToken}")
.check(status.is(200))
)
setUp(
scn.inject(
rampUsers(100).during(30.seconds),
constantUsersPerSec(50).during(60.seconds)
)
)
.protocols(httpConfig)
.thresholds(
http_req_duration.p95.lt(500),
http_req_duration.p99.lt(1000)
)
}
4. Locust (Python)
Melhor para: Equipes Python, testes distribuídos
Instalação
pip install locust
Script Locust
# locustfile.py
from locust import HttpUser, task, between, events
import random
class APIClient(HttpUser):
wait_time = between(1, 3)
def on_start(self):
"""Login antes de executar tarefas"""
response = self.client.post("/auth/login", json={
"email": "usuario@teste.com",
"password": "senha123"
})
if response.status_code == 200:
self.token = response.json()["token"]
else:
self.token = None
@task(3)
def list_products(self):
"""Listar produtos (mais frequente)"""
if self.token:
self.client.get(
"/api/produtos",
headers={"Authorization": f"Bearer {self.token}"}
)
@task(2)
def get_product(self):
"""Detalhes de produto"""
product_id = random.randint(1, 100)
if self.token:
self.client.get(
f"/api/produtos/{product_id}",
headers={"Authorization": f"Bearer {self.token}"}
)
@task(1)
def create_order(self):
"""Criar pedido (menos frequente)"""
if self.token:
self.client.post(
"/api/pedidos",
headers={"Authorization": f"Bearer {self.token}"},
json={
"produto_id": random.randint(1, 100),
"quantidade": random.randint(1, 5)
}
)
# Executar
# locust -f locustfile.py --host=https://api.exemplo.com
Cenários de Teste Common
1. E-commerce
| Cenário | Usuários | Duração | Objetivo |
|---|---|---|---|
| Navegação | 500 | 10 min | P95 < 2s |
| Busca | 200 | 5 min | Throughput > 50/s |
| Checkout | 100 | 15 min | P95 < 5s |
| Pico Black Friday | 2000 | 1 min | Sistema estável |
2. API REST
| Endpoint | Load | Stress | Spike |
|---|---|---|---|
| GET /users | 1000 rps | 2000 rps | 5000 rps |
| POST /orders | 500 rps | 1000 rps | 2000 rps |
| GET /products | 2000 rps | 4000 rps | 8000 rps |
3. Aplicação Web
| Página | Target Load | P95 Target |
|---|---|---|
| Home | 1000 concurrent | <3s |
| Search | 500 concurrent | <2s |
| Product Page | 800 concurrent | <2.5s |
| Checkout | 200 concurrent | <5s |
Interpretando Resultados
Identificando Bottlenecks
CPU Bound
Sintomas:- CPU > 90{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
- Throughput não aumenta com mais usuários
- Response time aumenta linearmente
Soluções:- Otimizar algoritmos
- Cachear resultados
- Adicionar índices ao banco
- Load balancing
Memory Bound
Sintomas:- Memory leak crescente
- Garbage collection frequente
- OOM errors
Soluções:- Code review para memory leaks
- Aumentar memória
- Pool de objetos
- Compactação de dados
I/O Bound
Sintomas:- Disk I/O 100{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
- Network saturation
- Queries lentas
Soluções:- Cache de queries
- Compressão de dados
- CDN para estáticos
- Read replicas
Dashboard de Resultados
// Exemplo de parse de resultados JMeter para dashboard
const results = parseJMeterResults('results.jtl');
const summary = {
totalRequests: results.length,
avgResponseTime: results.avg(r => r.elapsed),
p95ResponseTime: results.percentile(95, r => r.elapsed),
p99ResponseTime: results.percentile(99, r => r.elapsed),
errorRate: results.filter(r => r.success === false).length / results.length,
throughput: results.length / (results.max(r => r.timestamp) - results.min(r => r.timestamp)) * 1000,
};
console.log(`
=== Load Test Summary ===
Total Requests: ${summary.totalRequests}
Avg Response: ${summary.avgResponseTime}ms
P95 Response: ${summary.p95ResponseTime}ms
P99 Response: ${summary.p99ResponseTime}ms
Error Rate: ${(summary.errorRate * 100).toFixed(2)}{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
Throughput: ${summary.throughput.toFixed(2)} req/s
`);
Melhores Práticas
Antes do Teste
- Definir objetivos claros – SLAs, thresholds
- Ambiente isolado – Não testar em produção
- Dados准备了 – Massa de dados realista
- Baseline estabelecido – Métricas de referência
- Monitoramento configurado – APM tools
Durante o Teste
- Iniciar gradualmente – Ramp-up suave
- Monitorar em tempo real – Dashboards ativos
- Documentar incidentes – Timestamps e evidências
- Não tocar no ambiente – Interferência mínima
- Capturar métricas – Logs, monitoring, profiling
Após o Teste
- Analisar resultados – Correlacionar métricas
- Identificar bottlenecks – Root cause analysis
- Documentar achados – Relatório técnico
- Recomendar ações – Priorizadas por impacto
- Repetir testes – Validar otimizações
Checklist de Teste de Performance
Preparação
- [ ] Objetivos de teste definidos
- [ ] SLAs documentados
- [ ] Ambiente configurado
- [ ] Dados de teste criados
- [ ] Baselinecapturado
- [ ] Monitoramento configurado
Execução
- [ ] Teste piloto executado
- [ ] Carga gradual aplicada
- [ ] Métricas capturadas
- [ ] Incidentes documentados
- [ ] Logs coletados
Análise
- [ ] Resultados analisados
- [ ] Bottlenecks identificados
- [ ] Recomendações formuladas
- [ ] Relatório preparado
- [ ] Ações priorizadas
Conclusão
Testes de performance são essenciais para garantir que suas aplicações atendam às expectativas dos usuários em termos de velocidade, escalabilidade e estabilidade. A escolha da ferramenta certa depende do contexto do projeto, mas o mais importante é:
- Testar regularmente – Não apenas antes de releases
- Definir SLAs claros – Métricas objetivas
- Analisar resultados – Não apenas coletar
- Otimizar continuamente – Melhoria progressiva
- Automatizar – CI/CD integrado
FAQ
P: Quantos usuários devo simular no load test?
R: Baseie-se em seus picos de uso real + margem de 20-30{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}.
P: Qual é o P95 ideal?
R: Depende do tipo de aplicação. API: <500ms, Web: <3s, Mobile: <2s.
P: Como often devo executar load tests?
R: Mínimo: antes de cada release. Ideal: diária com subset, semanal completa.
P: Load test em produção é uma boa ideia?
R: Somente com feature flags, canary deployments e monitoramento rigoroso.
