# Testes de Performance: Guia Completo de Load Testing e Stress Testing

**Meta Description:** Domine testes de performance: load testing, stress testing, spike testing e soak testing. Aprenda a usar JMeter, k6, Gatling e interprete resultados para otimizar seus sistemas.

---

## 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% menos conversões |
| **Usuários** | 53% abandonam site se >3s para carregar |
| **Receita Amazon** | 1 segundo de delay = $1.6B/ano em vendas |
| **Google** | 500ms extra = 20% 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** | % de requisições com erro | <1% |
| **CPU Usage** | Utilização de CPU | <80% |
| **Memory Usage** | Utilização de memória | <85% |
| **Network I/O** | Largura de banda | Dentro de capacidade |
| **Disk I/O** | Operações de disco | <70% 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% acima = 800ms)
P99: 1000ms (1% acima = 1000ms)
```

---

## Ferramentas de Teste de Performance

### 1. Apache JMeter

**Melhor para:** Projetos enterprise, testes complexos

#### Instalação e Configuração

```bash
# 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)

```xml
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2">
  <hashTree>
    <TestPlan>
      <stringProp name="TestPlan.name">API Load Test</stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup>
        <stringProp name="ThreadGroup.num_threads">100</stringProp>
        <stringProp name="ThreadGroup.ramp_time">10</stringProp>
        <stringProp name="ThreadGroup.loop_count">10</stringProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy>
          <stringProp name="HTTPSampler.domain">api.exemplo.com</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <stringProp name="HTTPSampler.path">/api/produtos</stringProp>
        </HTTPSamplerProxy>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>
```

```bash
# 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

```bash
# 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

```javascript
// 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% das req < 500ms
    http_req_failed: ['rate<0.01'],     // < 1% de falhas
    errors: ['rate<0.1'],               // < 10% 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

```javascript
// 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

```bash
# 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)

```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

```bash
pip install locust
```

#### Script Locust

```python
# 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%
- 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%
- Network saturation
- Queries lentas

Soluções:
- Cache de queries
- Compressão de dados
- CDN para estáticos
- Read replicas
```

### Dashboard de Resultados

```javascript
// 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)}%
Throughput: ${summary.throughput.toFixed(2)} req/s
`);
```

---

## Melhores Práticas

### Antes do Teste

1. **Definir objetivos claros** - SLAs, thresholds
2. **Ambiente isolado** - Não testar em produção
3. **Dados准备了** - Massa de dados realista
4. **Baseline estabelecido** - Métricas de referência
5. **Monitoramento configurado** - APM tools

### Durante o Teste

1. **Iniciar gradualmente** - Ramp-up suave
2. **Monitorar em tempo real** - Dashboards ativos
3. **Documentar incidentes** - Timestamps e evidências
4. **Não tocar no ambiente** - Interferência mínima
5. **Capturar métricas** - Logs, monitoring, profiling

### Após o Teste

1. **Analisar resultados** - Correlacionar métricas
2. **Identificar bottlenecks** - Root cause analysis
3. **Documentar achados** - Relatório técnico
4. **Recomendar ações** - Priorizadas por impacto
5. **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 é:

1. **Testar regularmente** - Não apenas antes de releases
2. **Definir SLAs claros** - Métricas objetivas
3. **Analisar resultados** - Não apenas coletar
4. **Otimizar continuamente** - Melhoria progressiva
5. **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%.

**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.
