Metodologia9 min

Tuning Orientado a Dados: otimização sistemática baseada em evidências

Como usar dados para guiar decisões de otimização, priorizando pelo impacto real e validando cada mudança.

"Vamos aumentar a memória do servidor." Quanto? "O dobro." Por quê? "Parece que vai ajudar." Isso não é tuning — é chute. Tuning orientado a dados significa usar métricas reais para identificar o que ajustar, quanto ajustar, e validar se funcionou.

Cada ajuste deve ter uma hipótese, uma métrica e um resultado esperado.

O Processo de Tuning Científico

O método

1. Observar: Coletar métricas do estado atual
2. Hipótese: Formular o que ajustar e por quê
3. Prever: Estimar o impacto esperado
4. Testar: Aplicar mudança em ambiente controlado
5. Medir: Coletar métricas pós-mudança
6. Validar: Comparar previsão com resultado
7. Documentar: Registrar para referência futura

Por que funciona

Benefícios:
  - Evita mudanças ineficazes
  - Prioriza pelo impacto real
  - Cria conhecimento documentado
  - Permite reversão baseada em dados
  - Comunica valor para stakeholders

Coletando Dados Antes do Tuning

Métricas essenciais

Performance:
  - Latência (p50, p95, p99)
  - Throughput (req/s, tx/s)
  - Error rate

Recursos:
  - CPU utilization
  - Memory usage
  - Disk I/O
  - Network bandwidth

Aplicação:
  - Connection pool usage
  - Thread pool usage
  - Cache hit rate
  - GC time/frequency

Baseline documentado

## Baseline - Sistema XYZ
Data: 2024-01-15
Carga: 500 req/s (steady state)

### Latência
| Endpoint | p50 | p95 | p99 |
|----------|-----|-----|-----|
| /api/orders | 45ms | 120ms | 350ms |
| /api/products | 30ms | 80ms | 200ms |

### Recursos
| Componente | Uso | Limite |
|------------|-----|--------|
| App CPU | 65% | 100% |
| App Memory | 4.2GB | 8GB |
| DB Connections | 45 | 100 |
| Redis Memory | 2.1GB | 4GB |

### Gargalos Identificados
1. /api/orders p99 alto (350ms)
2. DB connections em 45% sob carga normal

Formulando Hipóteses

Template de hipótese

## Hipótese #1

**Observação**:
p99 de /api/orders é 350ms, enquanto p50 é 45ms

**Análise**:
- Trace mostra variância em query de histórico
- Query scan completo quando histórico > 1000 itens

**Hipótese**:
Adicionar índice em orders(user_id, created_at) reduzirá p99

**Previsão**:
- p99 atual: 350ms
- p99 esperado: < 100ms
- Redução: > 70%

**Risco**:
- Índice adiciona ~5% overhead em writes
- Espaço adicional: ~500MB

**Decisão**: Prosseguir (write overhead aceitável)

Priorizando hipóteses

Critérios de priorização:
  Impacto:
    - Quantos usuários afetados?
    - Quanto tempo economizado?
    - Qual valor de negócio?

  Esforço:
    - Quanto tempo para implementar?
    - Qual complexidade?
    - Qual risco?

  Confiança:
    - Quão certa é a hipótese?
    - Temos dados suficientes?

Matriz de decisão:
  Alto impacto + Baixo esforço + Alta confiança → FAZER PRIMEIRO
  Alto impacto + Alto esforço + Alta confiança → PLANEJAR
  Baixo impacto + Qualquer esforço → IGNORAR
  Qualquer + Baixa confiança → INVESTIGAR MAIS

Executando Testes Controlados

Ambiente de teste

Requisitos:
  - Similar a produção (dados, carga)
  - Isolado (sem interferência)
  - Monitorado (todas as métricas)
  - Reproduzível (mesmas condições)

Processo:
  1. Capturar baseline no ambiente de teste
  2. Aplicar mudança única
  3. Executar mesma carga
  4. Coletar métricas
  5. Comparar com baseline

Mudança única por vez

❌ Errado:
  "Vou aumentar memória, threads e timeout de uma vez"
  → Não sabe qual mudança causou o efeito

✅ Correto:
  Teste 1: Aumentar memória → Medir
  Teste 2: Aumentar threads → Medir
  Teste 3: Aumentar timeout → Medir
  → Sabe o impacto de cada mudança

Duração adequada

Tempo mínimo:
  - Smoke test: 5 minutos (validar que funciona)
  - Baseline: 30 minutos (estabilizar)
  - Teste de mudança: 30 minutos (mesmo tempo)

Por quê:
  - JIT precisa aquecer
  - Caches precisam popular
  - Métricas precisam estabilizar
  - Variância precisa ser capturada

Analisando Resultados

Comparação estruturada

## Resultado - Hipótese #1 (Índice em orders)

### Métricas Antes/Depois
| Métrica | Antes | Depois | Δ |
|---------|-------|--------|---|
| p50 | 45ms | 42ms | -7% |
| p95 | 120ms | 65ms | -46% |
| p99 | 350ms | 85ms | -76% ✓ |
| Write latency | 5ms | 5.2ms | +4% |
| DB CPU | 35% | 32% | -9% |

### Validação da Hipótese
- Previsão: p99 < 100ms
- Resultado: p99 = 85ms
- Status: ✅ Confirmada

