Saltar al contenido principal
26 oct 2026taxonomia errores prueba carga

Por Lucas Yoris · Performate

Taxonomía de errores en pruebas de carga: timeouts, resets, ráfagas 5xx y drops del lado cliente

Taxonomía de errores en pruebas de carga: timeouts, resets, ráfagas 5xx—clasifica señales http_req_failed de k6 antes de afinar el timeout equivocado.

El equipo subió el timeout de k6 de 30s a 120s y el job pasó en verde—mientras producción seguía devolviendo 503 en ráfagas porque el pool de conexiones estaba agotado. Afinar el knob equivocado es el costo de no clasificar errores antes de leer un gráfico de latencia.

La taxonomía de errores en pruebas de carga no es academicismo. Es el marco que separa misconfig del cliente, red transitoria, fallos de aplicación y cuotas de dependencias—para que el siguiente cambio sea auth, pool, código o límite de tasa, no «más timeout». En esta guía verás buckets accionables, cómo mapearlos a métricas de k6, y qué exportar para que postmortems y narrativas de IA no mezclen resets con 5xx.

Por qué http_req_failed solo no basta

k6 agrega http_req_failed cuando el status no es 2xx o hay error de red. Eso mezcla:

  • 401/403 por token expirado en setup() mal escrito.
  • 0 status por timeout o reset TCP.
  • 502/503 por saturación o dependencia caída.
  • 429 por rate limit—a veces esperado, a veces incidente.

Un 0,5 % plano de errores puede ser 100 % timeouts en checkout mientras health está verde. Sin buckets, optimizas latencia de una ruta que en realidad ni completa requests.

Combina taxonomía con cómo leer reportes de pruebas de carga y el runbook para depurar una prueba fallida.

Cuando la latencia mejora pero el negocio empeora

Bajar errores subiendo timeout solo oculta saturación: el usuario sigue esperando. Clasifica primero; luego decide si el SLO es tiempo, tasa de éxito o ambos—ver p95 vs p99 en latencia.

Tabla de taxonomía: señales y siguiente paso

CategoríaSeñales típicas en k6Próximo paso
Misconfig del clienteRáfagas 401/403 al inicio o tras N minAuth, rotación de secretos—OAuth y API keys en k6
Red / transitoriostatus=0, timeouts, resetsProxies, TLS, MTU, ingress—Kubernetes e ingress
Aplicación 5xx500/502/503 correlados con RPSProfiling, pools—análisis de cuellos de botella API
Cuotas / dependenciaPatrones 429, 503 con body de vendorCuotas coordinadas—límites de tasa y throttling
Negocio / dominio200 con check fallidoAserciones de dominio, no solo HTTP

Documenta el bucket dominante en el título del informe («incidente: pool agotado», no «inestabilidad»).

Implementación práctica con k6: checks, tags y export

Script de ejemplo (ilustrativo).

Qué demuestra este ejemplo:

  • Checks que separan rate limit de éxito.
  • Tags route y error_class derivados del status para thresholds segmentados.
  • Threshold en http_req_failed más checks explícitos para 429.
import http from 'k6/http';
import { check } from 'k6';

const BASE = __ENV.BASE_URL || 'https://staging.example.com';

function errorClass(res) {
  if (res.status === 0) return 'network';
  if (res.status === 401 || res.status === 403) return 'auth';
  if (res.status === 429) return 'quota';
  if (res.status >= 500) return 'server';
  if (res.status >= 400) return 'client';
  return 'ok';
}

export const options = {
  scenarios: {
    api: {
      executor: 'constant-arrival-rate',
      rate: 10,
      timeUnit: '1s',
      duration: '3m',
      preAllocatedVUs: 15,
      maxVUs: 60,
      exec: 'hitCheckout',
    },
  },
  thresholds: {
    http_req_failed: ['rate<0.02'],
    'http_req_failed{route:checkout}': ['rate<0.01'],
  },
};

