Você implantou um endpoint. Ele retorna o JSON correto no Postman. Mas você não tem ideia do que acontece quando 200 clientes o acessam de uma vez. Ele aguenta 500 requisições por segundo, ou a latência desmorona em 50? ApacheBench responde a essa pergunta em um único comando.
ApacheBench, invocado como ab, é uma ferramenta de linha de comando que dispara um número fixo de requisições HTTP para uma única URL e relata a vazão e a latência. Ele vem com o Apache HTTP Server e existe há décadas. É pequeno, rápido de executar e oferece uma leitura rápida de quanta carga um endpoint pode suportar.
Este guia aborda a instalação do ab, a execução de um teste básico, o teste de endpoints POST, a leitura da saída e o conhecimento de onde o ab deixa de ser a ferramenta certa. Cada comando aqui corresponde a uma flag documentada na referência oficial do Apache ab.
O que é ApacheBench e de onde ele vem
ab é um cliente de benchmarking empacotado com o Apache HTTP Server. O nome é uma abreviação de ApacheBench. Ele abre conexões para uma URL, envia requisições tão rápido quanto sua configuração de concorrência permite, cronometra cada resposta e imprime um resumo.

Ele mede uma coisa bem: quantas requisições por segundo um único endpoint pode servir e como o tempo de resposta é distribuído sob carga. Isso é vazão e latência para uma URL.
O que ele não faz é tão importante quanto. ab não verifica se o corpo da resposta está correto. Não valida um esquema nem verifica um campo. Não percorre um fluxo multi-etapas como login, depois buscar, depois atualizar. Ele atinge uma URL e conta. Mantenha esse escopo em mente e ab continuará útil. Espere mais e você ficará desapontado.
Se você quiser uma visão mais ampla da disciplina em que ab se encaixa, veja o que é teste de carga de API e por que o tempo de resposta da API é importante.
Instalando ab
ab vem empacotado com as utilidades do Apache. O nome do pacote difere por plataforma.
No Debian e Ubuntu, instale o pacote apache2-utils:
sudo apt-get update
sudo apt-get install -y apache2-utils
No CentOS, RHEL e Fedora, o pacote é httpd-tools:
# CentOS 7
sudo yum install -y httpd-tools
# Fedora e CentOS 8+
sudo dnf install -y httpd-tools
No macOS, ab já está presente porque o sistema vem com Apache. Verifique-o:
ab -V
Você deverá ver uma linha de versão como Version 2.3. Se o comando estiver ausente no macOS, instale-o através da fórmula Apache do Homebrew. Uma vez que ab -V imprimir uma versão, você estará pronto.
Executando um teste de carga básico
As duas flags que você usará sempre são -n e -c.
-n requestsdefine o número total de requisições a serem realizadas. O padrão é uma única requisição, o que não diz nada, então sempre defina este valor.-c concurrencydefine quantas requisições são executadas por vez. O padrão é uma, significando totalmente serial.
Aqui estão 1000 requisições, 50 por vez, contra um endpoint JSON:
ab -n 1000 -c 50 https://api.example.com/v1/users
Observe o caminho final. ab precisa de uma URL completa com um caminho. Se você apontá-lo para um host nu sem caminho, ele dará erro. Para a raiz, use uma barra final: https://api.example.com/.
Clientes reais reutilizam conexões TCP em vez de abrir uma nova a cada requisição. Adicione -k para habilitar o HTTP KeepAlive para que ab reutilize conexões dentro de uma sessão:
ab -n 1000 -c 50 -k https://api.example.com/v1/users
A execução com -k geralmente se aproxima mais de como um navegador ou um cliente de API bem comportado age, pois evita pagar o custo de configuração de conexão a cada requisição. Compare os dois números para ver quanto da sua latência é sobrecarga de conexão.
Você também pode limitar a execução por tempo em vez de contagem. -t define um número máximo de segundos e implica -n 50000 internamente, então o teste para no limite que for atingido primeiro:
ab -t 30 -c 50 -k https://api.example.com/v1/users
Isso é executado por até 30 segundos com concorrência 50. Útil quando você quer uma leitura de duração fixa em vez de uma contagem fixa.
Testando um endpoint POST
A maioria do trabalho de API não é GET. Para testar um POST, coloque o corpo da requisição em um arquivo e passe-o com -p. Você também precisa definir o tipo de conteúdo com -T, ou o servidor rejeitará o corpo.
Crie o payload:
cat > payload.json <<'EOF'
{"name": "Ada Lovelace", "email": "ada@example.com"}
EOF
Então envie-o:
ab -n 500 -c 25 -k \
-p payload.json \
-T application/json \
https://api.example.com/v1/users
A flag -p nomeia o arquivo que contém o corpo do POST. A flag -T define o cabeçalho Content-Type. O tipo de conteúdo padrão é text/plain, que quase nunca é o que uma API JSON deseja, então defina -T application/json explicitamente.
Se seu endpoint precisar de autenticação ou outros cabeçalhos, adicione-os com -H. Repita a flag para cada cabeçalho:
ab -n 500 -c 25 -k \
-p payload.json \
-T application/json \
-H "Authorization: Bearer SEU_TOKEN" \
https://api.example.com/v1/users
Para uma revisão sobre como construir corpos de requisição JSON manualmente, veja como POSTar dados JSON com curl. O mesmo corpo funciona como um arquivo de payload ab.
Lendo a saída
Uma execução imprime um bloco de números. Aqui está um exemplo truncado:
Concurrency Level: 50
Time taken for tests: 4.212 seconds
Complete requests: 1000
Failed requests: 0
Non-2xx responses: 0
Requests per second: 237.42 [#/sec] (mean)
Time per request: 210.598 [ms] (mean)
Time per request: 4.212 [ms] (mean, across all concurrent requests)
Transfer rate: 142.31 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 5 18 9.4 16 64
Processing: 22 189 41.2 182 310
Waiting: 21 177 39.8 171 295
Total: 31 207 42.7 201 338
Percentage of the requests served within a certain time (ms)
50% 201
66% 221
75% 236
90% 268
95% 291
99% 324
100% 338 (longest request)
Leia esses campos primeiro:
- Requests per second (Requisições por segundo) é seu número principal de vazão. É a contagem de requisições dividida pelo tempo total. Quanto maior, melhor.
- Failed requests (Requisições falhas) e Non-2xx responses (Respostas não 2xx) informam se o servidor realmente lidou com a carga ou começou a gerar erros. Um alto número de requisições por segundo não significa nada se metade das respostas forem 500s. Sempre verifique estes dois antes de confiar na figura de vazão.
- Time per request (Tempo por requisição) aparece duas vezes. A primeira linha é o tempo médio que um único usuário espera (concorrência vezes tempo total dividido por requisições). A segunda linha, rotulada "across all concurrent requests" (em todas as requisições concorrentes), é o intervalo médio entre as requisições concluídas. O primeiro número é o que os usuários sentem.
A tabela Percentage of the requests served within a certain time (ms) (Porcentagem das requisições servidas dentro de um certo tempo (ms)) é a parte mais útil. É uma quebra por percentil. A linha de 50% é sua mediana. As linhas de 95% e 99% mostram a cauda lenta. No exemplo, metade das requisições terminou em 201ms, mas 1% levou 324ms ou mais. A latência de cauda é onde os usuários reais são prejudicados, então observe os percentis 95 e 99 mais do que a média.
Quer os números brutos por requisição para um gráfico? Adicione -e results.csv para gravar um CSV de pares percentil-tempo, ou -g results.tsv para um arquivo amigável ao gnuplot.
Onde ab deixa de ser a ferramenta certa
ab é deliberadamente restrito. Seus limites merecem ser declarados claramente para que você não o utilize de forma inadequada.
Uma URL por execução. ab martela um único endpoint. Ele não consegue roteirizar uma sequência como autenticar, criar um recurso e depois lê-lo. Jornadas de usuários reais tocam muitos endpoints em ordem, e ab não tem conceito disso.
Sem verificações de correção. ab conta códigos de status e comprimentos de bytes. Ele não analisa seu JSON nem afirma que um campo é igual a um valor esperado. Uma resposta pode estar estruturalmente errada e ainda ser contada como sucesso. Números de carga não substituem uma suíte de testes aprovada.
Tratamento HTTP desatualizado. A documentação oficial afirma que ab não implementa HTTP/1.x completamente e aceita apenas algumas formas esperadas de respostas. Ele não tem suporte a HTTP/2. Para servidores que se comportam de forma diferente sob HTTP/2, ab não refletirá isso.
Carga de máquina única. ab é executado de uma única máquina e um único processo. A partir de uma certa concorrência, você mede os limites do seu próprio cliente em vez dos do servidor. A documentação até avisa que a própria análise do ab pode aparecer como um gargalo em perfis.
Nada disso torna o ab ruim. Isso o torna uma ferramenta específica: uma sonda de vazão rápida para um único endpoint. Quando você precisar de fluxos roteirizados, carga distribuída ou HTTP/2, procure algo feito para isso. JMeter lida com cenários multi-etapas e execuções distribuídas, e há um apanhado mais amplo de ferramentas de teste de carga se você estiver comparando opções.
Onde o teste funcional se encaixa
Vazão é um eixo. Correção é outro, e ab não o toca. Antes de testar a carga de um endpoint, você precisa saber se ele retorna os dados corretos com a forma correta em condições normais. Isso é teste funcional e de contrato, e é um trabalho diferente.
É aqui que uma plataforma de API completa ganha seu lugar ao lado do ab. O Apidog permite que você construa cenários de teste com asserções visuais, encadeie requisições em fluxos multi-etapas e valide respostas contra seu esquema, coisas que o ab não pode fazer por design. Você salva esses cenários uma vez e os executa em qualquer lugar.
Para integração contínua, a CLI do Apidog executa seus cenários salvos sem interface gráfica. Instale-o com Node:
npm install -g apidog-cli
Em seguida, execute um cenário ou suíte salva contra um ambiente escolhido, emitindo relatórios que sua CI pode arquivar:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
A flag -t direciona um cenário, pasta ou suíte salvo pelo ID. A flag -e seleciona o ambiente. A flag -r escolhe um ou mais relatores entre cli, html, json e junit. Para execuções orientadas por dados, adicione -d (ou --iteration-data) com um caminho de arquivo de dados ou ID de dados de teste. A CLI é headless e executa cenários salvos, então ela se encaixa em qualquer etapa de CI que possa executar Node. Não é um remetente de requisições nem um gerador de carga, ela executa os testes funcionais que o ab nunca foi feito para executar.
Uma configuração saudável usa ambos. Execute cenários Apidog para provar que o endpoint está correto. Execute ab para provar que ele é rápido o suficiente. Para o lado da correção, veja o guia de teste de desempenho do Apidog e o tutorial geral de teste de desempenho de API.
FAQ
ApacheBench é apenas para servidores Apache?
Não. Apesar do nome, ab envia requisições HTTP e HTTPS simples para qualquer servidor. Funciona contra Nginx, Node, Go, Python ou qualquer host que fale HTTP. A ligação com Apache é apenas que a ferramenta vem com o Apache HTTP Server.
Qual concorrência e contagem de requisições devo usar?
Comece baixo e aumente. Tente -n 1000 -c 10, depois aumente -c para 25, 50, 100 e observe onde as requisições por segundo param de aumentar e as requisições falhas começam a aparecer. Esse ponto de inflexão é aproximadamente onde o endpoint satura. Combine sua concorrência de pico com o tráfego real esperado, em vez de escolher um número redondo grande.
Por que minhas requisições falhas são altas quando a API funciona bem?
ab marca uma requisição como falha se o comprimento da resposta variar entre as requisições, o que é normal para JSON dinâmico. Adicione a flag -l para parar de contar diferenças de comprimento como falhas. Em seguida, verifique a linha "Non-2xx responses" para ver se há erros reais subjacentes.
ab pode testar um endpoint que precisa de um token de login?
Sim, se você já tiver um token. Passe-o com -H "Authorization: Bearer SEU_TOKEN". O que ab não pode fazer é logar primeiro para obter um token fresco e depois usá-lo. Esse é um fluxo multi-etapas, e você precisa de uma ferramenta baseada em cenários como Apidog para isso.
ab suporta HTTP/2?
Não. ab fala HTTP/1.x e, de acordo com a documentação oficial, nem mesmo o implementa totalmente. Se o comportamento do seu servidor sob HTTP/2 for importante, use uma ferramenta de carga com suporte a HTTP/2.
