Adriano Júnior
← Artigos

k6

Grafana e k6: testes de carga e observabilidade

O k6 (Grafana Labs) para estressar APIs com scripts em JavaScript, exportar resumo e comparar runs, e como o Grafana entra no jogo com InfluxDB para ver latência e throughput no tempo, sem confundir isso com teste unitário.

Quando a API já “funciona nos testes” e você quer uma resposta mais honesta (quantos clientes em paralelo ela aguenta, com que latência e onde começam os erros), entra o teste de carga. O k6 é uma ferramenta orientada a desenvolvedor para isso: você escreve o cenário em JavaScript, roda o binário k6 e lê métricas agregadas no terminal. O Grafana aparece quando você quer curvas no tempo (ao vivo ou histórico), em geral com um banco de séries temporais entre o k6 e os painéis. InfluxDB é o padrão clássico nesse meio.

Este texto é o fluxo que eu costumo seguir: instalar o k6, um script mínimo, rodar o teste, exportar resultado para comparar versões e, se fizer sentido, ligar no Grafana para enxergar o impacto na API como série temporal.

Se quiser ir direto ao gráfico, pule para Ver impacto em gráficos com Grafana.

Por que usar o k6

  • Scriptável: dá para versionar o teste no mesmo repositório da API.
  • Métricas úteis: duração HTTP, taxa de erro, throughput, checks declarativos, usuários virtuais (VUs).
  • Ecossistema Grafana: saída para InfluxDB, Grafana Cloud k6, OpenTelemetry, etc.

O k6 não substitui teste unitário nem integração; ele complementa ao simular muitos clientes ao mesmo tempo.

Instalação

No Windows, winget costuma ser o caminho mais simples:

winget install GrafanaLabs.k6

Confira com k6 version. Se o terminal não reconhecer k6 depois da instalação, feche e abra de novo (o PATH precisa recarregar) ou use o executável completo, por exemplo C:\Program Files\k6\k6.exe.

Outros sistemas: documentação oficial de instalação.

Conceitos essenciais

ConceitoSignificado
VU (virtual user)“Usuário” simulado que executa sua função default em loop.
optionsDuração do teste, número de VUs, stages (rampas), limites, etc.
http.get / http.postRequisições HTTP; o k6 agrega métricas como http_req_duration.
check()Asserções sobre a resposta (status, corpo, cabeçalhos). Falhar um check não derruba o VU; só entra na taxa de checks.
sleep()Pausa entre iterações; ajuda a modelar tempo de “pensamento” do usuário.

Exemplo mínimo de script

Um arquivo .js importa k6/http e exporta options + a função default:

import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
  vus: 5,
  duration: "30s",
};

const base = __ENV.BASE_URL || "http://localhost:3000";

export default function () {
  const res = http.get(`${base}/health`);
  check(res, { "status 200": (r) => r.status === 200 });
  sleep(1);
}

A variável de ambiente BASE_URL evita editar o arquivo quando o host muda:

# PowerShell
$env:BASE_URL="http://127.0.0.1:8080"; k6 run k6/api-test.js

Executar o teste

Com o alvo (por exemplo uma API REST) no ar:

k6 run caminho/para/o/script.js

No fim, o k6 imprime um resumo: requisições por segundo, percentis de duração (p90, p95, …), taxa de checks, etc. Vale subir vus e duration aos poucos, ou usar stages, até aparecer degradação clara (erro ou latência fora do aceitável).

P90 e P95 em uma frase cada

  • p90 → “9 em cada 10 requisições foram mais rápidas que este tempo.”
  • p95 → “19 em cada 20 foram mais rápidas que este tempo.”

Ou seja: percentil responde “como está a maioria?” e deixa claro se existe uma minoria muito lenta (a cauda).

Exemplo 1: a média esconde o problema

Imagine 10 chamadas, tempos em milissegundos, já do menor ao maior:

50, 51, 52, 53, 54, 55, 56, 57, 58, 400

  • Média89 ms (soma tudo e divide por 10). No papel, parece “ok”.
  • Na prática: 9 usuários viram tempos entre ~50 e 58 ms; 1 esperou 400 ms.

