M06·03Ferramentas

CAPÍTULO 03

Ferramentas

Load testing com k6, profiling com pprof, flame graphs e benchmarks em Go — mãos à obra.

Por Thiago Souza12 min de leituraAtualizado em 2026-05

Vamos sair da teoria e pegar martelo.

Load Testing (Teste de Carga)

Load testing é "vamos ver até onde o sistema aguenta antes de quebrar". Existem três variantes que você precisa conhecer:

TipoObjetivoExemplo
Load testValidar comportamento sob carga esperada"Aguentamos 1.000 RPS na Black Friday?"
Stress testAchar o limite do sistema"Em quantos RPS ele cai?"
Soak test (endurance)Rodar por horas pra detectar memory leaks, conexões vazando, etc."Roda 12h em 80% de carga e vê o que acontece"
Spike testSubir carga bruscamente pra ver se aguenta picos"Vai de 100 pra 5.000 RPS em 10 segundos"

As ferramentas que valem a pena aprender

  • vegeta: em Go, CLI + biblioteca nativa, métricas detalhadas (p95, p99, histograma). Recomendação para projetos Go.
  • hey: linha de comando em Go, zero configuração, ideal pra testes rápidos de baseline.
  • wrk / wrk2: C, extremamente rápidas, ótimas pra testes de throughput puro.
  • k6 (Grafana): usa JavaScript como DSL de testes, leve, boa integração com CI/CD.
  • Locust: em Python, ótima pra cenários com lógica de negócio complexa.
  • JMeter: veterano em Java, GUI pesada mas extremamente completo.

Exemplo prático com vegeta

go
// load-test.go — usando github.com/tsenart/vegeta/v12
package main
 
import (
    "fmt"
    "time"
 
    vegeta "github.com/tsenart/vegeta/v12/lib"
)
 
func main() {
    rate     := vegeta.Rate{Freq: 200, Per: time.Second} // 200 req/s
    duration := 2 * time.Minute
    targeter := vegeta.NewStaticTargeter(vegeta.Target{
        Method: "GET",
        URL:    "https://api.minha-empresa.com/users/42",
    })
    attacker := vegeta.NewAttacker()
 
    var metrics vegeta.Metrics
    for res := range attacker.Attack(targeter, rate, duration, "load-test") {
        metrics.Add(res)
    }
    metrics.Close()
 
    fmt.Printf("p95:   %s\n",     metrics.Latencies.P95)
    fmt.Printf("p99:   %s\n",     metrics.Latencies.P99)
    fmt.Printf("RPS:   %.2f\n",   metrics.Rate)
    fmt.Printf("erros: %.2f%%\n", (1-metrics.Success)*100)
}

Roda com go run load-test.go e entrega p95, p99, RPS e taxa de erro. Sem escrever código, o CLI resolve: vegeta attack -rate=200 -duration=2m -targets=targets.txt | vegeta report.

Dica de ouro: nunca rode load test direto em produção sem combinar com a equipe. E sempre rode contra um ambiente parecido com produção — testar contra localhost mente descaradamente.

Profiling em Go

Profiling é colocar o sistema na mesa de cirurgia: você descobre exatamente qual função está consumindo CPU, qual alocando memória, qual segurando lock. Em Go, isso é maravilhosamente integrado via o pacote pprof.

Habilitando o pprof na sua aplicação

go
package main
 
import (
    "log"
    "net/http"
    _ "net/http/pprof" // ← este import já registra os handlers em /debug/pprof
)
 
func main() {
    // server de profiling separado, em outra porta (não exponha em produção pública)
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()
 
    // ... resto da sua app
}

Pronto. Sua app agora expõe perfis em http://localhost:6060/debug/pprof/.

Os perfis principais

PerfilO que mostraQuando usar
profileCPU samples (default 30s)"Tá lento, onde a CPU tá indo?"
heapAlocações de memória vivas"Memória só sobe, tem leak?"
allocsTodas as alocações (vivas + mortas)"Onde gera lixo demais pro GC?"
goroutineSnapshot de todas as goroutines"Travou? Goroutines vazando?"
blockOnde goroutines bloqueiam"Throughput baixo, contenção em locks?"
mutexContenção de mutex"Mutex segurando demais?"

Coletando e analisando

bash
# coleta 30s de CPU profile e abre análise interativa
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
 
# coleta heap (memória atual)
go tool pprof http://localhost:6060/debug/pprof/heap
 
# UI web (muito mais legível que terminal)
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30

Dentro do pprof:

(pprof) top10          # 10 funções que mais consomem
(pprof) list MyFunc    # vê o código anotado linha a linha com tempo gasto
(pprof) web            # abre gráfico em SVG no browser

Flame graphs

A UI web (-http=:8080) traz o famoso flame graph: cada bloco horizontal é uma função, e a largura é proporcional ao tempo gasto. Você "voa" pelo stack e vê instantaneamente onde está o gargalo.

Benchmarks no Go

Antes de profiling em produção, escreva benchmarks:

go
// benchmark_test.go
func BenchmarkParseJSON(b *testing.B) {
    data := []byte(`{"id":1,"name":"Claude"}`)
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        var u User
        json.Unmarshal(data, &u)
    }
}

Roda com:

bash
go test -bench=. -benchmem -cpuprofile=cpu.out -memprofile=mem.out
go tool pprof -http=:8080 cpu.out
Cuidado: habilitar block e mutex profiling tem overhead. Em produção, ative só durante a investigação ou use sampling baixo.