Teste de carga HTTP com Vegeta

Viviane Reis
beyondTest
Published in
7 min readJul 6, 2020
Fonte: DEVIANT ART

Como conheci a ferramenta Vegeta 👩🏾‍💻

Na empresa em que eu trabalho em todas as últimas sexta-feiras do mês dedicamos o dia estudando algo novo (conteúdos dentro ou fora da área de atuação e relacionadas à tecnologia), esse dia é chamado de TECH DAY, que apelidamos de SSL (sexta sem lei). Em um desses dias resolvi estudar sobre uma ferramenta nova para testes de carga. Eu já havia ouvido falar do Vegeta e de sua versatilidade, e também um dos devs que trabalha no time me sugeriu como opção. Então foi a ferramenta que escolhi para estudar.

Agora bora lá saber melhor como funciona esse tal de Vegeta.

Antes de tudo…o que são testes de carga? 🤔

Testes de carga tem o objetivo de verificar o limite de capacidade de uma aplicação, através de fatore limites como: software, hardware, tempo de resposta, etc.

O teste de carga é uma parte importante da previsão de como seu serviço se comportará ao longo do tempo. Quando estamos realizando testes de carga, não devemos apenas fazer perguntas simples, como “Quantas requisições por segundo nosso sistema é capaz de atender?” Em vez disso, devemos tentar entender como todo o nosso sistema se comporta sob várias condições de carga. Para responder a essa pergunta, precisamos entender a infraestrutura que compõe nosso sistema e as dependências que um serviço específico possui. Por exemplo, o serviço está por trás de um balanceador de carga? Que tal uma CDN (Content Delivery Network ou Rede de Distribuição de Conteúdo)? Quais outros mecanismos de captura são usados? Todas essas perguntas e mais podem ser respondidas pelo nosso sistema, com boa observabilidade.

- Paul Osman - (Microservices Development Cookbook)

Se quiserem saber um pouco mais sobre este tipo de teste, deem uma olhada no artigo "Uma breve introdução sobre testes de Performance, Stress e Carga".

Como fazer testes de carga? 🤔

Existem muitas ferramentas diferentes para ajudar no teste de carga. A maneira como elas normalmente funcionam é enviando uma requisição HTTP, como por exemplo GET http://www.example.com/some/path e dizer à ferramenta para enviar, por exemplo, 10 requisições por segundo durante 30 segundos. Geralmente é gerado algum tipo de relatório, normalmente em texto simples ou gráfico para ser interpretado.

Conhecendo o Vegeta… 🤩

Vegeta não é só um personagem do Dragon Ball, mas também é uma ferramenta open source para testes de carga HTTP, escrita na linguagem de programação GO, usada via linha de comando ou como uma biblioteca externa no seu projeto. O vegeta permite o envio de tráfego para vários destinos com vários corpos de requisição HTTP, por meio de um arquivo.

Fonte: GIPHY

Então, mão na massa…Vegeta Attack!!!

Instalando o Vegeta

Para usar o Vegeta, você vai precisar dos executáveis pré-compilados, que podem ser encontrados aqui.

Homebrew (macOS)

No caso do Mac é possível a instalação via homebrew, utilizando o seguinte comando:

$ brew update && brew install vegeta

Curl (Linux)

Caso esteja utilizando alguma distribuição Linux, por exemplo o Ubuntu, é possível fazer o download seguindo os passos descritos abaixo:

$ curl -LO https://github.com/tsenart/vegeta/releases/download/v12.8.3/vegeta-12.8.3-linux-amd64.tar.gz

Descompactando tar.gz:

$ tar -zxvf vegeta-12.8.3-linux-amd64.tar.gz

Movendo para /usr/bin para disponibilizá-lo em todo o sistema:

$ sudo mv ./vegeta /usr/bin/vegeta

Verificando a instalação:

$ vegeta --version

Usando linha de comando

O uso mais básico do Vegeta é algo como:

$ echo "GET http://<application_url>/some/path" | vegeta attack -rate=10 -duration=30s | vegeta report

O -rate define o número de requisições por unidade de tempo (o valor padrão é definido como 50/1s) e o -duration especifica a duração do ataque.

Logo, estamos fazendo uma requisição HTTP GET para a URL fornecida a uma taxa de 10 requisições por segundo durante 30 segundos, que retornará um relatório como o seguinte:

