Como usar ab e wrk para testes de carga simples em APIs

1. Introdução aos Testes de Carga com Ferramentas de Linha de Comando

Testar a capacidade de uma API antes de colocá-la em produção é uma prática essencial para garantir que o sistema suporte o volume esperado de requisições sem degradar a experiência do usuário. Ferramentas de linha de comando como Apache Bench (ab) e wrk oferecem uma abordagem direta e eficiente para realizar testes de carga sem a complexidade de soluções corporativas.

O Apache Bench, parte do ecossistema Apache HTTP Server, é uma ferramenta madura e amplamente disponível que realiza testes de throughput básicos. Já o wrk, desenvolvido em C com suporte a scripts Lua, oferece maior controle sobre cenários de teste e métricas mais detalhadas, como percentis de latência.

Quando usar cada ferramenta:
- ab: Ideal para testes rápidos de validação, ambientes com restrições de instalação e cenários onde apenas requisições GET simples são necessárias.
- wrk: Recomendado para testes mais realistas, com múltiplas threads, requisições POST com payloads e necessidade de métricas estatísticas avançadas.

Ambas as ferramentas são gratuitas, open-source e funcionam em Linux, macOS e Windows, tornando-as acessíveis para qualquer desenvolvedor.

2. Instalação e Configuração Inicial

Instalando o Apache Bench

Linux (Debian/Ubuntu):

sudo apt update
sudo apt install apache2-utils

macOS (via Homebrew):

brew install apr apr-util
# O ab já vem instalado no macOS, mas pode ser atualizado via Xcode Command Line Tools

Windows:

# Baixe o Apache Lounge: https://www.apachelounge.com/download/
# Extraia e adicione o diretório bin ao PATH do sistema

Instalando o wrk

Linux (Ubuntu/Debian):

sudo apt install build-essential libssl-dev git -y
git clone https://github.com/wg/wrk.git
cd wrk
make
sudo cp wrk /usr/local/bin/

macOS:

brew install wrk

Windows (via Chocolatey):

choco install wrk

Verificando as versões

ab -V
wrk --version

Ambas as ferramentas não exigem dependências complexas além das bibliotecas SSL para suporte HTTPS.

3. Testes Básicos com Apache Bench (ab)

Sintaxe fundamental

ab -n 1000 -c 10 https://api.exemplo.com/v1/usuarios

Onde:
- -n: número total de requisições
- -c: número de requisições concorrentes
- A URL deve terminar com / para endpoints raiz

Interpretando resultados

ab -n 500 -c 20 http://localhost:3000/api/health

Saída típica:

