Tutoriais
Teste de Performance com Grafana K6

Introdução ao Grafana K6

O que é o K6?

K6 (opens in a new tab) é uma ferramenta moderna de teste de carga e performance de código aberto, projetada para ser eficiente, extensível e fácil de usar. Criada inicialmente pela Load Impact e agora mantida pela Grafana Labs, o K6 é utilizado para testar a robustez e o desempenho de aplicações, APIs e serviços.

O K6 permite simular múltiplos usuários virtuais (VUs) que executam ações definidas em scripts escritos em JavaScript, facilitando a criação de cenários de teste realistas. Ele é amplamente adotado por desenvolvedores e engenheiros de performance para garantir que seus sistemas possam lidar com cargas elevadas e continuar operando de maneira eficiente.

Por que usar o K6?

Existem várias razões para escolher o K6 como sua ferramenta de teste de performance, incluindo:

  • Facilidade de Uso: Com uma sintaxe simples baseada em JavaScript, o K6 permite que os usuários criem e mantenham scripts de teste de maneira intuitiva.
  • Desempenho: O K6 é altamente eficiente e pode simular milhares de usuários virtuais com baixo consumo de recursos.
  • Extensibilidade: A arquitetura modular do K6 permite a integração com outras ferramentas e plataformas, como Grafana, Prometheus e InfluxDB, facilitando a visualização e a análise dos resultados dos testes.
  • Automação: O K6 pode ser facilmente integrado em pipelines CI/CD, permitindo a execução automática de testes de performance em cada build ou lançamento.
  • Comunidade e Suporte: Sendo um projeto de código aberto, o K6 possui uma comunidade ativa e em crescimento, oferecendo suporte, plugins e melhorias constantes.

Casos de uso comuns

O K6 é uma ferramenta versátil e pode ser utilizada em diversos cenários de teste de performance, incluindo:

  • Testes de Carga: Avaliação de como uma aplicação se comporta sob carga pesada, simulando centenas ou milhares de usuários simultâneos.
  • Testes de Estresse: Identificação dos limites de uma aplicação, aumentando gradualmente a carga até que o sistema falhe.
  • Testes de Endurance: Testes prolongados para verificar a estabilidade e a performance de uma aplicação ao longo do tempo.
  • Testes Funcionais: Validação do comportamento funcional de APIs e serviços, garantindo que eles respondam corretamente sob carga.
  • Testes de Regressão: Garantia de que novas alterações no código não introduzam problemas de performance.

O uso do K6 em diferentes tipos de testes ajuda as equipes a identificar e resolver gargalos de performance, garantindo que as aplicações sejam robustas e escaláveis.

Instalação e Configuração

Instalação do K6

K6 possui pacotes para Linux, macOS e Windows. Alternativamente, você pode usar um contêiner Docker ou um binário standalone.

Linux

Debian/Ubuntu
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
Fedora/CentOS

Usando dnf (ou yum em versões mais antigas):

sudo dnf install https://dl.k6.io/rpm/repo.rpm
sudo dnf install k6

macOS

Usando Homebrew:

brew install k6

Windows

Se você usa o gerenciador de pacotes Chocolatey, pode instalar o pacote não oficial do K6 com:

choco install k6

Se você usa o Windows Package Manager, instale os pacotes oficiais dos manifests do K6:

winget install k6 --source winget

Alternativamente, você pode baixar e executar o instalador oficial mais recente.

Docker

docker pull grafana/k6

Também temos uma imagem separada que você pode usar com o Chromium instalado para executar testes de navegador com o K6:

docker pull grafana/k6:master-with-browser

Download do binário do K6

Na página de Releases no GitHub (opens in a new tab) do Grafana k6 tem um binário standalone para todas as plataformas. Após baixar e extrair o arquivo para sua plataforma, coloque o binário k6 ou k6.exe no seu PATH para executar o K6 de qualquer local.

Configuração inicial

Após instalar o K6, é importante verificar se a instalação foi bem-sucedida. Para isso, você pode executar o comando:

k6 version

Isso exibirá a versão do K6 instalada, confirmando que a instalação foi concluída com sucesso.

