Skip to main content
15 may 2026p95 vs p99 latencia

Por Performate

Latencia P95 vs P99: qué importa de verdad para la confiabilidad de APIs

Cómo los percentiles de latencia resumen riesgo de cola, cuándo p95 gana a p99 para gates y cómo k6 reporta http_req_duration para releases honestos.

El release muestra latencia media de checkout en 180 ms—producto aplaude—pero soporte sigue recibiendo tickets de «pago colgado» en el 1 % peor de sesiones. El promedio oculta colas; p95 marca la latencia por debajo de la cual cae el 95 % de observaciones; p99 marca el 1 % más lento por encima de p95. Para cargas HTTP k6 registra http_req_duration y stats que puedes umbralizar (métricas, thresholds).

En esta guía verás por qué equipos gatean en p95, cuándo p99 (o max) merece atención, cómo configurar umbrales k6 por ruta, errores que invalidan argumentos de percentiles y cómo Performate ayuda a comparar regresiones entre releases.

Consulta también cómo leer reportes de pruebas de carga y cuántos usuarios virtuales: los percentiles solo tienen sentido con muestras suficientes y parámetros de escenario estables.

Por qué el promedio miente en APIs bajo carga

Bajo concurrencia, latencia suele ser de cola: unos requests pasan rápido, otros esperan pool de DB, GC o locks. El promedio mezcla ambos mundos en un número cómodo para slides pero inútil para SLOs. Los percentiles responden preguntas distintas:

  • p95: «¿Qué vio la gran mayoría, incluidos momentos moderadamente malos?»
  • p99: «¿Qué tan mal puede ir para el 1 % peor típico?»
  • max: outlier extremo—útil para debug, ruidoso como gate único.

Piensa en p95 como clima habitual y p99 como la tormenta que aún ocurre varias veces al día en tráfico alto.

Por qué equipos gatean en p95

  • Señal vs ruido: p95 se mueve cuando la experiencia típica degrada pero es menos volátil que p99 en corridas cortas.
  • Costo de ingeniería: apretar latencia de cola suele costar esfuerzo no lineal; gates p95 detectan regresiones temprano sin perseguir cada outlier.
  • Claridad con stakeholders: «95 % de requests más rápidos que X ms» alinea fácil con expectativas de producto (throughput vs latencia).

Cuándo p99 (o max) merece atención

  • Flujos safety-critical o de pago donde lentitud rara equivale a riesgo de revenue o compliance.
  • Ventanas de muestra chicas donde p95 se ve bien pero un servicio dependiente se estanca a veces—picos p99 lo revelan.
  • Sistemas con autoscaling o colas donde latencia de cola predice saturación antes de que p95 se mueva.
  • Migraciones multi-versión donde divergencia en colas importa al SLO (versionado API bajo carga).

Los libros SRE de Google enfatizan alinear SLIs con dolor de usuario; burn rates multi-ventana a menudo combinan señales sensibles a cola con presupuesto (SRE workbook).

Implementación práctica con k6: umbrales por ruta

No uses un solo http_req_duration global cuando endpoints difieren en magnitud y criticidad. Umbraliza rutas etiquetadas y combina latencia con tasa de error.

Script de ejemplo (ilustrativo—no es una prueba lista para producción).

Qué demuestra este ejemplo:

  • Umbrales p95 y p99 en la misma ruta crítica.
  • Tags route:* para evitar mezclar checkout con health checks.
  • Error rate junto a latencia—«rápido pero wrong» no pasa.
import http from 'k6/http';
import { check, sleep } from 'k6';

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

export const options = {
  scenarios: {
    checkout: {
      executor: 'constant-arrival-rate',
      rate: 30,
      timeUnit: '1s',
      duration: '5m',
      preAllocatedVUs: 15,
      maxVUs: 60,
      exec: 'hitCheckout',
      tags: { route: 'checkout' },
    },
  },
  thresholds: {
    'http_req_duration{route:checkout}': ['p(95)<500', 'p(99)<1200'],
    'http_req_failed{route:checkout}': ['rate<0.01'],
    http_req_failed: ['rate<0.01'],
  },
};

export function hitCheckout() {
  const res = http.post(
    `${BASE}/checkout`,
    JSON.stringify({ sku: 'SKU-100', qty: 1 }),
    {
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${__ENV.TOKEN}`,
      },
      tags: { route: 'checkout' },
    }
  );
  check(res, { 'checkout 2xx': (r) => r.status >= 200 && r.status < 300 });
  sleep(0.3);
}

Tip pro (comando de ejemplo):

k6 run checkout.js --summary-trend-stats="p(95),p(99),max"

Qué demuestra este comando: el summary imprime p95, p99 y max para comparar builds cuando también pasas git_sha vía tags o variables de entorno.

Patrones que funcionan

  • Iteraciones altas estabilizan percentiles; micro-runs producen colas ruidosas.
  • Segmenta por tags alineados a APM (observabilidad k6).
  • Pair latencia con checks e http_req_failed—ver ejemplos de umbrales.

Anti-patrones a evitar

  • Comparar p95 entre corridas con distinto número de VUs o duración sin anotar drift de escenario.
  • Interpretar colas en staging caliente como prod frío.
  • Ignorar coordinated omission: si k6 bloquea más cuando el sistema está lento, existe sesgo de medición—revisa scenarios para análisis estricto.

Marco de decisión: qué percentil gatear

SituaciónGate recomendado
API general, releases frecuentesp95 por ruta + error rate
Checkout / pagos / auth críticap95 y p99 en rutas críticas
Canary post-deployDelta p99 vs baseline (canary)
Corridas cortas en CIp95 conservador; p99 solo con muestra suficiente
Presentación a ejecutivosp95 como headline; p99 como cola de riesgo

Usa p95 como gate principal si buscas señal estable en CI y releases frecuentes.

Añade p99 si el dolor de usuario vive en colas raras pero repetibles en tráfico alto.

Evita max como único gate salvo debug—demasiado volátil para política de release.

Errores que invalidan argumentos de percentiles

  • Declarar éxito porque la media bajó mientras p99 explotó.
  • Mezclar rutas rápidas y lentas en un threshold global.
  • Correr 30 segundos y debatir p99 como si fuera prod de Black Friday.
  • Olvidar que presupuesto frontend + API exige percentiles en ambos lados.

Cómo Performate ayuda con visibilidad de regresión

Performate ayuda a almacenar corridas comparables y resultados de umbrales para que shifts de p95/p99 aparezcan junto a metadata de release—donde hojas de cálculo y exports ad hoc suelen perder contexto.

Ejemplo: comparar p95/p99 entre builds

  1. Define umbrales p95/p99 en el editor de escenario. Problema resuelto: gates explícitos, no debate post-hoc.
  2. Corre baseline pre-release y candidato en el mismo workspace. Problema resuelto: mismos tags y executors entre comparaciones.
  3. Abre vista de comparación filtrada por route:checkout. Problema resuelto: QA y backend ven divergencia de cola en un export.
  4. Exporta JSON + script k6 para CI (CI/CD). Problema resuelto: historial auditables por git SHA.

Cierre

p95 y p99 no compiten—responden preguntas distintas sobre la misma cola. Gatea en p95 para señal estable en el día a día; vigila p99 donde la lentitud rara duele de verdad al negocio.

En la próxima revisión de release, trae p95 y p99 de la ruta que más tickets genera—y anota si la media contaba una historia distinta.

Try Performate free | Book a demo | k6 metrics reference

¿Listo para optimizar el rendimiento de tu API?

Sigue umbrales p95 y p99 en Performate y compara regresiones antes del release.

← Volver a todas las entradas