### Efeitos Colaterais
- Write overhead: +4% (aceitável)
- Espaço em disco: +450MB (aceitável)

### Decisão
Aplicar em produção ✓

Significância estatística

Cuidados:
  - Variância natural existe
  - Amostra pequena pode enganar
  - Compare distribuições, não só médias

Técnicas:
  - Teste t para comparar médias
  - Mann-Whitney para distribuições
  - Bootstrap para intervalos de confiança

Regra prática:
  - Diferença > 10%: provavelmente significativa
  - Diferença < 5%: pode ser ruído
  - Entre 5-10%: precisa mais dados

Tipos Comuns de Tuning

JVM Tuning

Parâmetros comuns:
  Heap size:
    -Xms, -Xmx
    Hipótese: "Aumentar heap reduz GC"
    Métrica: GC time, GC frequency

  GC algorithm:
    -XX:+UseG1GC, -XX:+UseZGC
    Hipótese: "G1 melhor para latência"
    Métrica: p99, GC pause time

  Thread pools:
    -XX:ParallelGCThreads
    Hipótese: "Mais threads GC reduz pause"
    Métrica: GC pause duration

Exemplo de teste:
  Baseline: -Xmx4g -XX:+UseG1GC
  Teste 1: -Xmx8g -XX:+UseG1GC
  Teste 2: -Xmx4g -XX:+UseZGC
  → Comparar p99 e throughput

Database Tuning

PostgreSQL:
  shared_buffers:
    Hipótese: "Mais buffer = menos disk I/O"
    Métrica: buffer hit ratio, disk reads

  work_mem:
    Hipótese: "Mais work_mem = sorts in-memory"
    Métrica: temp file usage, query time

  max_connections:
    Hipótese: "Mais connections = mais concorrência"
    Cuidado: Pode ter efeito inverso!

Exemplo de teste:
  Baseline: shared_buffers = 1GB
  Teste 1: shared_buffers = 2GB
  Teste 2: shared_buffers = 4GB
  → Medir buffer hit ratio e latência

Connection Pool Tuning

Parâmetros:
  Pool size:
    Fórmula: connections = (cores * 2) + disk_spindles
    Hipótese: "Pool muito grande causa contention"

  Timeout:
    Hipótese: "Timeout curto falha rápido"

  Idle timeout:
    Hipótese: "Manter conexões evita overhead"

Métricas:
  - Connection wait time
  - Pool utilization
  - Timeout errors
  - DB connection count

Documentando Tuning

Template de documentação

# Tuning Log - Sistema XYZ

## Entry #1 - 2024-01-15

### Mudança
Parâmetro: PostgreSQL shared_buffers
Valor anterior: 1GB
Valor novo: 4GB

### Motivação
Buffer hit ratio em 85%, objetivo é > 95%

### Teste
- Ambiente: Staging
- Carga: 500 req/s por 1 hora
- Baseline capturado: sim

### Resultados
| Métrica | Antes | Depois |
|---------|-------|--------|
| Buffer hit ratio | 85% | 96% |
| Avg query time | 15ms | 8ms |
| p99 query time | 150ms | 45ms |

### Decisão
Aplicado em produção em 2024-01-16

### Follow-up (1 semana depois)
Resultados mantidos em produção ✓

Biblioteca de tuning

Manter registro de:
  - Mudanças que funcionaram
  - Mudanças que não funcionaram
  - Contexto (versão, carga, hardware)
  - Efeitos colaterais observados

Benefícios:
  - Evita repetir erros
  - Acelera troubleshooting
  - Onboarding de novos membros
  - Base para automação

Anti-Patterns de Tuning

1. Tuning por cargo cult

❌ "Li que 4GB de heap é bom"
   → Aplica sem medir

✅ "Vou testar 2GB, 4GB e 8GB"
   → Mede cada configuração no contexto real

2. Tuning sem baseline

❌ "Aumentei threads e parece mais rápido"
   → Sem dados para comparar

✅ "Baseline: 100ms p95. Após mudança: 60ms p95"
   → Melhoria quantificada

3. Múltiplas mudanças simultâneas

❌ "Mudei heap, threads e timeout. Ficou melhor!"
   → Qual mudança ajudou? Qual pode ter atrapalhado?

✅ Uma mudança por vez
   → Entende o impacto de cada ajuste

4. Ignorar efeitos colaterais

❌ "p99 melhorou 50%!"
   → Mas throughput caiu 30%

✅ Avaliar todas as métricas relevantes
   → Melhoria líquida positiva

Conclusão

Tuning orientado a dados significa:

  1. Medir antes - baseline documentado
  2. Formular hipótese - previsão quantificada
  3. Testar isolado - uma mudança por vez
  4. Validar resultado - comparar com previsão
  5. Documentar - criar conhecimento reutilizável

O resultado: mudanças que comprovadamente melhoram, não chutes que podem piorar.

Tuning sem dados é gambling. Tuning com dados é engenharia.


Este artigo faz parte da série sobre a metodologia OCTOPUS de Performance Engineering.

OCTOPUStuningdadosotimização
Compartilhar:
Read in English

Quer entender os limites da sua plataforma?

Entre em contato para uma avaliação de performance.

Fale Conosco