Se você precisar de suporte adicional ou encontrar problemas durante a instalação, consulte a documentação de solução de problemas (opens in a new tab) ou participe da comunidade K6 no Slack e nos fóruns.

Com o K6 instalado e configurado, você está pronto para começar a criar e executar seus testes de performance.

Conceitos Básicos

Escrevendo seu primeiro teste

Quando você cria um novo teste de carga, um dos primeiros passos é definir as requisições HTTP que deseja testar.

Requisição GET

Aqui está um exemplo de uma requisição GET simples:

import http from 'k6/http';
 
export default function () {
  http.get('http://test.k6.io');
}

Requisição POST

Para algo um pouco mais complexo, este exemplo mostra uma requisição POST com um payload de autenticação por email/senha:

import http from 'k6/http';
 
export default function () {
  const url = 'http://test.k6.io/login';
  const payload = JSON.stringify({
    email: 'aaa',
    password: 'bbb',
  });
 
  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };
 
  http.post(url, payload, params);
}

Métodos disponíveis

O módulo http lida com todos os tipos de requisições HTTP e métodos:

NomeValor
batch()Emite múltiplas requisições HTTP em paralelo (como navegadores tendem a fazer).
del()Emite uma requisição HTTP DELETE.
get()Emite uma requisição HTTP GET.
head()Emite uma requisição HTTP HEAD.
options()Emite uma requisição HTTP OPTIONS.
patch()Emite uma requisição HTTP PATCH.
post()Emite uma requisição HTTP POST.
put()Emite uma requisição HTTP PUT.
request()Emite qualquer tipo de requisição HTTP.

Tags de Requisição HTTP

O K6 aplica automaticamente tags às suas requisições HTTP, que você pode usar para filtrar seus resultados e organizar sua análise.

NomeDescrição
expected_responsePor padrão, status de resposta entre 200 e 399 são considerados verdadeiros. Pode ser alterado com setResponseCallback.
groupQuando a requisição é executada dentro de um grupo, o valor da tag é o nome do grupo. Padrão é vazio.
namePor padrão é a URL requisitada.
methodMétodo da requisição (GET, POST, PUT etc.).
scenarioQuando a requisição é executada dentro de um cenário, o valor da tag é o nome do cenário. Padrão é default.
statusStatus da resposta.
urlPor padrão é a URL requisitada.

Exemplo de Requisição GET com Tags

import http from 'k6/http';
 
export default function () {
  http.get('http://test.k6.io');
}

Exemplo de Requisição POST com Tags

import http from 'k6/http';
 
export default function () {
  const url = 'http://test.k6.io/login';
  const payload = JSON.stringify({
    email: 'aaa',
    password: 'bbb',
  });
 
  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };
 
  http.post(url, payload, params);
}

Agrupamento de URLs sob uma Tag

Se seu teste possui caminhos de URL dinâmicos, você pode desejar agregar os dados dessas URLs em uma única métrica. Para isso, você pode definir explicitamente uma tag name:

import http from 'k6/http
 
';
 
export default function () {
  for (let id = 1; id <= 100; id++) {
    http.get(`http://example.com/posts/${id}`, {
      tags: { name: 'PostsItemURL' },
    });
  }
}

Métricas

Métricas medem como um sistema performa sob condições de teste. Por padrão, o K6 coleta automaticamente métricas embutidas. Além das métricas embutidas, você pode criar métricas customizadas.

Tipos de Métricas

  • Counters: Somam valores.
  • Gauges: Acompanham os menores, maiores e mais recentes valores.
  • Rates: Acompanham com que frequência um valor não-zero ocorre.
  • Trends: Calculam estatísticas para múltiplos valores (como média, moda ou percentil).

Exemplo de Métrica Personalizada

import { Trend } from 'k6/metrics';
 
const myTrend = new Trend('waiting_time');
 
export default function () {
  const res = http.get('https://httpbin.test.k6.io');
  myTrend.add(res.timings.waiting);
}

Checagens

Checagens validam condições booleanas em seu teste. Elas são usadas para verificar se o sistema está respondendo com o conteúdo esperado.

