Metodologia8 min

Identificando Gargalos Reais: onde está o verdadeiro problema

Nem todo código lento é um gargalo. Aprenda a identificar os pontos que realmente impactam a performance do sistema.

"O sistema está lento, deve ser o banco de dados." Quantas vezes você ouviu isso? E quantas vezes estava errado? Encontrar o verdadeiro gargalo é uma das habilidades mais valiosas em performance engineering. Este artigo ensina como fazer isso de forma sistemática.

Um gargalo real é o ponto que limita o throughput de todo o sistema. O resto é ruído.

O Que É um Gargalo

Definição

Gargalo = O componente que, se melhorado,
          aumentaria o throughput total do sistema

O que NÃO é gargalo

❌ Código que parece lento (mas não está no caminho crítico)
❌ Função que consome CPU (mas executa raramente)
❌ Query que demora 500ms (mas roda uma vez por dia)
❌ Serviço com alta latência (mas não é chamado pelos usuários)

Características de um gargalo real

✅ Está no caminho crítico do request
✅ É acessado com frequência significativa
✅ Limita o throughput máximo do sistema
✅ Melhorá-lo melhora a experiência do usuário

A Lei de Amdahl

O conceito

Speedup máximo = 1 / ((1 - P) + P/S)

Onde:
P = Fração do tempo gasto no componente
S = Fator de melhoria aplicado

Exemplo:
Se componente A representa 10% do tempo total,
mesmo melhorando A em 10x, o ganho máximo é ~11%

Implicação prática

Cenário: Request de 1000ms

Componentes:
  - API Gateway: 50ms (5%)
  - Auth: 100ms (10%)
  - Business Logic: 150ms (15%)
  - Database: 600ms (60%)
  - Response: 100ms (10%)

Se otimizar Auth em 50%:
  Economia: 50ms
  Novo total: 950ms
  Melhoria: 5%

Se otimizar Database em 50%:
  Economia: 300ms
  Novo total: 700ms
  Melhoria: 30%

→ Sempre ataque o maior contribuidor primeiro

Metodologia para Identificar Gargalos

Passo 1: Mapear o fluxo completo

Request do usuário
       ↓
┌─────────────────┐
│  Load Balancer  │ → Métricas: latência, conexões
└────────┬────────┘
         ↓
┌─────────────────┐
│   API Gateway   │ → Métricas: rate, errors, duration
└────────┬────────┘
         ↓
┌─────────────────┐
│  Auth Service   │ → Métricas: cache hit, token time
└────────┬────────┘
         ↓
┌─────────────────┐
│ Order Service   │ → Métricas: processing time
├────────┬────────┤
│   ↓    │    ↓   │
│  DB    │  Cache │ → Métricas: query time, hit rate
└────────┴────────┘
         ↓
    Response

Passo 2: Medir cada componente

# Latência por componente
histogram_quantile(0.95,
  sum by(component) (rate(component_duration_seconds_bucket[5m]))
)

# Tempo relativo por componente
sum by(component) (rate(component_duration_seconds_sum[5m]))
/ sum(rate(request_duration_seconds_sum[5m]))

# Chamadas por componente
sum by(component) (rate(component_calls_total[5m]))

Passo 3: Identificar o maior contribuidor

Análise de traces (exemplo):

Request total: 450ms

Breakdown:
  ├─ Gateway: 15ms (3%)
  ├─ Auth: 25ms (6%)
  ├─ Validation: 10ms (2%)
  ├─ DB Query 1: 180ms (40%) ← GARGALO
  ├─ DB Query 2: 120ms (27%) ← SEGUNDO MAIOR
  ├─ External API: 80ms (18%)
  └─ Serialization: 20ms (4%)

Foco: DB Query 1 (40% do tempo)

Passo 4: Validar hipótese

Antes de otimizar, confirme:

1. É consistente?
   → Gargalo aparece em múltiplos traces?

2. É frequente?
   → Quantos requests passam por esse caminho?

3. Impacta o usuário?
   → Está no caminho crítico da jornada?

4. É otimizável?
   → Existe potencial de melhoria realista?

Tipos de Gargalos

1. Gargalo de CPU

Sintomas:
  - CPU em 100%
  - Latência aumenta com carga
  - Throughput estagna em ponto fixo

Causas comuns:
  - Algoritmos ineficientes (O(n²))
  - Serialização/deserialização excessiva
  - Criptografia em CPU
  - Regex complexos

Diagnóstico:
  - CPU profiler (async-profiler, py-spy)
  - top/htop para identificar processo
  - perf para flame graphs

2. Gargalo de I/O