export function hitCheckout() {
  const res = http.post(
    `${BASE}/checkout`,
    JSON.stringify({ sku: 'SKU-1', qty: 1 }),
    {
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${__ENV.API_TOKEN}`,
      },
      tags: { route: 'checkout' },
      timeout: '30s',
    },
  );

  const ec = errorClass(res);
  // En informes, agrupa por ec (auth|server|quota|network) exportando CSV o custom metrics

  check(res, {
    'not auth failure': (r) => r.status !== 401 && r.status !== 403,
    'not rate limited': (r) => r.status !== 429,
    'checkout 2xx': (r) => r.status >= 200 && r.status < 300,
  });
}

Patrones que funcionan

  • Exporta CSV o JSON de k6 y etiqueta post-corrida si necesitas análisis offline (métricas k6).
  • Umbrales por error_class o por route—no un solo porcentaje global.
  • En CI smoke, falla rápido en auth antes de quemar minutos de carga inútil.
  • Pide a narrativas de IA que usen el vocabulario del bucket—ver narrativas IA y métricas tradicionales k6.

Anti-patrones

  • Subir timeout hasta que http_req_failed sea cero.
  • Tratar 429 como 5xx en política de producto sin documentar expectativa.
  • Ignorar check fallidos con HTTP 200 (pagos, inventario).

Pro tip (comando de ejemplo):

k6 run taxonomy-checkout.js --summary-export=summary.json \
  --summary-trend-stats="p(95),p(99)"

Qué demuestra este comando: conserva percentiles y tasas de fallo en un artefacto que puedes diff entre builds junto a la clase de error dominante anotada en el PR.

Marco de decisión: qué knob girar

DominanteNo hagas primeroHaz primero
authSubir VUsArreglar setup(), secretos CI—entornos k6
networkOptimizar SQLIngress, TLS, red del runner
serverBajar timeoutTraces APM, pools, dependencias
quotaStress sin topeAcuerdo de RPM, escenario a menor RPS
ok HTTP + check failCelebrar verdeAserciones de negocio, datos de prueba

Checklist antes del postmortem

  • ¿Cuál bucket supera el 50 % de fallos?
  • ¿Los fallos correlacionan con una ruta (route tag) o son globales?
  • ¿Hubo cambio de secretos o TTL de token en la ventana del test?
  • ¿429 es esperado por diseño o regresión de cuota?
  • ¿El informe nombra la clase de error en el título?

Cómo Performate mantiene el debate en evidencia compartida

Los debates en spreadsheet frenan fixes cuando los equipos exportan artefactos incompatibles. Abajo hay un ejemplo concreto de flujo para la clasificación de fallos de la API de orders de arriba.

Ejemplo: clasificar fallos de la API orders en un reporte

  1. Importa el request GET de orders desde Postman con la misma auth que usa QA. Problema resuelto: elimina desajustes de auth «funciona en Postman, falla en k6» antes de empezar la taxonomía.
  2. Crea escenario constant-arrival-rate a 25 req/s durante cinco minutos. Problema resuelto: volumen suficiente para que las familias de fallo se separen estadísticamente.
  3. Añade checks para 2xx, fallos de auth y 5xx en el panel de escenario—refleja la intención de clasificación del script. Problema resuelto: no ingenieros ven la mezcla de fallos en el reporte integrado, no output crudo de CLI.
  4. Aplica tag route:orders en todos los pasos. Problema resuelto: umbrales filtrados coinciden con el modelo k6 de arriba.
  5. Corre, exporta resumen y comparte con backend y plataforma—etiqueta explícitamente ráfagas 502 vs picos 401. Problema resuelto: debates de taxonomía usan un artefacto; on-call abre la sección correcta del runbook al primer intento.
  6. Exporta script k6 con métricas Counter para gates CI en conteo errors_5xx. Problema resuelto: pipelines fallan en errores de servidor sin confundir cuota o auth.

Ese flujo conecta directamente con el cta de este post: convertir playbooks de taxonomía en escenarios ejecutables y reportes compartibles—no otra reunión de una hora sobre «¿qué significa failed?».

Cierre

Clasificar errores antes de tunear timeouts convierte pruebas de carga en diagnóstico, no en cosmética verde. Usa checks, tags y umbrales por clase para que el próximo fix apunte al sistema correcto.

En la próxima corrida roja, anota el bucket dominante en la primera línea del informe—si no es obvio en dos minutos, tu script necesita más tags, no más VUs.

Try Performate free | Guides | k6 HTTP debugging

¿Listo para optimizar el rendimiento de tu API?

Usa Performate para convertir este playbook en escenarios k6 ejecutables, umbrales y reportes compartibles sin perder días en código pegamento.

← Volver a todas las entradas