Exemplo de Checagem de Código de Resposta

import { check } from 'k6';
import http from 'k6/http';
 
export default function () {
  const res = http.get('http://test.k6.io/');
  check(res, {
    'is status 200': (r) => r.status === 200,
  });
}

Thresholds

Thresholds são os critérios de aprovação/reprovação que você define para suas métricas de teste. Se a performance do sistema sob teste (SUT) não atender às condições do threshold, o teste termina com status de falha.

Exemplo de Thresholds para Erros HTTP e Duração de Resposta

import http from 'k6/http';
 
export const options = {
  thresholds: {
    http_req_failed: ['rate<0.01'], // erros HTTP devem ser menos que 1%
    http_req_duration: ['p(95)<200'], // 95% das requisições devem ser menores que 200ms
  },
};
 
export default function () {
  http.get('https://test-api.k6.io/public/crocodiles/1/');
}

Ciclo de Vida do Teste

Um script K6 sempre passa por essas etapas na mesma ordem:

  1. Init: Carregamento de arquivos, importação de módulos e definição de funções de ciclo de vida.
  2. Setup: Configuração do ambiente de teste e geração de dados.
  3. VU: Execução do teste, geralmente na função default.
  4. Teardown: Processamento dos dados e encerramento do ambiente de teste.

Estrutura Básica de um Script K6

// 1. Código de Init
 
export function setup() {
  // 2. Código de Setup
}
 
export default function (data) {
  // 3. Código de VU
}
 
export function teardown(data) {
  // 4. Código de Teardown
}

Funções Adicionais de Ciclo de Vida

  • handleSummary(): Para criar um resumo customizado, o K6 chama essa função no final do teste.
  • Funções de cenário: Em vez de default, você pode executar o código de VU em funções de cenário.

Exemplo de Função de Cenário

import http from 'k6/http';
import { sleep } from 'k6';
 
export const options = {
  scenarios: {
    my_web_test: {
      exec: 'webtest',
      executor: 'constant-vus',
      vus: 50,
      duration: '1m',
    },
  },
};
 
export function webtest() {
  http.get('https://test.k6.io/contacts.php');
  sleep(Math.random() * 2);
}

Nos próximos capítulos, exploraremos como configurar cenários de teste, analisar os resultados e integrar o K6 com o Grafana para uma visualização avançada das métricas de performance.

Configuração de Cenários de Teste

Cenários configuram como os VUs e as iterações são agendadas em detalhes granulares. Com cenários, você pode modelar cargas de trabalho diversas ou padrões de tráfego em testes de carga.

Benefícios de usar cenários

  • Organização mais fácil e flexível dos testes: Você pode declarar múltiplos cenários no mesmo script, e cada um pode executar uma função JavaScript diferente de forma independente.
  • Simulação de tráfego mais realista: Cada cenário pode usar um padrão distinto de agendamento de VU e iteração, impulsionado por um executor específico.
  • Cargas de trabalho paralelas ou sequenciais: Os cenários são independentes entre si e executados em paralelo, embora possam ser feitos para parecer sequenciais configurando a propriedade startTime de cada um cuidadosamente.
  • Análise granular de resultados: Diferentes variáveis de ambiente e tags de métricas podem ser configuradas por cenário.

Configurando cenários

Para configurar cenários, use a chave scenarios no objeto options. Você pode dar qualquer nome ao cenário, desde que cada nome de cenário no script seja único.

O nome do cenário aparece no resumo dos resultados, tags, e assim por diante.

export const options = {
  scenarios: {
    example_scenario: {
      // nome do executor a ser usado
      executor: 'shared-iterations',
 
      // configuração comum do cenário
      startTime: '10s',
      gracefulStop: '5s',
      env: { EXAMPLEVAR: 'testing' },
      tags: { example_tag: 'testing' },
 
      // configuração específica do executor
      vus: 10,
      iterations: 200,
      maxDuration: '10s',
    },
    another_scenario: {
      /*...*/
    },
  },
};

Executores de Cenário