Requests      [total, rate, throughput]  300, 10.03, 0.00
Duration [total, attack, wait] 30.08134139s, 29.900351951s, 180.989439ms
Latencies [mean, 50, 95, 99, max] 129.279344ms, 123.6383ms, 183.289094ms, 207.393368ms, 255.297684ms
Bytes In [total, mean] 376800, 1256.00
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.00%
Status Codes [code:count] 200:300
Error Set:
  • Requests: mostra o número total de requisições enviadas durante o teste e a taxa das solicitações;
  • Duration: mostra a duração total do teste, o período de ataque que simula a carga no aplicativo e o tempo de espera;
  • Latencies: mostra a latência média, percentuais 50, 95 e 99, respectivamente, das latências de todas as solicitações em um ataque, bem como a latência máxima reconhecida;
  • Bytes In e Bytes Out: mostra o número total de bytes enviados (out) ou recebidos (in) com os corpos de requisição ou resposta, e o número médio de bytes enviados (out) ou recebidos (in) com os corpos de requisição ou resposta;
  • Success: mostra os percentuais de requisições bem-sucedidas enviadas ao aplicativo;
  • Status Codes: fornecem códigos de resposta HTTP recebidos e sua ocorrência. Um código de status 0 significa que uma solicitação não foi enviada.

Como visível no exemplo acima, 100% das solicitações enviadas ao aplicativo foram bem-sucedidas.

Configurando um arquivo de destino

Como citado anteriormente, o Vegeta também suporta vários destinos para atacar um aplicativo com vários endpoints (ou seja, uma API) simultaneamente.

  • Crie um arquivo de destino e abra-o em um editor de texto de sua preferência. No exemplo abaixo estou usando o vim:
$ vim targets.txt
  • Coloque os diferentes endpoints no arquivo criado:
GET http://<application_url>/list/user/1
GET http://<application_url>/list/user/2
GET http://<application_url>/list/user/3
  • Também é possível definir comandos POST ou PUT no arquivo.
POST http://<application_url>/create/newuser/
Content-Type: application/json
@data/users.json

O conteúdo do arquivo data/users.json contém o corpo da requisição:

{
"name": "Viviane";
"lastname": Reis";
"email": "viviane_reis@example.com"
}

Executando o attack:

$ vegeta attack -duration=30s -rate=10 -targets=targets.txt

No comando acima a leitura da chamada está sendo realizada através do arquivo targets.txt .

Fonte: Speaker Deck

Gerando um Relatório

O teste de carga executado coleta dados que podem ser salvos em um arquivo de saída usando o parâmetro -output . Os dados coletados durante cada teste de carga são armazenados em um arquivo de saída.

O nome padrão do arquivo de saída é results.bin, mas podemos definir qualquer nome utilizando o -output:

$ vegeta attack -duration=30s -rate=10 -targets=txt -output=attack.bin

Usaremos o comando vegeta plot para gerar um relatório HTML a partir do arquivo de saída .bin retornado após o attack, e o -title que permite definir um título para o gráfico.

$ vegeta plot -title="Attack Results" attack.bin > results.html

Abra o arquivo HTML em um navegador da web para visualizar o gráfico:

Para ver o relatório diretamente no terminal, execute:

$ vegeta report attack.bin

Que fornece um relatório no formato visto nas primeiras etapas:

Duration      [total, attack, wait]      31.602714428s, 29.902106254s, 1.700608174s
Latencies [mean, 50, 95, 99, max] 783.59934ms, 520.017482ms, 1.803562842s, 3.331988574s, 3.811116618s
Bytes In [total, mean] 1346700, 4489.00
Bytes Out [total, mean] 14970900, 49903.00
Success [ratio] 100.00%
Status Codes [code:count] 200:300
Error Set:

Análise em tempo real

É possível também integrar o Vegeta ao jplot usando o jaggr para plotar um relatório Vegeta em tempo real e acompanhar do seu terminal, usando o seguinte comando:

vegeta attack -targets target.txt -rate 10 -duration 30s | vegeta encode | \
jaggr @count=rps \
hist\[100,200,300,400,500\]:code \
p25,p50,p95:latency \
sum:bytes_in \
sum:bytes_out | \
jplot rps+code.hist.100+code.hist.200+code.hist.300+code.hist.400+code.hist.500 \
latency.p95+latency.p50+latency.p25 \
bytes_in.sum+bytes_out.sum

Usando biblioteca externa no seu projeto

Primeiramente você vai precisar do GO instalado e do GOBIN no seu PATH. Feito isso, execute o comando:

$ go get -u github.com/tsenart/vegeta

De acordo com a documentação oficial do Vegeta, a versão da biblioteca segue o SemVer v2.0.0. Desde a lib/v9.0.0, a biblioteca e o cli são versionados separadamente para melhor isolar as alterações mais recentes em cada componente.

Veja Versionamento para obter mais detalhes sobre esquemas de nomenclatura de tags git e compatibilidade com go mod.

Segue abaixo um exemplo simples, citado na documentação:

Conclusão

Os testes de carga são muito importantes para nos ajudar a identificar possíveis gargalos na arquitetura, e o Vegeta, com sua versatilidade, nos ajuda muito bem nisso.

--

--