M06·07Projeto Guiado

CAPÍTULO 07

Projeto Guiado

API Go com Toxiproxy, k6 load test, pprof profiling, timeout + retry + circuit breaker e Prometheus/Grafana.

Por Thiago Souza15 min de leituraAtualizado em 2026-05

Vamos juntar tudo num projeto pequeno mas realista. Se você seguir, sai com a apostila aplicada.

Cenário

Você tem uma API em Go que expõe GET /products/:id. Ela consulta um banco PostgreSQL e, se não achar, chama uma API externa (api-catalogo.com) que é lenta e instável.

Sua missão:

  1. Subir a API e dependências localmente.
  2. Testar carga e medir latência.
  3. Adicionar timeout, retry e circuit breaker na chamada externa.
  4. Simular falhas (engenharia do caos baby mode).
  5. Comparar antes e depois.

Etapa 1 — Suba o ambiente

Use Docker Compose:

yaml
# docker-compose.yml
version: '3.8'
services:
  api:
    build: .
    ports: ["8080:8080", "6060:6060"] # 6060 é o pprof
    environment:
      EXTERNAL_API: http://toxiproxy:8666
      DB_DSN: postgres://app:app@db:5432/app?sslmode=disable
    depends_on: [db, toxiproxy]
 
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
 
  toxiproxy:
    image: ghcr.io/shopify/toxiproxy
    ports: ["8474:8474", "8666:8666"] # 8474 é a admin API

Toxiproxy é um proxy TCP que injeta caos: latência, timeouts, conexões cortadas. Vai ser nosso macaco do caos no nível pobre.

Etapa 2 — Teste de carga inicial

Use hey (escrito em Go) para o teste de carga:

bash
# Instale: go install github.com/rakyll/hey@latest
 
# warm-up: 30s com 10 workers
hey -z 30s -c 10 http://localhost:8080/products/1
 
# carga sustentada: 2min com 50 workers
hey -z 2m -c 50 http://localhost:8080/products/1
 
# ramp-down: 30s com 10 workers
hey -z 30s -c 10 http://localhost:8080/products/1

Execute cada etapa em sequência.

Anote os números: p50, p95, p99, RPS, taxa de erro. Esse é seu baseline.

Etapa 3 — Profiling

Com o teste rodando, em outro terminal:

bash
go tool pprof -http=:9090 http://localhost:6060/debug/pprof/profile?seconds=30

Abra http://localhost:9090, veja o flame graph, identifique funções lentas. Provavelmente vai ver tempo gasto em I/O da API externa.

Etapa 4 — Aplique os padrões de resiliência

Em pseudo-código Go:

go
// 1. Timeout via context
ctx, cancel := context.WithTimeout(r.Context(), 1500*time.Millisecond)
defer cancel()
 
// 2. Circuit breaker (sony/gobreaker)
result, err := cb.Execute(func() (interface{}, error) {
    // 3. Retry com backoff exponencial
    return doWithRetry(ctx, 3, func() (interface{}, error) {
        return fetchExternal(ctx, id)
    })
})
 
// 4. Fallback: se tudo falhou, retorna do cache local ou um valor mínimo
if err != nil {
    if cached := localCache.Get(id); cached != nil {
        return cached, nil
    }
    return nil, ErrServiceUnavailable
}

Etapa 5 — Engenharia do Caos com Toxiproxy

Crie o "proxy" pra API externa:

bash
curl -X POST http://localhost:8474/proxies -d '{
  "name": "external_api",
  "listen": "0.0.0.0:8666",
  "upstream": "api-catalogo.com:443",
  "enabled": true
}'

Agora injete caos:

bash
# Adiciona 2s de latência em todas as conexões
curl -X POST http://localhost:8474/proxies/external_api/toxics -d '{
  "name": "lag",
  "type": "latency",
  "attributes": {"latency": 2000}
}'
 
# Corta 50% das conexões
curl -X POST http://localhost:8474/proxies/external_api/toxics -d '{
  "name": "drop",
  "type": "limit_data",
  "attributes": {"bytes": 0}
}'

Rode o k6 de novo. Compare:

  • Sem resiliência: sua API trava, p99 explode, taxa de erro vai pras alturas.
  • Com resiliência: circuit breaker abre, requisições falham rápido (fail-fast), p99 fica controlado, fallback responde com cache. Vida que segue.

Etapa 6 — Monitoramento

Adicione o handler /metrics (Prometheus), suba um Grafana, plote:

  • p50/p95/p99 por endpoint.
  • RPS e taxa de erros.
  • Estado do circuit breaker (CLOSED/OPEN/HALF-OPEN).

Configure 1 alerta: "taxa de erros > 5% por 5min".

Parabéns: você implementou os 4 sinais dourados, 3 padrões de resiliência, e fez seu primeiro experimento de caos. Já está acima de 70% dos backends do mercado.