Para cada cenário K6, a carga de trabalho dos VUs é agendada por um executor. Os executores configuram quanto tempo o teste dura, se o tráfego permanece constante ou muda, e se a carga de trabalho é modelada por VUs ou pela taxa de chegada (ou seja, modelos abertos ou fechados).

Seu objeto de cenário deve definir a propriedade executor com um dos nomes de executor predefinidos. Sua escolha de executor determina como o K6 modela a carga. As opções incluem:

  • Por número de iterações:
    • shared-iterations: compartilha iterações entre os VUs.
    • per-vu-iterations: cada VU executa as iterações configuradas.
  • Por número de VUs:
    • constant-vus: mantém o número de VUs constante.
    • ramping-vus: aumenta ou diminui o número de VUs de acordo com os estágios configurados.
  • Por taxa de iterações:
    • constant-arrival-rate: inicia iterações a uma taxa constante.
    • ramping-arrival-rate: aumenta ou diminui a taxa de iterações de acordo com os estágios configurados.

Além das opções genéricas de cenário, cada objeto executor possui opções adicionais específicas para sua carga de trabalho. Para a lista completa, consulte Executores (opens in a new tab).

Opções de Cenário

Opção (obrigatória)TipoDescriçãoPadrão
executorstringNome único do executor. Veja a lista de possíveis valores na seção de executores.-
startTimestringDeslocamento de tempo desde o início do teste, no qual este cenário deve começar a execução."0s"
gracefulStopstringTempo para aguardar que as iterações terminem antes de interrompê-las à força. Para saber mais, leia Graceful Stop."30s"
execstringNome da função JS exportada a ser executada."default"
envobjectVariáveis de ambiente específicas para este cenário.
tagsobjectTags específicas para este cenário.

Exemplo de Cenário

Este script combina dois cenários, com sequenciamento:

  • O shared_iter_scenario começa imediatamente. Dez VUs tentam usar 100 iterações o mais rápido possível (alguns VUs podem usar mais iterações do que outros).
  • O per_vu_scenario começa após 10s. Neste caso, dez VUs executam cada um dez iterações.
import http from 'k6/http';
 
export const options = {
  scenarios: {
    shared_iter_scenario: {
      executor: 'shared-iterations',
      vus: 10,
      iterations: 100,
      startTime: '0s',
    },
    per_vu_scenario: {
      executor: 'per-vu-iterations',
      vus: 10,
      iterations: 10,
      startTime: '10s',
    },
  },
};
 
export default function () {
  http.get('https://test.k6.io/');
}

Se você executar um script com cenários, a saída do

K6 inclui informações de alto nível sobre cada um. Por exemplo, se você executar o script anterior com k6 run scenario-example.js, o K6 reporta os cenários da seguinte forma:

  execution: local
     script: scenario-example.js
     output: -
 
  scenarios: (100.00%) 2 scenarios, 20 max VUs, 10m40s max duration (incl. graceful stop):
           * shared_iter_scenario: 100 iterations shared among 10 VUs (maxDuration: 10m0s, gracefulStop: 30s)
           * per_vu_scenario: 10 iterations for each of 10 VUs (maxDuration: 10m0s, startTime: 10s, gracefulStop: 30s)

A saída completa inclui as métricas de resumo, como qualquer resumo padrão de fim de teste.

Modelos Abertos e Fechados

Diferentes configuradores de cenário podem afetar muitos aspectos diferentes do seu sistema, incluindo a carga gerada, os recursos utilizados e as métricas emitidas. Se você souber um pouco sobre como os cenários funcionam, projetará melhores testes e interpretará os resultados com mais compreensão.

Modelos Fechados

No modelo fechado, o tempo de execução de cada iteração dita o número de iterações executadas em seu teste. A próxima iteração não começa até que a anterior termine.

import http from 'k6/http';
 
export const options = {
  scenarios: {
    closed_model: {
      executor: 'constant-vus',
      vus: 1,
      duration: '1m',
    },
  },
};
 
export default function () {
  http.get('https://httpbin.test.k6.io/delay/6');
}

Executar este script resultaria em algo como:

running (1m01.5s), 0/1 VUs, 10 complete and 0 interrupted iterations
closed_model  [======================================] 1 VUs  1m0s