Concurrency Level:      20
Time taken for tests:   2.345 seconds
Complete requests:      500
Failed requests:        0
Requests per second:    213.22 [#/sec] (mean)
Time per request:       93.80 [ms] (mean)
Transfer rate:          45.67 [Kbytes/sec] received

Métricas chave:
- Requests per second: throughput do servidor
- Time per request: latência média por requisição
- Failed requests: indica problemas de conectividade ou timeout

Exemplo com cabeçalhos customizados

ab -n 200 -c 10 -H "Authorization: Bearer token123" \
   -H "Content-Type: application/json" \
   http://localhost:3000/api/protected

4. Aprofundando com wrk: Scripts e Métricas Avançadas

Comando básico

wrk -t4 -c100 -d30s http://localhost:3000/api/health

Onde:
- -t: número de threads
- -c: número de conexões simultâneas
- -d: duração do teste (ex: 30s, 2m)

Criando scripts Lua para simular comportamentos

Arquivo teste-post.lua:

wrk.method = "POST"
wrk.body = '{"email": "teste@exemplo.com", "senha": "123456"}'
wrk.headers["Content-Type"] = "application/json"

Executando:

wrk -t2 -c20 -d15s -s teste-post.lua http://localhost:3000/api/login

Analisando latência e percentis

wrk -t4 -c50 -d30s --latency http://localhost:3000/api/usuarios

Saída com percentis:

Thread Stats   Avg      Stdev     Max   +/- Stdev
  Latency    45.23ms   12.34ms 345.67ms   78.50%
  Req/Sec    1.23k   234.56     2.10k    68.45%
Latency Distribution (HdrHistogram)
 50.000%   42.00ms
 75.000%   51.00ms
 90.000%   63.00ms
 99.000%   98.00ms

Os percentis p50, p90 e p99 são cruciais para entender a experiência real do usuário, especialmente em sistemas com variação de carga.

5. Comparando Resultados e Interpretando Métricas Chave

Diferenças fundamentais

Característica Apache Bench (ab) wrk
Concorrência Baseada em processos Baseada em threads
Suporte a scripts Limitado Completo (Lua)
Percentis de latência Não Sim (HdrHistogram)
Requisições POST Sim, mas limitado Sim, com scripts

Identificando gargalos

  • CPU alto: latência aumenta linearmente com concorrência
  • I/O de rede: throughput estagna mesmo aumentando conexões
  • Banco de dados: erros de timeout ou conexão recusada

Boas práticas para resultados confiáveis

  1. Warm-up: execute 10-20% das requisições antes de medir
  2. Cooldown: aguarde 5-10 segundos entre testes
  3. Múltiplas execuções: repita o teste 3-5 vezes e calcule a média
  4. Ambiente isolado: evite executar outros processos durante o teste
# Exemplo de warm-up com ab
ab -n 100 -c 10 http://localhost:3000/api/health > /dev/null
sleep 2
ab -n 1000 -c 50 http://localhost:3000/api/health

6. Cenários Práticos de Teste em APIs REST

Testando endpoints POST com payload

Arquivo criar-usuario.lua:

wrk.method = "POST"
wrk.body = '{"nome": "João Silva", "email": "joao@exemplo.com"}'
wrk.headers["Content-Type"] = "application/json"
wrk -t2 -c10 -d20s -s criar-usuario.lua http://localhost:3000/api/usuarios

Simulando múltiplos endpoints

Script multiplos-endpoints.lua:

local contador = 0
request = function()
   contador = contador + 1
   if contador % 2 == 0 then
      return wrk.format("GET", "/api/health")
   else
      return wrk.format("POST", "/api/login", 
         {["Content-Type"] = "application/json"},
         '{"usuario":"admin","senha":"123"}')
   end
end
wrk -t4 -c20 -d30s -s multiplos-endpoints.lua http://localhost:3000

Integrando em pipelines CI/CD

Exemplo com GitHub Actions:

name: Teste de Carga
on: [push]
jobs:
  load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Instalar wrk
        run: |
          sudo apt update
          sudo apt install build-essential libssl-dev -y
          git clone https://github.com/wg/wrk.git
          cd wrk && make && sudo cp wrk /usr/local/bin/
      - name: Executar teste
        run: |
          wrk -t2 -c10 -d10s http://${{ secrets.API_URL }}/health

7. Limitações e Alternativas para Testes Mais Complexos

Quando ab e wrk não são suficientes

  • Testes distribuídos: cenários que exigem múltiplas máquinas gerando carga
  • Cenários de usuário complexos: navegação com sessões e cookies
  • Monitoramento em tempo real: dashboards com métricas contínuas

Ferramentas complementares

  • Vegeta: teste de carga com saída formatada em JSON, ideal para automação
  • Hey: similar ao wrk, mas com foco em simplicidade e suporte nativo a HTTP/2
  • k6: ferramenta moderna com scripts em JavaScript e integração com Grafana

Próximos passos

Para testes contínuos em produção, considere:
1. Implementar health checks com métricas exportadas para Prometheus
2. Usar dashboards Grafana para visualizar latência e throughput
3. Configurar alertas automáticos quando p99 ultrapassar thresholds definidos

Referências