Alejandría

Busca en Alejandría

Herramientas

Grafana k6

Pruebas de carga y rendimiento escritas como código JavaScript, con umbrales que fallan el pipeline.

01

En pocas palabras

Herramienta open source de Grafana Labs para pruebas de carga, estrés y soak, con scripts en JavaScript, escenarios configurables y umbrales automáticos.

Qué problema resuelve

Saber cuánta carga soporta un servicio solo cuando falla en producción, o pruebas de carga manuales que nadie repite.

Cuándo utilizarlo

Antes de campañas, al cambiar infraestructura o como fitness function de rendimiento. Ejemplo: validar que la API de solicitudes aguanta 500 solicitudes por minuto con p95 < 800 ms.

02

De la idea a la práctica

Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.

Tipos de prueba

Tipo Objetivo Forma de la carga
Smoke Verificar que el script y el sistema funcionan 1–2 usuarios, 1 minuto
Load Comportamiento con la carga esperada Rampa hasta el nivel normal
Stress Encontrar el punto de ruptura Rampa por encima del nivel normal
Spike Reacción a picos repentinos Salto brusco y caída
Soak Fugas de memoria y degradación en el tiempo Carga normal durante horas

Ejemplo: carga con tasa de llegada constante

import http from 'k6/http';
import { check } from 'k6';

export const options = {
  scenarios: {
    solicitudes: {
      executor: 'constant-arrival-rate',
      rate: 500,
      timeUnit: '1m',
      duration: '10m',
      preAllocatedVUs: 50,
    },
  },
  thresholds: {
    http_req_failed: ['rate<0.01'],
    http_req_duration: ['p(95)<800'],
  },
};

export default function () {
  const res = http.post(
    `${__ENV.BASE_URL}/v1/solicitudes`,
    JSON.stringify({ monto: 1500000, plazo: 12 }),
    { headers: { 'Content-Type': 'application/json' } },
  );
  check(res, { aceptada: (r) => r.status === 202 });
}
k6 run -e BASE_URL=https://staging.example.com carga-solicitudes.js

Si un umbral no se cumple, k6 termina con código distinto de cero y el pipeline falla.

Modelo abierto frente a cerrado

Los executors de tasa de llegada (constant-arrival-rate, ramping-arrival-rate) generan peticiones a un ritmo fijo aunque el sistema se ralentice, como ocurre con usuarios reales. Los de VUs (constant-vus, ramping-vus) esperan a que termine cada iteración, por lo que un servicio lento recibe automáticamente menos carga y oculta el problema.

Autenticación y datos de prueba

import http from 'k6/http';
import { SharedArray } from 'k6/data';
import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';

const clientes = new SharedArray(
  'clientes',
  () => papaparse.parse(open('./clientes.csv'), { header: true }).data,
);

export function setup() {
  const res = http.post(`${__ENV.BASE_URL}/oauth/token`, {
    grant_type: 'client_credentials',
    client_id: __ENV.CLIENT_ID,
    client_secret: __ENV.CLIENT_SECRET,
  });
  return { token: res.json('access_token') }; // se pasa a cada iteración
}

export default function (datos) {
  const cliente = clientes[Math.floor(Math.random() * clientes.length)];
  http.get(`${__ENV.BASE_URL}/v1/clientes/${cliente.id}/creditos`, {
    headers: { Authorization: `Bearer ${datos.token}` },
    tags: { endpoint: 'creditos-cliente' },
  });
}

SharedArray carga el CSV una vez en memoria compartida entre usuarios virtuales. Usa datos sintéticos y cuentas de prueba, nunca clientes reales.

Mezcla de tráfico realista

export const options = {
  scenarios: {
    consultas: {
      executor: 'constant-arrival-rate',
      rate: 300,
      timeUnit: '1m',
      duration: '15m',
      preAllocatedVUs: 40,
      exec: 'consultar',
    },
    solicitudes: {
      executor: 'ramping-arrival-rate',
      startRate: 20,
      timeUnit: '1m',
      preAllocatedVUs: 30,
      stages: [
        { target: 100, duration: '5m' },
        { target: 100, duration: '10m' },
      ],
      exec: 'solicitar',
    },
  },
  thresholds: {
    'http_req_duration{endpoint:creditos-cliente}': ['p(95)<300'],
    'http_req_duration{endpoint:crear-solicitud}': ['p(95)<800'],
    http_req_failed: ['rate<0.01'],
  },
};

Los umbrales por etiqueta permiten tener objetivos distintos por endpoint, alineados con los SLO.

Leer los resultados

Observación Interpretación
Latencia estable hasta cierta tasa y luego crece rápido Punto de saturación: busca el recurso limitante
dropped_iterations mayor que cero k6 no tuvo VUs suficientes para la tasa pedida
Errores que aparecen tras minutos de carga sostenida Agotamiento de pools, colas o memoria
p99 muy superior al p95 Colas puntuales, GC, bloqueos en base de datos

Correlaciona siempre con métricas del sistema bajo prueba (CPU, conexiones, GC, trazas) durante la misma ventana.

Ejecución distribuida y resultados

k6 run -o experimental-prometheus-rw carga.js   # métricas a Prometheus/Mimir para Grafana

Para generar más carga de la que soporta una máquina, el k6 Operator reparte la prueba en varios pods de Kubernetes; Grafana Cloud k6 ofrece lo mismo como servicio y desde varias regiones. También existe una extensión de navegador (k6/browser) para medir rendimiento de frontend con métricas web.

Criterios de implementación

Ejecuta un smoke test en cada pull request y la prueba de carga completa en un entorno representativo de forma programada. Exporta métricas a Prometheus o Grafana Cloud para correlacionarlas con trazas de Grafana Tempo. Deriva los umbrales de escenarios de atributos de calidad y de los SLO, y avisa a los proveedores externos o usa mocks antes de lanzar carga contra ellos.

Continúa en las fuentes

Documentación oficial para verificar detalles y explorar más.