Desvantagens de usar o Modelo Fechado

Quando a duração da iteração do VU está fortemente ligada ao início de novas iterações de VU, o tempo de resposta do sistema alvo pode influenciar a taxa de transferência do teste. Tempos de resposta mais lentos significam iterações mais longas e uma taxa de chegada de novas iterações menor, e vice-versa para tempos de resposta mais rápidos. Em alguns textos de teste, esse problema é conhecido como "omissão coordenada".

Modelo Aberto

Comparado ao modelo fechado, o modelo aberto dissocia as iterações do VU da duração da iteração. Os tempos de resposta do sistema alvo não influenciam mais a carga sobre o sistema alvo.

import http from 'k6/http';
 
export const options = {
  scenarios: {
    open_model: {
      executor: 'constant-arrival-rate',
      rate: 1,
      timeUnit: '1s',
      duration: '1m',
      preAllocatedVUs: 20,
    },
  },
};
 
export default function () {
  http.get('https://httpbin.test.k6.io/delay/6');
}

Executar este script resultaria em algo como:

running (1m09.3s), 000/011 VUs, 60 complete and 0 interrupted iterations
open_model  [======================================] 011/011 VUs  1m0s  1 iters/s

Parada Graciosa (Graceful Stop)

O gracefulStop é um período no final do teste em que o K6 permite que as iterações em andamento sejam concluídas.

Exemplo de Parada Graciosa

import http from 'k6/http';
 
export const options = {
  discardResponseBodies: true,
  scenarios: {
    contacts: {
      executor: 'constant-vus',
      vus: 100,
      duration: '10s',
      gracefulStop: '3s',
    },
  },
};
 
export default function () {
  const delay = Math.floor(Math.random() * 5) + 1;
  http.get(`https://httpbin.test.k6.io/delay/${delay}`);
}

Executar este script resultaria em algo como:

running (13.0s), 000/100 VUs, 349 complete and 23 interrupted iterations
contacts  [======================================] 100 VUs  10s

Alocação de VUs por Taxa de Chegada

Nos executores de taxa de chegada, enquanto o K6 tiver VUs disponíveis, ele inicia iterações de acordo com sua taxa-alvo. A capacidade de definir a taxa de iteração vem com um pouco mais de complexidade de configuração: você deve pré-alocar um número suficiente de VUs. Em outras palavras, antes que o teste seja executado, você deve:

  • Configurar a carga (como novas iterações por unidade de tempo)
  • Garantir que você alocou VUs suficientes.

Iterações Perdidas

Às vezes, um cenário não pode executar o número esperado de iterações. O K6 rastreia o número de iterações não enviadas em uma métrica de contador, dropped_iterations. O número de iterações perdidas pode ser um dado valioso quando você depura executores ou analisa resultados.

Exemplos Avançados

Você pode usar múltiplos cenários em um script, e esses cenários podem ser executados em sequência ou em paralelo. Algumas maneiras de combinar cenários incluem:

  • Ter diferentes horários de início para sequenciar cargas de trabalho
  • Adicionar tags e variáveis de ambiente por cenário
  • Fazer thresholds específicos de cenário.
  • Usar múltiplos cenários para executar diferentes lógicas de teste, para que os VUs não executem apenas a função padrão.

Combinando Cenários

Com a propriedade startTime, você pode configurar seu script para iniciar alguns cenários mais tarde que outros. Para sequenciar seus cenários, você pode combinar startTime com as opções de duração específicas do executor.

Este script tem dois cenários, contacts e news, que são executados em sequência:

import http from 'k6/http';
 
export const options = {
  discardResponseBodies: true,
  scenarios: {
    contacts: {
      executor: 'constant-vus',
      exec: 'contacts',
      vus: 50,
      duration: '30s',
    },
    news: {
      executor: 'per-vu-iterations',
      exec: 'news',
      vus: 50,
      iterations: 100,
      startTime: '30s',
      maxDuration: '1m',
    },
  },
};
 
export function contacts() {
  http.get('https://test.k6.io/contacts.php', {
    tags: { my_custom_tag: 'contacts' },
  });
}
 
