Módulo 4: Perfiles de carga y stages
2. Por qué una carga constante no basta
Descripción
Una carga constante es la prueba más fácil de escribir: fijas N usuarios, los mantienes N minutos, mides. Y no está mal —responde una pregunta legítima—. El problema es que responde solo una, y el tráfico real plantea varias. En esta lección desmontamos la carga constante para ver con precisión qué sí contesta y qué deja mudo, y de ahí nace la idea central del módulo: que la carga necesita una forma. La tesis es corta: el tráfico real no es plano, llega en olas, y una prueba plana no puede describir una ola. Con una carga constante sabes cómo te va en una meseta; no sabes cómo llegas a esa meseta, en qué punto de la subida empezaste a sufrir, ni cómo te recuperas cuando la ola baja. Esas tres cosas —arranque, punto de degradación y recuperación— son justo las que una forma de carga revela y una constante esconde.
Conexión con el módulo: la lección 1 te dio la idea grande (tamaño vs forma) y un adelanto ejecutado. Esta lección la argumenta: por qué la forma es necesaria, no un lujo. Es el "por qué" que justifica todo lo que viene después —los stages (lección 3), las formas concretas (lección 4), los executors (5 y 6)—. Aquí todavía usamos el vocabulario de concurrencia por VUs del módulo 2 y las métricas del módulo 3 (el p95); lo nuevo es empezar a mirarlas a lo largo del tiempo en vez de en un solo instante. No tocamos aún la anatomía de stages (eso es la 3): nos quedamos en el argumento y en un contraste ejecutado entre una carga plana y una con forma.
La analogía: la foto y la película
Piensa en la diferencia entre una foto y una película. Una carga constante es una foto: capta un instante —"así se ve el sistema con 24 usuarios encima"— y ese instante es real y útil. Pero una foto no tiene antes ni después. No muestra cómo llegó el sistema a ese estado ni qué pasó luego. Si te enseño la foto de un corredor a mitad de carrera, sabes que en ese momento iba corriendo, pero no si venía acelerando o frenando, ni si un segundo después se desplomó.
Un perfil de carga es una película: una secuencia de instantes que cuenta una historia con principio, medio y final. Muestra la subida (cómo el sistema absorbe una demanda creciente), el pico (cómo se sostiene en lo más alto) y la bajada (cómo se recupera). Y en esa secuencia aparecen cosas que ninguna foto suelta puede mostrar: el momento exacto en que el p95 empieza a dispararse mientras subes, o el hecho revelador de que, tras el pico, el sistema no vuelve a su latencia de reposo —una pista de que algo quedó atascado—. La foto (carga constante) no es falsa; es incompleta. Y cuando la pregunta es "¿cómo se comporta mi sistema ante el tráfico de un día real?", que es una historia con olas, necesitas la película.
Qué SÍ responde una carga constante
Seamos justos con la carga constante antes de criticarla, porque tiene su lugar. Una meseta plana de N usuarios responde bien una pregunta: "¿cómo se comporta el sistema en estado estable con N usuarios encima?". Es la pregunta del estado estacionario (steady state), y es valiosa. Si sabes que tu tráfico pico son 24 usuarios concurrentes sostenidos, una carga constante de 24 te dice el p95 que verán en esa hora punta. Para un smoke test —¿el sistema siquiera funciona bajo una carga mínima?— la constante es la forma ideal: unos pocos VUs fijos, unos segundos, y confirmas que nada explota antes de invertir en pruebas más grandes.
Mira el número real. Corriendo el generador a concurrencia constante de 24 (la fase de pico, aislada) contra Reservo:
Qué esperar — con 24 usuarios fijos, el p95 se estabiliza en un valor; es la latencia del estado estable a esa carga. Salida real (la etapa de pico de una corrida por etapas, que es exactamente una carga constante de 24):
etapa VUs peticiones p95 (ms) promedio (ms)
steady (peak) 24 1775 174.63 63.00
Ese 174.63 ms es información buena y honesta: "en estado estable, con 24 usuarios concurrentes, el 95% de las cotizaciones responde en 175 ms o menos". Si tu SLO fuera "p95 < 500 ms", esta foto ya te diría que a 24 usuarios cumples con margen. La carga constante hizo su trabajo. El problema no es que mienta; es todo lo que no está en la foto.
Qué NO responde (y por qué duele)
Una carga constante de 24 usuarios te da ese 174.63 ms y nada más. Estas son las tres preguntas que deja mudas, y por qué cada una importa:
Cómo te comportas mientras subes. El número del estado estable no dice nada del camino hasta él. ¿El p95 sube suave y lineal con la carga, o hay una rodilla —un punto donde de golpe se dispara—? Esa rodilla es información de oro: marca dónde empieza la degradación real, tu capacidad útil. Una carga que arranca directo en 24 nunca visita los niveles intermedios, así que no puede encontrar la rodilla. Solo una subida (un ramp-up) recorre 4, 8, 12, 16, 20, 24 y te muestra en cuál se torció la curva.
Dónde está tu límite. Una constante a 24 confirma que 24 va bien, pero no busca el punto de quiebre. ¿Aguantas 50? ¿100? ¿A partir de cuántos el p95 se vuelve inaceptable o empiezan los errores? Esa pregunta —el stress test de la lección 4— solo se responde subiendo la carga más allá de lo normal hasta que algo cede. Una meseta fija, por definición, nunca lo intenta.
Si te recuperas. Esta es la más traicionera. Tras un pico de carga, ¿el sistema vuelve a su latencia de reposo, o queda degradado? Un sistema sano se recupera; uno con una fuga (memoria que no se libera, conexiones que no se cierran, una cola que no se vacía) queda lento aun cuando la carga ya bajó. Una carga constante no tiene "después del pico" —termina en el pico—, así que es estructuralmente incapaz de ver la recuperación. Necesitas una bajada (un ramp-down) para observarla.
El contraste ejecutado: una foto vs la película
Pongamos las dos pruebas lado a lado, ambas contra la misma API de Reservo, con los mismos usuarios en el pico. La diferencia es solo la forma: una es plana (constante a 24), la otra tiene forma (sube y baja).
Qué esperar — la carga constante entrega un solo número (el del pico); la carga con forma entrega la historia completa, con el p95 subiendo en la rampa y recuperándose en la bajada. Salida real de la corrida por etapas:
$ python3.14 staged_load.py http://127.0.0.1:PORT
perfil por etapas contra http://127.0.0.1:PORT/quote (Focus/basic/3h -> 7500)
etapa VUs peticiones p95 (ms) promedio (ms)
--------------------------------------------------------------
ramp-up (warm) 4 1028 22.55 12.17
ramp-up (mid) 12 1208 77.01 33.18
steady (peak) 24 1775 174.63 63.00
ramp-down (mid) 12 1187 82.56 33.65
ramp-down (cool) 4 1054 24.20 11.85
--------------------------------------------------------------
errores: 0
Una carga constante de 24 te habría dado una sola de esas filas: la del pico, 174.63 ms. La carga con forma te da las cinco, y con ellas tres cosas que la constante jamás:
- El arranque: con 4 usuarios el p95 es
22.55 ms. Ahora sabes tu latencia casi en reposo, tu línea base. - La subida: de 4 a 12 a 24, el p95 va
22.55 → 77.01 → 174.63. Ves cómo crece con la carga —aquí, más que lineal: al triplicar de 4 a 12 el p95 se multiplicó por más de tres, y al duplicar de 12 a 24 por más de dos—. Esa aceleración es la señal de que te acercas a la saturación. - La recuperación: al bajar de vuelta a 12 y a 4, el p95 regresa a
82.56y24.20—casi idénticos a los77.01y22.55de la subida—. El sistema se recupera limpio: no quedó daño. Si la fila "ramp-down (cool)" hubiera mostrado, digamos,150 mscon solo 4 usuarios, tendrías una alarma —algo no se liberó tras el pico— y una carga constante nunca te la habría encendido.
La misma API, la misma métrica del módulo 3, el mismo pico. Lo único que cambió fue darle forma a la carga, y con eso pasaste de una foto a una película.
Una carga constante responde "¿cómo te va en estado estable con N usuarios?" —una foto de un instante—. El tráfico real es una película: sube, se sostiene, baja. Solo una carga con forma revela el arranque (¿dónde empieza a doler?), el límite (¿dónde se rompe?) y la recuperación (¿vuelve a la normalidad?). La constante no miente; está incompleta.
Cuándo la constante es la forma correcta
Nada de esto significa que la carga constante sea mala; significa que es una de varias formas, cada una para una pregunta. La constante es la elección correcta cuando la pregunta es sobre el estado estable:
- Smoke test: unos pocos VUs constantes por poco tiempo, solo para confirmar que el sistema arranca y responde. La forma más simple para la pregunta más básica.
- Verificar un SLO en la carga esperada: si sabes que tu pico sostenido son 24 usuarios y quieres confirmar que ahí cumples "p95 < 500 ms", una constante a 24 es exactamente lo que necesitas.
- Soak test: una constante larga (horas) para buscar degradación lenta —fugas que solo aparecen con el tiempo—. Aquí la forma plana es la correcta, pero la duración es la variable clave (lo veremos en la lección 7).
La regla no es "nunca uses carga constante"; es "elige la forma según la pregunta". Si tu pregunta tiene que ver con la subida, el límite o la recuperación, la constante no basta y necesitas una forma con stages. Esa elección consciente es el tema de la lección 7.
Errores comunes
Reportar el número del estado estable como si describiera "el sistema". Qué pasa: alguien corre una constante a 24, obtiene 175 ms de p95 y lo presenta como el rendimiento del sistema. Por qué pasa: un solo número es cómodo de comunicar. Cómo detectarlo: si tu conclusión es un número sin una forma detrás, describiste una foto y la vendiste como película. Cómo corregirlo: acompaña el número del estado estable con la forma —cómo llegaste ahí y si te recuperas—; el p95 del pico es una fila de la tabla, no la tabla entera.
Arrancar la carga directo en el pico. Qué pasa: la prueba empieza con los 24 VUs de golpe, sin subida. Por qué pasa: parece que "ir directo al grano" ahorra tiempo. Cómo detectarlo: si tu primer instante de carga ya es el máximo, te saltaste toda la subida y no puedes ver la rodilla de degradación (además de castigar al sistema con un arranque en frío que no representa el tráfico real, que sube gradual). Cómo corregirlo: usa un ramp-up —una subida gradual— para que la prueba recorra los niveles intermedios y para dar tiempo de calentamiento; es lo que hace stages (lección 3).
Terminar la prueba en el pico y no observar la bajada. Qué pasa: la prueba corta justo cuando la carga está en el máximo, sin ramp-down. Por qué pasa: se asume que "si aguantó el pico, ya está". Cómo detectarlo: si tu prueba no tiene un "después del pico", no puedes ver si el sistema se recupera —y una fuga se te escapa por completo—. Cómo corregirlo: agrega una fase de bajada y compara la latencia de la bajada con la de la subida al mismo nivel de carga; si no regresa, hay algo que investigar.
Ejercicios
Ejercicio 1 — ¿Qué pregunta responde? Para cada objetivo, di si una carga constante basta o si necesitas una carga con forma (y por qué). (a) "Confirmar que la API arranca y responde 200 bajo una carga mínima." (b) "Encontrar a partir de cuántos usuarios el p95 se dispara." (c) "Saber el p95 en nuestra hora pico sostenida de 24 usuarios." (d) "Verificar que tras un pico de tráfico la latencia vuelve a la normalidad."
Ver solución
- (a) Constante basta. Es un smoke test: pocos VUs fijos para confirmar que funciona. La pregunta es sobre un estado, no sobre una evolución.
- (b) Con forma (rampa creciente). "A partir de cuántos se dispara" exige subir la carga y observar la rodilla; una meseta fija nunca visita los niveles intermedios ni busca el límite.
- (c) Constante basta. La pregunta es sobre el estado estable a una carga conocida; una constante a 24 la responde directo.
- (d) Con forma (necesita ramp-down). La recuperación solo se ve si hay un "después del pico"; una constante que termina en el pico es incapaz de mostrarla.
La regla: si la pregunta es sobre un estado, constante; si es sobre una subida, un límite o una recuperación, con forma.
Ejercicio 2 — Lee la película. Con la salida ejecutada de la corrida por etapas, responde: (a) ¿Cuál es la latencia base (casi en reposo) del sistema? (b) Entre 4→12 VUs y 12→24 VUs, ¿en qué tramo crece proporcionalmente más el p95, y qué sugiere eso? (c) ¿Qué fila usarías para reportar "el p95 en hora pico" y cuál para argumentar "el sistema se recupera"?
Ver solución
- (a) La de 4 VUs:
22.55 ms(o los24.20de la bajada a 4). Es la línea base, la latencia casi sin contención. - (b) De 4 a 12 (×3 la carga) el p95 pasó de
22.55a77.01(×3.4). De 12 a 24 (×2 la carga) pasó de77.01a174.63(×2.3). En ambos tramos el p95 crece más que proporcional a la carga, lo que sugiere que ya hay contención y te acercas a la saturación; no es un crecimiento lineal cómodo. - (c) Para "p95 en hora pico", la fila
steady (peak)con174.63 ms. Para "se recupera", comparasramp-down (cool)(24.20) conramp-up (warm)(22.55): casi iguales, luego recuperación limpia.
Ejercicio 3 — Rediseña la prueba. Un compañero prueba Reservo así: "lanzo 24 VUs constantes durante 30 segundos y reporto el p95". Su jefe pregunta tres cosas: "¿dónde empieza a degradarse?, ¿aguanta 50?, ¿se recupera tras el pico?". Reescribe la prueba (en palabras, describiendo la forma) para que responda las tres, y di qué fase responde cada pregunta.
Ver solución
Una prueba con forma, por ejemplo: sube de 0 a 50 VUs por etapas (ramp-up), sostén un pico, y baja de vuelta a unos pocos (ramp-down). Con eso:
- "¿Dónde empieza a degradarse?" → la subida: al recorrer 4, 12, 24, 36, 50 ves en qué nivel el p95 se tuerce (la rodilla).
- "¿Aguanta 50?" → llevar el ramp-up (o el steady) hasta 50 responde si a esa carga el p95 sigue aceptable o ya se disparó; si quieres el límite exacto, sigue subiendo hasta que ceda (stress).
- "¿Se recupera?" → la bajada: comparas el p95 en la bajada con el de la subida al mismo nivel; si regresa, se recupera.
La constante de 24 no respondía ninguna de las tres; solo daba el número del estado estable a 24. Cada pregunta del jefe es sobre una fase de la forma.
Resumen y siguiente paso
En esta lección argumentaste por qué una carga constante no basta. Una constante responde bien una pregunta —"¿cómo te va en estado estable con N usuarios?"—, y esa foto es real y útil (para un smoke test, para verificar un SLO en la carga esperada, para un soak largo). Pero el tráfico real no es una foto, es una película: llega en olas que suben, se sostienen y bajan. Y hay tres cosas que solo la película revela —el arranque (¿dónde empieza a doler la subida?), el límite (¿dónde se rompe?) y la recuperación (¿vuelve a la normalidad tras el pico?)— que una meseta plana esconde por construcción.
Lo viste con números: la etapa de pico daba 174.63 ms, pero la corrida con forma daba las cinco filas —la línea base de 22.55 ms, la subida acelerada, y la recuperación simétrica de vuelta a 24.20 ms—. La misma API, la misma métrica; lo que cambió fue darle forma a la carga. Y viste que la constante no es "mala": es una de varias formas, correcta cuando la pregunta es sobre un estado estable, e insuficiente cuando la pregunta es sobre una evolución.
Antes de avanzar deberías poder: nombrar las tres preguntas que una carga constante deja mudas; explicar por qué la constante es estructuralmente incapaz de ver la recuperación; decir cuándo la constante sí es la forma correcta; y leer una tabla de p95 por etapa distinguiendo la línea base, la subida y la recuperación.
Lo que sigue es aprender a escribir esa forma. En la lección 3 abrimos la anatomía de los stages de k6: qué es exactamente esa lista de {duration, target}, cómo k6 interpola los VUs hacia cada objetivo, y cómo se leen las tres fases —ramp-up, steady, ramp-down— en un script real (contenido) y en el generador Python (ejecutado).
Recursos
- k6 — Tipos de pruebas de carga (load testing) — la guía oficial que distingue el smoke, el load, el stress y el spike por su forma; conecta este argumento con los tipos que verás en la lección 7.
- k6 — Opción
stages— cómo se escribe la forma (ramp-up/steady/ramp-down) que la carga constante no tiene; la abrimos en la lección 3. - Google SRE Workbook — Implementing SLOs — por qué el rendimiento se observa como una serie en el tiempo, no como un número aislado; el fundamento de "la película sobre la foto".
statistics— documentación de Python — la biblioteca con la que el generador calcula el p95 de cada etapa (la misma del módulo 3, ahora aplicada por tramos).