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
| Conceito | Significado |
|---|---|
| VU (virtual user) | “Usuário” simulado que executa sua função default em loop. |
options | Duração do teste, número de VUs, stages (rampas), limites, etc. |
http.get / http.post | Requisiçõ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édia ≈ 89 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étrica | O que ela te conta |
|---|---|
| Média | Um número só, mistura rápidas e lentas; outliers distorcem fácil. |
| p90 / p95 | Onde 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 é:
- InfluxDB 1.x recebendo pontos em tempo real do k6.
- 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:
docker compose up -d- Subir a API que você vai testar.
- Rodar o k6 com
-o influxdb=.... - Abrir o Grafana e importar um dashboard da comunidade. O ID 2587 (k6 Load Testing Results) é muito usado com InfluxDB.
- 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.