export function news() {
  http.get('https://test.k6.io/news.php', { tags: { my_custom_tag: 'news' } });
}

Usando Variáveis de Ambiente e Tags Diferentes por Cenário

Você pode definir tags por cenário, aplicando-as a outros objetos que podem ser etiquetados.

import http from 'k6/http';
import { fail } from 'k6';
 
export const options = {
  discardResponseBodies: true,
  scenarios: {
    contacts: {
      executor: 'constant-vus',
      exec: 'contacts',
      vus: 50,
      duration: '30s',
      tags: { my_custom_tag: 'contacts' },
      env: { MYVAR: 'contacts' },
    },
    news: {
      executor: 'per-vu-iterations',
      exec: 'news',
      vus: 50,
      iterations: 100,
      startTime: '30s',
      maxDuration: '1m',
      tags: { my_custom_tag: 'news' },
      env: { MYVAR: 'news' },
    },
  },
};
 
export function contacts() {
  if (__ENV.MYVAR != 'contacts') fail();
  http.get('https://test.k6.io/contacts.php');
}
 
export function news() {
  if (__ENV.MYVAR != 'news') fail();
  http.get('https://test.k6.io/news.php');
}

Executando Múltiplas Funções de Cenário, com Diferentes Thresholds

Você também pode definir diferentes thresholds para diferentes funções de cenário. Para fazer isso:

  • Defina tags específicas de cenário.
  • Defina thresholds para essas tags.

Este teste tem 3 cenários, cada um com diferentes funções de execução, tags e variáveis de ambiente, e thresholds:

import http from 'k6/http';
import { sleep } from 'k6';
 
export const options = {
  scenarios: {
    my_web_test: {
      executor: 'constant-vus',
      vus: 50,
      duration: '5m',
      gracefulStop: '0s', // não aguarde iterações terminarem no final
      tags: { test_type: 'website' },
      exec: 'webtest',
    },
    my_api_test_1: {
      executor: 'constant-arrival-rate',
      rate: 90,
      timeUnit: '1m',
      duration: '5m',
      preAllocatedVUs: 10,
      tags: { test_type: 'api' },
      env: { MY_CROC_ID: '1' },
      exec: 'apitest',
    },
    my_api_test_2: {
      executor:
 
 'ramping-arrival-rate',
      startTime: '30s',
      startRate: 50,
      timeUnit: '1s',
      stages: [
        { target: 200, duration: '30s' },
        { target: 200, duration: '3m30s' },
        { target: 0, duration: '30s' },
      ],
      preAllocatedVUs: 50,
      maxVUs: 100,
      tags: { test_type: 'api' },
      env: { MY_CROC_ID: '2' },
      exec: 'apitest',
    },
  },
  discardResponseBodies: true,
  thresholds: {
    'http_req_duration{test_type:api}': ['p(95)<250', 'p(99)<350'],
    'http_req_duration{test_type:website}': ['p(99)<500'],
    'http_req_duration{scenario:my_api_test_2}': ['p(99)<300'],
  },
};
 
export function webtest() {
  http.get('https://test.k6.io/contacts.php');
  sleep(Math.random() * 2);
}
 
export function apitest() {
  http.get(`https://test-api.k6.io/public/crocodiles/${__ENV.MY_CROC_ID}/`);
}

Análise de Resultados

Visualização de Resultados

O K6 emite métricas com timestamps a cada ponto do teste. Você pode visualizar os resultados das métricas como estatísticas agregadas ou pontos de dados individuais.

Sumário ao Final do Teste

Quando um teste termina, o K6 imprime uma visão geral dos resultados agregados no stdout.

checks.........................: 50.00%  45        45
data_received..................: 1.3 MB 31 kB/s
data_sent......................: 81 kB  2.0 kB/s
group_duration.................: avg=6.45s    min=4.01s    med=6.78s    max=10.15s   p(90)=9.29s    p(95)=9.32s
http_req_blocked...............: avg=57.62ms  min=7µs      med=12.25µs  max=1.35s    p(90)=209.41ms p(95)=763.61ms
http_req_connecting............: avg=20.51ms  min=0s       med=0s       max=1.1s     p(90)=100.76ms p(95)=173.41ms
http_req_duration..............: avg=144.56ms min=104.11ms med=110.47ms max=1.14s    p(90)=203.54ms p(95)=215.95ms
  { expected_response:true }...: avg=144.56ms min=104.11ms med=110.47ms max=1.14s    p(90)=203.54ms p(95)=215.95ms
