k6: testes de carga e performance em APIs
k6 é uma ferramenta de testes de carga open-source escrita em Go com scripts em JavaScript — próxima do que você já conhece como desenvolvedor Node.js. Com ela você descobre gargalos antes que seus usuários descubram: como a API se comporta com 100 usuários simultâneos? E com 1000? E com um pico súbito de tráfego?
Instalar k6 e primeiro teste
Instalação e script básico de teste de carga:
# Instalar k6:
# macOS:
brew install k6
# Ubuntu/Debian:
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 update && sudo apt install k6
# Docker:
docker run --rm -i grafana/k6 run - < script.js
# Primeiro script (tests/carga/api-basico.js):
import http from 'k6/http'
import { sleep, check } from 'k6'
import { Rate } from 'k6/metrics'
const erros = new Rate('erros')
export const options = {
vus: 10, // 10 virtual users simultâneos
duration: '30s', // por 30 segundos
thresholds: {
http_req_duration: ['p(95)<500'], // 95% das req em < 500ms
http_req_failed: ['rate<0.01'], // menos de 1% de erros
erros: ['rate<0.05'],
},
}
export default function () {
const res = http.get('https://api.seudominio.com.br/api/health')
check(res, {
'status 200': (r) => r.status === 200,
'latência < 200ms': (r) => r.timings.duration < 200,
})
erros.add(res.status !== 200)
sleep(1) // pausar 1s entre iterações (simular comportamento humano)
}Cenários de carga: ramp-up, spike e soak
Diferentes perfis de carga para testar diferentes hipóteses:
// tests/carga/cenarios.js:
import http from 'k6/http'
import { sleep, check } from 'k6'
export const options = {
scenarios: {
// Cenário 1: rampa gradual — simula crescimento de tráfego normal
ramp_up: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '2m', target: 50 }, // subir para 50 VUs em 2min
{ duration: '5m', target: 50 }, // manter 50 VUs por 5min
{ duration: '2m', target: 0 }, // descer para 0
],
},
// Cenário 2: spike — testar resiliência a pico repentino
spike: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '30s', target: 10 }, // carga normal
{ duration: '10s', target: 200 }, // spike súbito!
{ duration: '3m', target: 200 }, // manter o pico
{ duration: '30s', target: 10 }, // voltar ao normal
],
},
// Cenário 3: soak test — resistência a carga sustentada por horas
soak: {
executor: 'ramping-vus',
stages: [
{ duration: '5m', target: 30 }, // aquecimento
{ duration: '2h', target: 30 }, // 2 horas de carga contínua
{ duration: '5m', target: 0 }, // resfriamento
],
},
},
thresholds: {
'http_req_duration{scenario:ramp_up}': ['p(99)<1000'],
'http_req_duration{scenario:spike}': ['p(95)<3000'], // mais tolerante no spike
http_req_failed: ['rate<0.05'],
},
}
export default function () {
const res = http.post(
'https://api.seudominio.com.br/api/auth/login',
JSON.stringify({ email: 'teste@exemplo.com', senha: 'senha-teste' }),
{ headers: { 'Content-Type': 'application/json' } }
)
check(res, { 'login com sucesso': (r) => r.status === 200 })
sleep(Math.random() * 3 + 1) // pausa aleatória de 1-4s (comportamento humano)
}Testar endpoints autenticados e fluxos completos
Scripts para testar fluxos que exigem autenticação JWT:
// tests/carga/fluxo-completo.js:
import http from 'k6/http'
import { check, group, sleep } from 'k6'
import { SharedArray } from 'k6/data'
// Dados de teste pré-carregados (evitar criar usuário a cada iteração):
const usuarios = new SharedArray('usuarios', function () {
return JSON.parse(open('./dados/usuarios-teste.json'))
})
export const options = {
vus: 20,
duration: '5m',
thresholds: {
'http_req_duration{name:login}': ['p(95)<300'],
'http_req_duration{name:listar-pedidos}': ['p(95)<500'],
'http_req_duration{name:criar-pedido}': ['p(95)<1000'],
},
}
export default function () {
const usuario = usuarios[Math.floor(Math.random() * usuarios.length)]
// ── Fase 1: Login ──────────────────────────────────────────────
group('autenticação', () => {
const loginRes = http.post(
'https://api.seudominio.com.br/api/auth/login',
JSON.stringify({ email: usuario.email, senha: usuario.senha }),
{ headers: { 'Content-Type': 'application/json' }, tags: { name: 'login' } }
)
check(loginRes, { 'login OK': (r) => r.status === 200 })
const token = loginRes.json('accessToken') as string
const headers = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }
// ── Fase 2: Navegar pela aplicação ─────────────────────────────
sleep(1)
group('pedidos', () => {
const listRes = http.get(
'https://api.seudominio.com.br/api/v2/pedidos',
{ headers, tags: { name: 'listar-pedidos' } }
)
check(listRes, { 'lista OK': (r) => r.status === 200 })
sleep(Math.random() * 2)
const criarRes = http.post(
'https://api.seudominio.com.br/api/v2/pedidos',
JSON.stringify({ itens: [{ produto_id: usuario.produtoId, quantidade: 1 }] }),
{ headers, tags: { name: 'criar-pedido' } }
)
check(criarRes, { 'pedido criado': (r) => r.status === 201 })
})
})
sleep(Math.random() * 3 + 2)
}Exportar métricas do k6 para Prometheus
Ver métricas de carga em tempo real no Grafana durante o teste:
# k6 pode exportar métricas para Prometheus via remote write:
# k6 com output para Prometheus Remote Write:
K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write k6 run --out experimental-prometheus-rw script.js
# Ou via InfluxDB (mais simples para uso local):
# docker run -p 8086:8086 influxdb:1.8
k6 run --out influxdb=http://localhost:8086/k6 script.js
# Dashboard Grafana para k6 + InfluxDB:
# Importar ID 2587 — k6 Load Testing Results (oficial Grafana)
# Configurar no docker-compose.yml:
services:
influxdb:
image: influxdb:1.8
environment:
INFLUXDB_DB: k6
ports:
- "8086:8086"
grafana:
environment:
GF_DATASOURCES_DEFAULT_TYPE: influxdb
GF_DATASOURCES_DEFAULT_URL: http://influxdb:8086
GF_DATASOURCES_DEFAULT_DATABASE: k6
# Rodar k6 apontando para o InfluxDB do Docker:
docker run --rm -i --network host grafana/k6 run --out influxdb=http://localhost:8086/k6 - < script.jsIntegrar testes de carga no CI/CD
Rodar k6 automaticamente antes de cada deploy em produção:
# .github/workflows/carga.yml:
name: Testes de Carga
on:
push:
branches: [main]
jobs:
k6:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar k6
run: |
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 update && sudo apt install k6
- name: Rodar teste de carga (staging)
run: |
k6 run \
--env BASE_URL=https://staging.seudominio.com.br \
--out json=resultados.json \
tests/carga/api-basico.js
- name: Upload resultados
uses: actions/upload-artifact@v4
if: always()
with:
name: k6-resultados
path: resultados.json$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS para Node.js em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.
Perguntas frequentes
Conteúdos relacionados