Por Performate
Ejemplos de umbrales en k6: alerta sobre las métricas que importan
Patrones concretos de umbrales k6 para percentiles de latencia, tasas de error y métricas custom—y cómo los códigos de salida convierten corridas en puertas de CI.
La corrida terminó con p(99)=2.1s y nadie sabe si eso es pass o fail. El equipo debate el gráfico veinte minutos, mergea igual, y el viernes producción viola el SLO que «visualmente se veía bien» en staging.
Los umbrales en k6 convierten la salida de interesante a accionable: definen pass/fail sobre métricas agregadas, fijan el código de salida al violarlos, y cablean pruebas de carga como puertas reales en CI. En esta guía verás patrones concretos para latencia global, rutas por tag, métricas custom y abort temprano—y cómo interpretar fallos sin confundir saturación con bugs funcionales.
Por qué los umbrales cambian decisiones—no solo reportes
A nivel visual, un gráfico de latencia siempre « cuenta una historia ». Sin criterios explícitos:
- Debate sin cierre —
p95en 380 ms puede ser victoria o desastre según el endpoint; sin número acordado, gana la intuición. - Agregación engañosa — mezclar checkout lento y catálogo rápido en un solo
http_req_durationoculta regresiones en el camino crítico. - Errores vs latencia — HTTP 200 con body de error de negocio pasa checks de status pero viola conversión; hace falta métricas custom.
- CI sin dientes — k6 exit code 0 con umbrales vacíos = pipeline verde que no protege releases.
Lee p95 vs p99 latencia antes de elegir percentiles, y pruebas de carga en CI/CD al cablear fallos en pipelines (thresholds documentation).
Implementación práctica con k6: umbrales globales, por tag y abortOnFail
Combina umbrales globales para smoke, filtros por tag para rutas críticas, y abortOnFail cuando el sistema ya está derretido.
Script de ejemplo (ilustrativo—no es una prueba lista para producción). El snippet usa URLs, SLO y tags ficticios. Adapta base URL, auth y límites a tu entorno.
Qué demuestra este ejemplo:
- Patrón A — global:
http_req_durationyhttp_req_failedpara smoke de salud general. - Patrón B — por ruta: umbrales en
http_req_duration{route:checkout}más estrictos que catálogo. - Patrón C — custom:
Ratesobre errores de negocio devueltos como HTTP 200. - Patrón D — abort:
abortOnFailen error rate evita quemar staging 30 minutos cuando ya falló.
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate } from 'k6/metrics';
const BASE = __ENV.API_BASE || 'https://staging.example.com';
const businessErrors = new Rate('business_errors');
export const options = {
scenarios: {
mixed_routes: {
executor: 'constant-arrival-rate',
rate: 40,
timeUnit: '1s',
duration: '5m',
preAllocatedVUs: 20,
maxVUs: 80,
exec: 'mixedFlow',
},
},
thresholds: {
// Patrón A: global
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01', { abortOnFail: true, delayAbortEval: '30s' }],
// Patrón B: por tag de ruta
'http_req_duration{route:checkout}': ['p(95)<700', 'p(99)<1200'],
'http_req_duration{route:catalog}': ['p(95)<250'],
// Patrón C: métrica custom
business_errors: ['rate<0.005'],
},
};
export function mixedFlow() {
const headers = { Authorization: `Bearer ${__ENV.TOKEN}` };
const catalog = http.get(`${BASE}/v1/catalog?page=1`, {
headers,
tags: { route: 'catalog' },
});
check(catalog, { 'catalog 2xx': (r) => r.status === 200 });
const checkout = http.post(
`${BASE}/v1/checkout`,
JSON.stringify({ sku: 'SKU-100', qty: 1 }),
{ headers, tags: { route: 'checkout' } }
);
const ok = check(checkout, { 'checkout 2xx': (r) => r.status >= 200 && r.status < 300 });
if (ok && checkout.json('errorCode') !== undefined) {
businessErrors.add(1);
} else {
businessErrors.add(0);
}
sleep(0.2);
}
Patrones que funcionan
- Tags en requests —
tags: { route: 'checkout' }alimenta umbrales filtrados (HTTP metrics). - Checks + thresholds — checks validan corrección por iteración; thresholds agregan pass/fail (checks).
abortOnFailcon delay — para suites largas, aborta tras ventana inicial si error rate explota.- Percentiles distintos por criticidad — checkout con
p99; catálogo solop95.
Anti-patrones a evitar
- Un solo umbral global cuando un script mezcla rutas con SLO de órdenes de magnitud distintos.
- Umbrales copiados de prod en smoke de CI—demasiado estrictos generan flaky pipelines.
- Ignorar
http_req_failedcuando la red de staging es ruidosa—ajusta tolerancia o segmenta por entorno.
Tip pro (comando de ejemplo):
k6 run mixed-routes.js; echo "exit code: $?"
Qué demuestra este comando: el exit code de k6 refleja violación de umbrales—exactamente lo que CI debe evaluar, no solo logs bonitos.
Marco de decisión: qué umbral para qué pregunta
| Situación | Acción recomendada |
|---|---|
| Smoke CI post-merge | Global p(95) + http_req_failed; duración corta |
| Ruta crítica (checkout, pago) | Umbrales por tag; incluye p(99) |
| Errores de negocio en HTTP 200 | Métrica custom Rate + threshold |
| Suite larga en staging saturado | abortOnFail en error rate tras 30–60 s |
| Regresión entre releases | Mismos umbrales + git SHA archivado (línea base) |
Usa umbrales globales si el script golpea una sola ruta homogénea.
Usa filtros por tag si mezclas checkout y catálogo—or any SLO distinto por superficie.
Usa abortOnFail si continuar la corrida no aporta señal—solo consume staging y tiempo.
Observabilidad, documentación y siguientes pasos
Los umbrales solo sirven si el equipo acordó los números. Antes de cablear CI:
- Documenta SLO fuente (contrato interno, error budget) junto a cada threshold en el script o wiki.
- Revisa si
p95op99es la puerta correcta por ruta (p95 vs p99). - Define política para staging flaky—retry vs umbral relajado vs segmentación por entorno.
- Archiva summary JSON con resultado pass/fail por threshold en cada release.
- Correlaciona fallos de latencia con telemetría de servidor (análisis de cuellos).
Cómo Performate simplifica umbrales sin copy-paste entre laptops
Umbrales divergentes entre el script de Ana y el de Bob producen CI inconsistente. Abajo hay un ejemplo concreto de flujo para checkout + catálogo con SLO distintos.
Ejemplo: umbrales por ruta en un escenario mixto
- Importa requests de catálogo y checkout en un solo escenario de flujo. Problema resuelto: un script, dos superficies—sin duplicar options blocks.
- Asigna tags
route:catalogyroute:checkouten el panel de escenario. Problema resuelto: segmentación alineada al ejemplo k6 sin editar JS. - Define umbrales visuales: catálogo
p(95)<250, checkoutp(95)<700yp(99)<1200. Problema resuelto: QA y backend ven los mismos números acordados. - Corre contra staging y revisa pass/fail por threshold en el reporte integrado—not solo gráficos. Problema resuelto: decisiones de merge basadas en criterios, no en vibes.
- Compara con corrida anterior en vista de comparación para detectar regresión de cola. Problema resuelto: línea base visible sin spreadsheets manuales.
- Exporta script k6 con thresholds para gate en CI (pruebas de carga en CI/CD).
Ese flujo conecta directo con el cta de este post: definir y comparar resultados de umbrales más rápido con escenarios y reportes alineados.
Cierre
El riesgo de release sin umbrales es un problema de criterio, no de tooling. Define pass/fail antes de correr, segmenta rutas críticas por tag, y trata el exit code de k6 como la puerta que CI necesita.
Acordá los números de checkout y catálogo en tu próximo planning—y cablea al menos un threshold de error rate con abortOnFail antes del próximo merge a main.
¿Listo para optimizar el rendimiento de tu API?
Define y compara resultados de umbrales más rápido con escenarios y reportes en Performate.