O p90 (ideia intuitiva nesse tipo de conjunto) aponta para a região das respostas rápidas da maioria. A média puxa para cima por causa do 400 e não diz que quase todo mundo teve experiência boa.

Exemplo 2: p95 com 20 chamadas

19 respostas entre 48 e 55 ms, e 1 resposta de 2000 ms (fila, banco, spike).

  • Média sobe forte por causa do 2000.
  • p95 continua perto dos ~55 ms. Ou seja, 95% das chamadas estavam no patamar bom; o problema está na fatia pequena que demorou eras.

É essa fatia que em produção vira reclamação, timeout ou SLA estourado. Por isso em carga olhamos p90/p95, não só média.

Resumo

MétricaO que ela te conta
MédiaUm número só, mistura rápidas e lentas; outliers distorcem fácil.
p90 / p95Onde está a maioria; se a cauda (poucas lentas) está grande demais.

No k6, o resumo já traz esses percentis. Dá para comparar runs e ver se a “cauda” piorou depois de uma mudança no código ou na infra.

Guardar resultados para comparar

Para comparar duas configurações da API ou duas versões, exportar o resumo em JSON no fim do run é bem prático:

k6 run --summary-export=resultados/antes.json script.js
k6 run --summary-export=resultados/depois.json script.js

Você pode comparar os arquivos no editor ou com qualquer ferramenta de diff. Para série temporal completa (arquivo maior), existe também -o json=..., útil em pipeline ou análise mais pesada.


Ver impacto em gráficos com Grafana

O Grafana não recebe métricas “direto” do k6 sem um intermediário: quase sempre entra um armazém de métricas. Em ambiente local, um desenho clássico é:

  1. InfluxDB 1.x recebendo pontos em tempo real do k6.
  2. Grafana com datasource InfluxDB e um dashboard voltado a k6.

Enviar métricas do k6 para o InfluxDB

Com o InfluxDB acessível (por exemplo localhost:8086) e a base k6 criada:

k6 run -o influxdb=http://localhost:8086/k6 script.js

Enquanto o teste roda, os dados vão sendo escritos no InfluxDB.

Subir Grafana + InfluxDB com Docker

Um docker-compose típico expõe o InfluxDB na porta 8086 e o Grafana em outra (por exemplo 3001, para não brigar com a API na 3000). Dá para provisionar o datasource já apontando para a base k6.

Fluxo resumido:

  1. docker compose up -d
  2. Subir a API que você vai testar.
  3. Rodar o k6 com -o influxdb=....
  4. Abrir o Grafana e importar um dashboard da comunidade. O ID 2587 (k6 Load Testing Results) é muito usado com InfluxDB.
  5. No import, escolher o datasource InfluxDB certo.

Assim você vê requisições por segundo, latências e outras séries ao longo do tempo, e consegue relacionar carga com o comportamento da API.

Grafana Cloud e k6

Para quem prefere SaaS, a Grafana Cloud tem fluxo centrado em k6 (execução e visualização). Quando sair do 100% local, vale olhar a documentação Grafana Cloud k6.

Boas práticas para começar

  • Comece com poucos VUs e aumente até aparecer erro ou latência inaceitável.
  • Use check() para critério de sucesso (status, JSON mínimo), não só “a requisição completou”.
  • Mantenha o cenário determinístico (URLs, payloads) para comparação entre runs ser justa.
  • Não estresse produção sem processo combinado; use staging ou ambiente dedicado a carga.
  • Em CI, dá para rodar k6 com janela curta e falhar o pipeline se checks ou SLIs definidos não baterem.

Considerações finais

O k6 dá um jeito rápido e repetível de medir como a API reage à carga. O resumo em JSON ajuda a comparar evolução entre versões; Grafana + InfluxDB (ou Grafana Cloud) dá contexto visual para afinar performance e mostrar resultado para o time.

O objetivo aqui foi amarrar o fluxo inteiro, do script ao gráfico, sem tratar carga como substituto de teste de regressão.

Onde aprofundar