http_req_failed................: 0.00%   0         180
http_req_receiving.............: avg=663.96µs min=128.46µs med=759.82µs max=1.66ms   p(90)=1.3ms    p(95)=1.46ms
http_req_sending...............: avg=88.01µs  min=43.07µs  med=78.03µs  max=318.81µs p(90)=133.15µs p(95)=158.3µs
http_req_tls_handshaking.......: avg=29.25ms  min=0s       med=0s       max=458.71ms p(90)=108.31ms p(95)=222.46ms
http_req_waiting...............: avg=143.8ms  min=103.5ms  med=109.5ms  max=1.14s    p(90)=203.19ms p(95)=215.56ms
http_reqs......................: 180    4.36938/s
iteration_duration.............: avg=12.91s   min=12.53s   med=12.77s   max=14.35s   p(90)=13.36s   p(95)=13.37s
iterations.....................: 45     1.092345/s
vus............................: 1      min=1      max=19
vus_max........................: 20     min=20     max=20

Além desse sumário padrão, o K6 pode gerar os resultados em outros formatos ao final do teste:

Sumário Customizado

Você pode usar a função handleSummary() para criar relatórios totalmente customizados.

import { handleSummary } from 'k6';
 
export function handleSummary(data) {
  // processar os dados e gerar relatórios customizados
  return {
    'summary.html': generateHtmlReport(data), // função fictícia para gerar HTML
    stdout: JSON.stringify(data, null, 2), // imprime JSON no console
  };
}

Exportação para CSV

k6 run --out csv=resultado.csv script.js

Exportação para JSON

k6 run --out json=resultado.json script.js

Resultados em Tempo Real

Além do sumário ao final do teste, você também pode visualizar métricas como pontos de dados granulares em tempo real. O K6 pode transmitir as métricas em tempo real e:

  • Escrever a saída em um arquivo.
  • Enviar a saída para um serviço externo.

Escrever para Arquivo

Atualmente, o K6 suporta a escrita nos seguintes formatos de arquivo:

  • CSV
  • JSON

Transmitir para Serviço

Você também pode transmitir métricas em tempo real para:

  • Grafana Cloud K6
  • Amazon CloudWatch
  • Apache Kafka
  • Datadog
  • Dynatrace
  • Elasticsearch
  • Grafana Cloud Prometheus
  • InfluxDB
  • Netdata
  • New Relic
  • Prometheus remote write
  • TimescaleDB
  • StatsD

Para usar o StatsD, você precisa construir um binário K6 usando a extensão xk6-output-statsd.

Web Dashboard

O K6 fornece um dashboard web embutido que você pode habilitar para visualizar e monitorar os resultados dos testes em tempo real.

Para habilitar o dashboard web, defina a variável de ambiente K6_WEB_DASHBOARD como true ao executar seu script de teste:

K6_WEB_DASHBOARD=true k6 run script.js

Por padrão, o dashboard web está disponível na porta 5665 do localhost. Você pode alterar o host e a porta usando as opções de configuração do dashboard.

Gerar Relatórios HTML

Você pode gerar relatórios HTML detalhados diretamente do dashboard web ou da linha de comando. Esses relatórios são auto-contidos, ideais para compartilhar com sua equipe.

Para gerar um relatório a partir do dashboard web, clique em Report no menu do dashboard.

Para gerar um relatório automaticamente a partir da linha de comando uma vez que o teste termine, use a opção K6_WEB_DASHBOARD_EXPORT:

K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=relatorio.html k6 run script.js

Conclusão

Com a instalação e configuração do K6 concluídas, você está pronto para começar a criar e executar seus testes de performance. Este guia abordou desde os conceitos básicos até práticas avançadas, ajudando você a entender como utilizar o K6 de maneira eficaz.

Referências