Sintomas:
  - CPU baixa, latência alta
  - Muitas conexões em WAIT
  - iowait alto

Causas comuns:
  - Queries sem índice
  - Disco lento
  - Network latency
  - Connection starvation

Diagnóstico:
  - iostat para disco
  - netstat para conexões
  - Database slow query log

3. Gargalo de memória

Sintomas:
  - OOM events
  - GC frequente
  - Swap usage alto

Causas comuns:
  - Memory leaks
  - Caches unbounded
  - Objetos grandes em memória

Diagnóstico:
  - Heap dumps
  - GC logs
  - Memory profilers

4. Gargalo de concorrência

Sintomas:
  - Baixa utilização de CPU
  - Latência alta sob carga
  - Threads em WAIT

Causas comuns:
  - Locks contentious
  - Connection pool pequeno
  - Thread pool exausto

Diagnóstico:
  - Thread dumps
  - Lock profiler
  - Pool metrics

Ferramentas de Diagnóstico

Para código

Java:
  - async-profiler (CPU, allocation)
  - JFR (Java Flight Recorder)
  - VisualVM

Python:
  - py-spy (CPU profiler)
  - memory_profiler
  - cProfile

Node.js:
  - clinic.js
  - 0x (flame graphs)
  - v8-profiler

Go:
  - pprof
  - trace
  - bench

Para sistema

Linux:
  - perf (CPU profiling)
  - strace (system calls)
  - eBPF/bcc tools
  - sar (histórico)

Containers:
  - cAdvisor
  - Prometheus node_exporter
  - kubectl top

Para database

PostgreSQL:
  - pg_stat_statements
  - EXPLAIN ANALYZE
  - pg_stat_user_tables

MySQL:
  - slow query log
  - EXPLAIN
  - performance_schema

Redis:
  - SLOWLOG
  - INFO stats
  - MEMORY DOCTOR

Exemplo Prático: Investigação Completa

Cenário

Problema: Checkout lento (p95 = 3s, SLO = 1s)

Investigação

## Passo 1: Métricas gerais
- p95 checkout: 3.2s
- Throughput: 50 req/s
- Error rate: 0.5%
- CPU: 35%, Memory: 60%

→ Não é problema de recursos de infra

## Passo 2: Breakdown por serviço
- API Gateway: 100ms (3%)
- Cart Service: 200ms (6%)
- Inventory: 300ms (10%)
- Payment: 2400ms (75%) ← SUSPEITO
- Notification: 200ms (6%)

→ Payment service domina o tempo

## Passo 3: Drill-down no Payment
- Auth: 50ms
- Validation: 100ms
- Stripe API: 2200ms ← GARGALO
- Logging: 50ms

→ Chamada externa para Stripe é o gargalo

## Passo 4: Análise da chamada Stripe
- Timeout configurado: 30s (muito alto)
- Retries: 3 (total wait pode ser 90s)
- p50: 400ms, p99: 8s
- Variância altíssima

→ Stripe tem latência variável, sem circuit breaker

## Passo 5: Validação
- 95% dos checkouts passam por Stripe
- É o caminho crítico (sem pagamento, sem venda)
- Impacta diretamente conversão

## Root cause:
Latência variável da API Stripe + configuração
de timeout/retry inadequada

## Solução:
1. Timeout: 30s → 5s
2. Retry: exponential backoff
3. Circuit breaker: fail fast se Stripe instável
4. Cache: validações de cartão quando possível

Armadilhas Comuns

1. Otimizar o que é fácil, não o que importa

❌ "Vou cachear esse endpoint porque sei fazer"
   → Endpoint representa 0.1% do tráfego

✅ "Vou investigar o que realmente importa"
   → Identificar os 20% que causam 80% do problema

2. Confundir latência com gargalo

❌ "Essa função demora 500ms, é o gargalo"
   → Mas é chamada 1x por hora

✅ "Essa função demora 5ms mas é chamada 10K/s"
   → Representa 50s de CPU por segundo

3. Ignorar efeitos cascata

❌ "O serviço A está lento"
   → Mas A depende de B que depende de C

✅ "A está lento porque C está saturado"
   → Resolver C resolve A

Conclusão

Identificar gargalos reais requer método:

  1. Mapeie o fluxo completo do request
  2. Meça cada componente no caminho crítico
  3. Identifique o maior contribuidor (Lei de Amdahl)
  4. Valide a hipótese antes de otimizar
  5. Ataque o gargalo real, não o percebido

O pior desperdício em performance é otimizar algo que não é gargalo.


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

OCTOPUSgargalosbottleneckdiagnóstico
Compartilhar:
Read in English

Quer entender os limites da sua plataforma?

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

Fale Conosco