Módulo 3: Métricas — latencia, throughput y errores
1. Presentación del módulo: el tablero de la prueba
Descripción
En los dos primeros módulos aprendiste dos cosas grandes. En el módulo 1, que "aguanta" es una pregunta distinta de "funciona", y que se responde midiendo. En el módulo 2, cómo se escribe un script de k6 y cómo un puñado de VUs —usuarios virtuales, hilos que golpean la API en paralelo— generan tráfico contra Reservo. Sabes generar carga. Lo que todavía no sabes es leer lo que esa carga produce, y sin eso una prueba de carga no vale nada. Una corrida de k6 termina y escupe una pantalla de números; si no sabes qué significa cada uno, tienes ruido, no información. Este módulo te enseña a leer el tablero.
El tablero de una prueba de carga tiene exactamente tres instrumentos, y este módulo instala uno por uno. El primero es la latencia: cuánto tarda cada petición. Parece simple, pero esconde la trampa más común de todo el performance testing —mirar el promedio—, y buena parte del módulo es enseñarte a mirar en su lugar los percentiles (p50, p90, p95, p99). El segundo es el throughput: cuántas peticiones por segundo procesa el sistema (RPS), y cómo se relaciona con cuántos VUs lanzas. El tercero es la tasa de error: qué porcentaje de peticiones falló, la métrica que puede tirar a la basura una latencia bajísima. Latencia, throughput, errores. Con esos tres números, leídos bien, sabes casi todo lo que una prueba de carga tiene que decirte.
Conexión con el módulo: esta lección es el mapa. No calcula todavía ningún percentil ni levanta el generador —eso empieza en la lección 2 y no para hasta el proyecto de la 8—. Lo que instala aquí es la estructura: las tres familias de métricas, en qué lección vive cada una, y dos decisiones de infraestructura que hacen posible el módulo. Porque Reservo corre en localhost y es rapidísima, si midiéramos su /quote normal el p95 saldría en fracciones de milisegundo y no verías la lección del promedio-vs-cola con fuerza. Por eso este módulo declara —lo dice abiertamente— dos endpoints extra sobre la API canónica: uno lento con cola larga (para ver un p95 alto de verdad) y uno flaky que falla de vez en cuando (para ver una tasa de error de verdad). La API canónica no cambia; solo se le añaden dos endpoints de laboratorio, y esta lección explica cuáles y por qué.
La honestidad de siempre, porque marca el tono: los números que vas a ver medidos son medidos. El generador de carga en Python golpea Reservo de verdad, cronometra cada petición de verdad, y statistics.quantiles calcula los percentiles de verdad —los ejecuté antes de escribir esta guía y verás la salida real de la terminal—. Lo único que va como contenido rotulado es el resumen de k6 run, porque k6 es un binario que no está instalado aquí; ese bloque es fiel al formato oficial de k6, pero nunca te lo presentaremos como si lo hubiéramos ejecutado.
El tablero de un coche: tres instrumentos, no uno
Piensa en el tablero de un coche cuando vas por carretera. Si solo pudieras mirar un instrumento, ¿cuál elegirías? Casi todo el mundo dice "el velocímetro". Pero el velocímetro solo te dice qué tan rápido vas; no te dice si el motor está a punto de fundirse (eso es el termómetro), ni cuánto te queda de gasolina (el indicador de combustible), ni si algo se rompió (los testigos de avería). Un conductor que solo mira el velocímetro llega rapidísimo... hasta que se queda sin gasolina en medio de la nada, o funde el motor. La velocidad sola miente por omisión: es un número real, pero incompleto.
Una prueba de carga tiene el mismo problema, y por eso también tiene tres instrumentos. La latencia es el velocímetro: te dice qué tan rápido responde el sistema. El throughput es el cuentakilómetros de flujo: cuántas peticiones por segundo estás procesando. Y la tasa de error son los testigos de avería: cuántas peticiones se rompieron por el camino. Mirar solo uno de los tres te engaña igual que al conductor. Una API con latencia bajísima pero 30% de errores es un coche que va volando... con el motor en llamas. Una API con throughput altísimo pero un p95 de ocho segundos es un coche que mueve mucha carga... pero cada entrega llega tardísimo. Necesitas los tres números, y necesitas leerlos juntos.
Fíjate en que el instrumento más traicionero es la latencia, y no porque sea difícil de medir, sino porque es fácil de resumir mal. Si a alguien le preguntas "¿cuánto tarda tu API?", casi siempre responde con un promedio: "unos 30 milisegundos". Y el promedio, en latencias, es como decirle a un pasajero "de media vamos cómodos" cuando el coche pega frenazos brutales cada dos minutos: técnicamente cierto, humanamente falso. La mitad central de este módulo es desmontar esa trampa y enseñarte a mirar percentiles, que sí cuentan la verdad de lo que vive cada usuario.
Una prueba de carga tiene tres familias de métricas: latencia (¿qué tan rápido?), throughput (¿cuánto volumen?) y tasa de error (¿cuánto se rompió?). Se leen juntas: cualquiera de las tres, sola, engaña. Y la latencia, en particular, jamás se resume con el promedio —se mira en percentiles—.
Las tres familias de métricas, y su nombre en k6
Cada una de las tres familias tiene un nombre concreto en el resumen de k6. Los presento aquí en una tabla para que tengas el mapa completo desde el minuto uno; cada lección desarrolla una fila.
| Familia | Pregunta que responde | Métrica en k6 | La ves ejecutada en |
|---|---|---|---|
| Latencia | ¿Qué tan rápido responde cada petición? | http_req_duration (avg/med/p90/p95…) | Generador Python (lecciones 2, 3, 7) |
| Throughput | ¿Cuántas peticiones por segundo procesa? | http_reqs (total + /s), iterations | Generador Python (lección 4) |
| Tasa de error | ¿Qué porcentaje de peticiones falló? | http_req_failed (% de fallidas) | Generador Python (lección 5) |
Las tres se calculan sobre lo mismo: una lista de peticiones, cada una con su latencia medida y su resultado (éxito o fallo). El generador de Python que ya conoces del módulo 1 lanza N peticiones concurrentes, guarda la latencia de cada una y si fue exitosa, y de esa lista sale todo: los percentiles de latencia, el RPS (dividir el total entre el tiempo de reloj) y la tasa de error (contar las fallidas). k6 hace exactamente lo mismo, industrializado y a mayor escala. Que puedas calcular las tres métricas con veinte líneas de Python es la mejor prueba de que no son magia: son estadística básica sobre una lista de números.
Las dos declaraciones de este módulo: un endpoint lento y uno flaky
Aquí está la decisión de infraestructura que hace posible el módulo, y la declaro con todas las letras porque la regla de la guía es no esconder nada. La API canónica de Reservo —GET /rooms, POST /quote, POST /book— no cambia: sigue devolviendo 7500 para Focus/basic/3h y 6000 para Focus/pro/3h, idéntica a como la conociste en el módulo 1. Pero Reservo corre en localhost y es tan rápida que su /quote responde en fracciones de milisegundo. Con esos números, la lección más importante del módulo —"el promedio esconde la cola"— saldría desdibujada, porque casi no hay cola que esconder.
Así que este módulo añade dos endpoints de laboratorio al mismo servidor, y los usa solo para poder medir fenómenos que en el /quote real serían invisibles:
| Endpoint declarado | Qué hace | Para qué lo usamos |
|---|---|---|
POST /quote_slow | Calcula el mismo precio que /quote, pero simula una dependencia lenta: el 90% de las peticiones responde rápido y ~10% sufre un pico grande (una cola larga). | Ver un p95/p99 alto de verdad y la diferencia entre promedio y percentiles (lecciones 2, 3, 7). |
POST /quote_flaky | Calcula el mismo precio y responde rápido, pero ~10% de las veces devuelve un error 500 en lugar del precio. | Ver una tasa de error de verdad y por qué latencia baja + errores = fracaso (lección 5). |
Los dos son honestos sobre lo que son: simulaciones. Una API de producción tendría una cola larga porque su base de datos a veces tarda, y errores porque a veces un servicio del que depende se cae. Reservo no tiene ni base de datos ni dependencias, así que las fabricamos de la forma más simple posible (un sleep con cola, un 500 aleatorio) para que puedas practicar a medir e interpretar esos fenómenos con datos reales. La técnica que aprendas —calcular el p95 de una distribución con cola, leer una tasa de error— es idéntica contra una API de verdad; solo cambia el origen de la lentitud y de los fallos.
El mapa de las ocho lecciones
Este módulo va de entender qué es cada métrica a calcularla de verdad a leerla en el resumen de k6 a ponerlo todo junto sobre Reservo. Cada lección deja una pieza:
| Lección | Qué instala |
|---|---|
| 1. Presentación (esta) | Las tres familias de métricas; los dos endpoints declarados; el mapa |
| 2. Latencia y percentiles | Qué es la latencia, su anatomía, cliente vs servidor, por qué no el promedio |
| 3. p50/p90/p95/p99 | Los cuatro percentiles y cómo calcularlos con statistics.quantiles |
| 4. Throughput/RPS y VUs | El RPS, su relación con los VUs y el think time (la ley de Little) |
| 5. La tasa de error | http_req_failed, y por qué latencia baja + errores = fracaso |
| 6. Leer el resumen de k6 | El bloque de k6 run línea por línea (contenido rotulado) |
| 7. Promedio vs p95 | El clímax: la cola, con números medidos, y las SLO en percentiles |
| 8. Mini-proyecto | Medir las métricas de Reservo con tus manos e interpretarlas |
Y en la guía entera, este módulo es la bisagra. Los módulos 1 y 2 te dieron el porqué y la herramienta; los módulos 4 en adelante te enseñan a usar las métricas para decidir. En el módulo 4 modelas perfiles de carga (stages, rampas) y observas cómo cambia el p95 al variar la forma de la carga —pero para leer ese cambio, primero tienes que saber qué es el p95, y eso lo instalas aquí—. En el módulo 5 pones thresholds: umbrales sobre estas mismas métricas (p(95)<500, rate<0.01) que hacen la prueba pasar o fallar —pero un threshold es un umbral sobre una métrica, así que no tiene sentido hasta que la métrica es tuya—. En el 6 verificas la corrección bajo carga con check(); en el 7 analizas y corres en CI. Todo lo que viene se apoya en que sepas leer latencia, throughput y errores. Este es el módulo que te da los ojos.
La frontera: qué es de este módulo y qué de los siguientes
Para que no mezcles, aquí está la línea exacta entre este módulo y lo que viene, porque es fácil adelantarse:
| Tema | Dónde vive | Por qué no aquí |
|---|---|---|
| Qué son las métricas y cómo se calculan/leen | Este módulo (3) | — |
| La anatomía del script y los VUs | Módulo 2 (ya visto) | Aquí los reusamos, no los reexplicamos |
| Perfiles de carga: stages, rampas, spikes | Módulo 4 | Cómo varía la carga en el tiempo; aquí la carga es fija y medimos |
| Thresholds: umbrales que hacen pasar/fallar | Módulo 5 | Un threshold es un umbral sobre estas métricas; primero la métrica |
| Checks y correlación (cotizar→reservar) | Módulo 6 | Verificar corrección bajo carga; aquí medimos rendimiento |
| Analizar tendencias y correr en CI | Módulo 7 | El "después" de tener las métricas |
La regla mecánica: si la pregunta es "¿qué significa este número y cómo lo saco?" —un p95, un RPS, una tasa de error—, es este módulo. Si es "¿cómo hago que la carga suba y baje?", es el 4. Si es "¿cómo hago que la prueba falle cuando el p95 pasa de 500 ms?", es el 5. Aquí nos quedamos en entender y calcular; usar las métricas para decidir viene después.
Errores comunes
Reportar una prueba de carga con un solo número. Qué pasa: alguien corre k6 y resume "la API va a 30 ms". ¿30 ms qué? ¿El promedio? ¿El p95? ¿Con cuántos VUs? ¿Cuántos errores hubo? Por qué pasa: se trata la latencia como si fuera un dato único, cuando es una distribución con muchas caras. Cómo detectarlo: si tu reporte cabe en un número, te falta información. Cómo corregirlo: reporta siempre las tres familias —latencia (con al menos p50 y p95), throughput (RPS) y tasa de error— y el contexto (cuántos VUs). Un número solo no es un reporte de carga.
Ignorar la tasa de error porque "la latencia se ve bien". Qué pasa: la prueba muestra un p95 de 10 ms, precioso, y se declara la API sanísima —sin notar que el 10% de las peticiones devolvió 500—. Por qué pasa: la latencia es el instrumento más vistoso y roba la atención; la tasa de error se lee de reojo. Cómo detectarlo: si nunca miraste http_req_failed, tu veredicto de "rápida" no vale. Una petición que falla rápido sigue siendo una petición que falló. Cómo corregirlo: lee siempre la tasa de error antes de celebrar la latencia. Lo verás con dureza en la lección 5, con el endpoint flaky: 10 ms de p95 y 10% de error es un fracaso, no un éxito.
Creer que los endpoints lento y flaky son "trampa" o "datos inventados". Qué pasa: alguien ve /quote_slow y piensa que estamos maquillando los números. Por qué pasa: confunde simular un fenómeno con inventar una medición. Cómo detectarlo: la pregunta correcta no es "¿es real la lentitud?" sino "¿es real la medición de esa lentitud?". Cómo corregirlo: entiende la distinción. La lentitud está simulada con un sleep (declarado); pero el p95 que el generador calcula sobre esas latencias es una medición real de una distribución real. En producción la lentitud vendría de una base de datos en vez de un sleep, y la medirías exactamente igual. Simular la causa para poder practicar la medición es legítimo y está declarado; fabricar el resultado sin medir no lo sería, y no lo hacemos.
Ejercicios
Ejercicio 1 — ¿Qué familia de métrica responde cada pregunta? Para cada pregunta sobre Reservo bajo carga, di si la responde la latencia, el throughput o la tasa de error, y nombra la métrica de k6 correspondiente. (a) "¿Cuántas cotizaciones por segundo procesa la API?" (b) "El 95% de los usuarios, ¿en cuánto tiempo recibió su precio?" (c) "¿Qué porcentaje de reservas devolvió un error 500?" (d) "¿Cuánto tardó la petición más lenta?"
Ver solución
- (a) Throughput. Peticiones por segundo es exactamente RPS; en k6,
http_reqs(que se reporta como total y como tasa/s). - (b) Latencia. "El 95% recibió su precio en X tiempo o menos" es el p95 de la latencia; en k6, la columna
p(95)dehttp_req_duration. - (c) Tasa de error. El porcentaje de peticiones fallidas es
http_req_faileden k6. - (d) Latencia. La petición más lenta es el máximo de la latencia; en k6, la columna
maxdehttp_req_duration.
La regla: "por segundo" → throughput; "cuánto tardó" (un percentil, el max, la mediana) → latencia; "qué porcentaje falló" → tasa de error.
Ejercicio 2 — ¿Por qué se declaran dos endpoints extra? En una o dos frases cada uno: (a) ¿Por qué este módulo añade /quote_slow en vez de medir el /quote normal para la lección de percentiles? (b) ¿Por qué añade /quote_flaky en vez de esperar a que /quote falle solo?
Ver solución
- (a) Porque Reservo corre en
localhosty/quoteresponde en fracciones de milisegundo, casi sin cola. Con una distribución tan plana, la diferencia entre promedio y p95 sería mínima y la lección "el promedio esconde la cola" no se vería con fuerza./quote_slowinyecta una cola larga (declarada, con unsleep) para que el p95 alto sea real y medible. - (b) Porque
/quotees correcto y no falla nunca bajo esta carga, así que su tasa de error sería siempre 0% y no habría nada que aprender a leer./quote_flakydevuelve500en ~10% de las peticiones (declarado) para que exista una tasa de error real que medir e interpretar.
En ambos casos la causa del fenómeno está simulada, pero la medición del fenómeno es real. Eso es lo que se practica.
Ejercicio 3 — El coche con un solo instrumento. Para cada situación, di qué está mal en el veredicto y qué métrica falta mirar. (a) "El p95 es de 8 ms, la API vuela, lista para producción." (No se miró la tasa de error, que es 12%.) (b) "Procesamos 5.000 RPS, buenísimo." (No se miró la latencia; el p95 es de 4 segundos.) (c) "El promedio de latencia es 30 ms, perfecto." (No se miró el p95, que es 190 ms.)
Ver solución
- (a) El veredicto mira solo la latencia e ignora la tasa de error. Un p95 de 8 ms con 12% de errores significa que 1 de cada 8 usuarios recibió un fallo rápido: veloz, pero inservible. Falta mirar
http_req_failed. - (b) El veredicto mira solo el throughput e ignora la latencia. Mover 5.000 RPS con un p95 de 4 segundos significa procesar mucho volumen mientras cada usuario espera una eternidad. Falta mirar
http_req_duration(los percentiles). - (c) El veredicto mira el promedio en vez del percentil. Un promedio de 30 ms con un p95 de 190 ms delata una cola: el promedio bajo esconde que 1 de cada 20 usuarios esperó seis veces más. Falta mirar el p95 (lo verás medido en la lección 7).
La lección de las tres: ningún instrumento, solo, da el veredicto. Latencia, throughput y errores se leen juntos, y la latencia siempre en percentiles.
Resumen y siguiente paso
En esta lección montaste el mapa del módulo. Una prueba de carga se lee con tres familias de métricas: la latencia (http_req_duration en k6: ¿qué tan rápido?), el throughput (http_reqs: ¿cuánto volumen por segundo?) y la tasa de error (http_req_failed: ¿cuánto se rompió?). Son el tablero de la prueba, y como el tablero de un coche, engañan si miras solo un instrumento: se leen juntas, y la latencia jamás con el promedio.
Conociste las dos declaraciones que hacen posible el módulo: sobre la misma API canónica de Reservo (que sigue devolviendo 7500 y 6000, intacta), añadimos /quote_slow —lento, con cola larga, para ver un p95 alto de verdad— y /quote_flaky —que falla ~10%, para ver una tasa de error de verdad—. La causa de la lentitud y de los fallos está simulada y declarada; la medición de ambos es real y la vas a ver salir en la terminal. Y quedó clara la frontera: aquí se aprende qué son y cómo se calculan las métricas; usarlas para variar la carga (M4), para hacer pasar o fallar la prueba (M5) o para analizar y correr en CI (M7) viene después.
Antes de avanzar deberías poder: nombrar las tres familias de métricas y su métrica de k6; explicar por qué se leen juntas; y decir con tus palabras por qué este módulo declara un endpoint lento y uno flaky. Lo que sigue es abrir el primer instrumento. En la lección 2 entramos en la latencia: qué mide exactamente http_req_duration, cómo se descompone (envío + espera + recepción), la diferencia entre la latencia que ve el cliente y la que procesa el servidor —medida de verdad— y la primera prueba concreta de por qué el promedio miente.
Recursos
- k6 — Métricas integradas (referencia) — el catálogo oficial de las métricas que produce k6:
http_req_duration,http_reqs,http_req_failedy las demás. Es la fuente contra la que verificamos el contenido rotulado de k6 en este módulo. - Google SRE Book — Monitoring Distributed Systems — el marco de por qué el rendimiento se mide en varias señales (latencia, tráfico, errores, saturación) y en percentiles, no en promedios. El fondo conceptual de todo el módulo.
statistics— documentación de Python — el módulo de la biblioteca estándar conquantilesyfmean, con el que calculamos los percentiles y el promedio de verdad a partir de la lección 3.- Módulo 2 de esta guía — El script de k6 y los usuarios virtuales — la anatomía del script y el modelo de VUs que aquí reusamos. Si no tienes claro qué es un VU o cómo se lanza la carga, repásalo antes de seguir.