Módulo 4: Perfiles de carga y stages

4. Las formas: constante, rampa y spike

Descripción

Con los stages puedes dibujar casi cualquier forma de carga, pero en la práctica tres formas cubren la mayoría de las preguntas, y conviene conocerlas por nombre porque cada una revela algo distinto. La constante (una meseta plana) revela el estado estable. La rampa (una subida gradual) revela dónde empieza la degradación —la rodilla de capacidad—. Y el spike (una subida abrupta) revela la resiliencia a un pico súbito y si el sistema se recupera del golpe. La diferencia entre la rampa y el spike es sutil pero enorme: las dos llevan la carga a un pico alto, pero una lo hace despacio y la otra de golpe, y el sistema reacciona de forma muy distinta a cada una. En esta lección recorremos las tres formas, cuándo usar cada una, y sobre todo ejecutamos un spike real contra Reservo para que veas con números por qué "subir de golpe" no es lo mismo que "subir despacio hasta el mismo punto".

Conexión con el módulo: la lección 3 te dio la sintaxis (stages); esta te da el vocabulario de formas que escribes con esa sintaxis. Es el puente hacia la lección 7 (elegir el perfil según la pregunta): allí decidirás cuál forma usar; aquí aprendes qué es cada una y qué revela. Reutilizamos la rampa por etapas que ya ejecutaste (la del generador staged_load.py) como ejemplo de la forma "rampa", y agregamos un generador nuevo, spike_load.py, para la forma "spike". La forma constante ya la discutimos en la lección 2 (la etapa de pico aislada). Los executors que implementan estas formas por debajo son las lecciones 5 y 6; aquí nos quedamos en las formas mismas.

La analogía: tres maneras de meter gente a un teatro

Imagina que administras un teatro de mil butacas y quieres saber cómo se comporta la entrada. Hay tres experimentos distintos, y son las tres formas de carga.

Constante: dejas entrar a un ritmo fijo, digamos 100 personas por minuto, durante media hora, y observas. Aprendes cómo fluye la entrada en régimen estable a ese ritmo: si las filas se mantienen cortas, si los acomodadores dan abasto. Es la meseta.

Rampa: empiezas dejando entrar despacio y vas aumentando el ritmo poco a poco —50, 100, 200, 400 por minuto— hasta saturar. Como subes gradual, ves exactamente en qué ritmo se empieza a formar el cuello de botella: quizá a 300 por minuto las filas siguen fluidas, pero a 350 se atascan. Ese punto —la rodilla— es lo que la rampa revela y la constante no.

Spike: el teatro está tranquilo con poca gente y de pronto, al terminar un partido en el estadio de al lado, mil personas aparecen de golpe en la puerta en dos minutos. No es un aumento gradual: es un muro de gente. Aquí no te interesa el ritmo sostenido; te interesa si el sistema sobrevive el golpe —¿colapsan las puertas?, ¿se pisa la gente?— y, crucialmente, si se recupera cuando la avalancha pasa —¿la entrada vuelve a fluir normal en cinco minutos, o queda un caos que tarda media hora en despejarse?—. Un teatro puede aguantar perfectamente 1000 personas repartidas en una hora (rampa) y aun así colapsar con esas mismas 1000 en dos minutos (spike). Mismo total, forma distinta, resultado opuesto.

Forma 1: constante (la meseta)

La forma constante es una carga fija durante toda la prueba: una sola meseta, sin subida ni bajada apreciables. En stages se escribe con un tramo (o dos, si quieres una subida rápida antes de la meseta) que mantiene el target:

// CONTENIDO (no ejecutado aquí). Forma constante: 20 VUs fijos por 1 minuto.
export const options = {
  stages: [
    { duration: '1m', target: 20 }, // sube a 20 y, al ser el único target, es casi toda meseta
  ],
};

Qué revela: el comportamiento en estado estable a esa carga. Es la forma del smoke test (pocos VUs, confirmar que funciona), de verificar un SLO en la carga esperada, y del soak (una constante larga para buscar fugas). Ya la viste ejecutada en la lección 2: la etapa de pico aislada, 24 VUs → 174.63 ms de p95. Su límite, como argumentamos, es que no dice nada de la subida, el límite ni la recuperación. Es la forma correcta cuando la pregunta es sobre el régimen estable.

Forma 2: rampa (la subida gradual)

La rampa lleva la carga de poco a mucho de forma gradual, recorriendo los niveles intermedios. Es el ramp-up que ya conoces, pero usado como protagonista: subes despacio y observas en qué nivel el sistema empieza a sufrir.

// CONTENIDO (no ejecutado aquí). Rampa: subida gradual de 0 a 100 VUs en 2 min.
export const options = {
  stages: [
    { duration: '2m', target: 100 }, // sube linealmente de 0 a 100 VUs
  ],
};

Qué revela: la rodilla de degradación —el punto donde el p95 deja de crecer suave y se dispara— y, si sigues subiendo hasta que algo cede, el punto de quiebre (el stress test). Como la carga sube gradual, la rampa recorre 10, 20, 40, 80 VUs y te muestra la curva completa de latencia contra carga, no solo un punto.

Ya la ejecutaste: el generador staged_load.py es una rampa por etapas. Su columna de p95 —22.55 → 77.01 → 174.63 en la subida— es justo la curva que la rampa revela. Mírala como "la latencia en función de la carga": a 4 VUs, 22 ms; a 12, 77 ms; a 24, 175 ms. Esa curva ascendente y acelerándose es la firma de un sistema que se acerca a la saturación, y solo una rampa la dibuja.

Forma 3: spike (la subida abrupta)

El spike lleva la carga a un pico alto de golpe, la sostiene poco, y la baja. La diferencia con la rampa no es el destino (ambas llegan a un pico) sino la velocidad: el spike no da tiempo de calentamiento ni de adaptación. Modela un pico súbito de tráfico real —una promoción que se viraliza, un enlace en un programa de TV, el final de un partido—.

// CONTENIDO (no ejecutado aquí). Spike: baseline bajo, salto brusco, y vuelta.
export const options = {
  stages: [
    { duration: '30s', target: 3 },  // baseline: carga normal, baja
    { duration: '10s', target: 30 }, // SPIKE: salto brusco a 30 VUs en 10 s
    { duration: '30s', target: 3 },  // recovery: vuelta al baseline, observar recuperación
  ],
};

Qué revela: dos cosas que la rampa no. Primero, la resiliencia al golpe: cuando 30 usuarios aparecen de golpe, el sistema no tuvo tiempo de calentar cachés ni abrir conexiones, así que el p95 salta mucho más de lo que saltaría subiendo gradual al mismo pico. Segundo —y es la joya del spike—, la recuperación: tras el pico, ¿el sistema vuelve rápido a su latencia base, o queda tocado? Un sistema con colas que se llenan de golpe puede tardar en drenarlas mucho después de que el pico pasó.

El spike ejecutado

Aquí está el spike de verdad contra Reservo, con las tres fases: baseline (3 VUs), spike (salto a 30 VUs), recovery (vuelta a 3 VUs).

Qué esperar — el p95 debe ser bajo y estable en el baseline, saltar fuerte en el spike (con un máximo muy alto, porque el golpe pilla al sistema en frío), y volver al baseline en la recuperación si el sistema está sano. Salida real:

$ python3.14 spike_load.py http://127.0.0.1:PORT
perfil SPIKE contra http://127.0.0.1:PORT/quote
fase        VUs  peticiones   p95 (ms)   max (ms)
--------------------------------------------------
baseline      3         993      15.82      30.80
SPIKE        30        1171     235.01    2016.39
recovery      3         995      15.41      28.33
--------------------------------------------------
errores: 0

Lee las tres fases. En el baseline (3 VUs), el p95 es 15.82 ms y el máximo 30.80 ms: todo tranquilo, el sistema en reposo. Llega el spike (30 VUs de golpe) y el p95 se dispara a 235.01 ms —quince veces el baseline— pero mira sobre todo la columna max: 2016.39 ms, ¡más de dos segundos! Ese máximo es la firma del golpe: cuando 30 usuarios aparecen a la vez, las primeras peticiones hacen una fila enorme mientras el sistema absorbe la avalancha, y alguna espera dos segundos. La rampa gradual al mismo pico de 24-30 VUs nunca produjo un máximo así de brutal, porque subía dando tiempo de asimilar. Y en la recuperación (vuelta a 3 VUs), el p95 regresa a 15.41 ms y el máximo a 28.33 ms: idénticos al baseline. Reservo se recuperó del golpe limpio y al instante. Ese regreso es la buena noticia que el spike estaba diseñado para verificar.

La rampa y el spike llegan al mismo pico, pero la rampa sube despacio y el spike de golpe. El golpe revela dos cosas que la subida gradual esconde: cuánto peor es el pico sin tiempo de calentamiento (mira el max, no solo el p95) y si el sistema se recupera cuando la avalancha pasa. Mismo total de carga, forma distinta, comportamiento distinto.

Rampa vs spike: por qué la velocidad cambia todo

Vale la pena insistir, porque es el corazón de la lección. Compara el pico de la rampa (24 VUs, subiendo gradual: p95 174.63 ms, y sus máximos moderados) con el pico del spike (30 VUs, de golpe: p95 235.01 ms, máximo 2016.39 ms). Aunque el spike solo tiene unos VUs más, su comportamiento es cualitativamente peor por la forma, no por el tamaño. Cuando la carga sube gradual, cada nuevo VU llega a un sistema que ya se adaptó a los anteriores; cuando sube de golpe, todos llegan a un sistema que aún estaba en reposo, y el arranque en frío (cachés vacías, conexiones sin abrir, colas que se llenan de un tirón) castiga a las primeras peticiones con esperas enormes.

Por eso no puedes sustituir un spike test por una rampa "más rápida": la abruptez es la variable que estás probando. Y por eso el max (o el p99) importa tanto en un spike: el promedio y hasta el p95 pueden verse aceptables, pero el puñado de peticiones que pilló el golpe en el peor momento vio latencias de segundos, y esos son usuarios reales que vivieron la avalancha. Un sistema que sube de golpe y no se recupera —que queda lento minutos después— tiene un problema serio de resiliencia que solo un spike test destapa.

Errores comunes

Confundir una rampa rápida con un spike. Qué pasa: alguien pone un ramp-up corto (subir a 30 en 5 segundos) y cree que probó un spike. Por qué pasa: ambos llegan rápido al pico. Cómo detectarlo: un spike de verdad salta de un baseline bajo a un pico alto casi instantáneo y luego vuelve, para medir el golpe y la recuperación; una rampa, por rápida que sea, sigue recorriendo niveles. Cómo corregirlo: si tu pregunta es "¿sobrevive un pico súbito y se recupera?", usa la forma spike (baseline → salto → baseline) y mira el max y la fase de recuperación, no solo el p95 del pico.

Mirar solo el p95 en un spike e ignorar el max. Qué pasa: en el spike el p95 fue 235 ms y alguien concluye "aceptable". Por qué pasa: el p95 es la métrica que siempre miramos. Cómo detectarlo: en un spike, el daño del golpe vive en la cola extrema —el max de 2016 ms—, que el p95 (que deja fuera el 5% peor) no captura. Cómo corregirlo: en un spike, mira también el max y el p99; son las peticiones que vivieron la avalancha, y son usuarios reales.

No incluir la fase de recuperación. Qué pasa: el spike test sube de golpe, mide el pico, y termina ahí. Por qué pasa: se cree que "aguantó el pico" es la conclusión. Cómo detectarlo: sin una fase de vuelta al baseline, no sabes si el sistema drenó las colas o quedó atascado; la mitad del valor del spike (¿se recupera?) se pierde. Cómo corregirlo: siempre cierra el spike con una vuelta al baseline y compara la latencia post-pico con la pre-pico; si no regresa, hay una fuga o una cola que no se vacía.

Ejercicios

Ejercicio 1 — Nombra la forma. Para cada stages, di si es constante, rampa o spike. (a) [{duration:'2m',target:50}] (una sola subida larga a 50). (b) [{duration:'20s',target:10},{duration:'10s',target:200},{duration:'20s',target:10}]. (c) [{duration:'10s',target:30},{duration:'5m',target:30},{duration:'10s',target:0}].

Ver solución
  • (a) Rampa. Una subida gradual y sostenida de 0 a 50 en 2 minutos; recorre los niveles intermedios. (Sin meseta explícita: es una rampa pura.)
  • (b) Spike. Baseline bajo (10 VUs), salto brusco a 200 en 10 segundos, y vuelta a 10. La abruptez del salto y la vuelta al baseline lo delatan.
  • (c) Constante (con subida rápida). Sube a 30 en 10 segundos y sostiene 30 durante 5 minutos —una meseta larga—; el protagonista es la meseta, no la subida. La duración larga sugiere incluso un soak.

Ejercicio 2 — Lee el spike. Con la salida ejecutada del spike, responde: (a) ¿Cuántas veces más alto es el p95 del spike respecto al baseline? (b) ¿Por qué el max del spike (2016 ms) es tan desproporcionado frente a su p95 (235 ms)? (c) ¿Qué te dice que la fase de recovery tenga p95 15.41 ms, casi igual al baseline 15.82 ms?

Ver solución
  • (a) 235.01 / 15.82 ≈ 15 veces. El golpe multiplicó el p95 por quince.
  • (b) Porque el golpe (30 VUs de golpe sobre un sistema en reposo) castiga durísimo a un puñado de peticiones —las primeras de la avalancha, que hacen una fila enorme—, que se van a la cola extrema (el max). El p95 deja fuera ese 5% peor, así que no ve los dos segundos; el max sí. En un spike, la cola extrema es donde vive el daño.
  • (c) Que Reservo se recuperó limpio y al instante: cuando la avalancha pasó, drenó cualquier cola y volvió a su latencia de reposo. Si el recovery hubiera quedado en, digamos, 100 ms, sospecharías que algo no se liberó tras el golpe.

Ejercicio 3 — Elige y escribe la forma. Para cada pregunta, di qué forma usarías y escribe un stages de ejemplo. (a) "¿En qué nivel de carga Reservo empieza a degradarse?" (b) "¿Sobrevive Reservo a que 500 usuarios lleguen de golpe cuando salga la campaña, y se recupera?"

Ver solución
  • (a) Rampa. Una subida gradual que recorra los niveles hasta ver la rodilla:

    stages: [ { duration: '3m', target: 200 } ] // sube de 0 a 200, observa dónde se tuerce el p95

    Miras la curva de p95 contra carga y buscas dónde deja de ser suave.

  • (b) Spike. Baseline bajo, salto brusco a 500, y vuelta al baseline para ver la recuperación:

    stages: [
      { duration: '30s', target: 20 },  // baseline
      { duration: '10s', target: 500 }, // SPIKE: golpe súbito
      { duration: '1m',  target: 500 }, // aguanta el pico un poco
      { duration: '30s', target: 20 },  // recovery: vuelve al baseline
    ]

    Miras el max/p99 durante el spike (el golpe) y comparas el p95 del recovery con el del baseline (la recuperación).

Resumen y siguiente paso

En esta lección aprendiste las tres formas canónicas de carga y qué revela cada una. La constante (meseta) revela el estado estable: la forma del smoke, del SLO en carga esperada y del soak. La rampa (subida gradual) revela la rodilla de degradación y el punto de quiebre: recorre los niveles intermedios y dibuja la curva de latencia contra carga. Y el spike (subida abrupta) revela la resiliencia al golpe y la recuperación: lleva la carga a un pico de golpe, sin tiempo de calentamiento.

La lección grande es que la rampa y el spike llegan al mismo pico pero por caminos opuestos, y el sistema reacciona distinto a cada uno. Lo viste con números reales: el spike ejecutado saltó a un p95 de 235 ms con un max brutal de 2016 ms —la firma del arranque en frío— y luego se recuperó limpio a 15 ms, idéntico al baseline. La rampa al mismo pico nunca produjo ese máximo, porque subía dando tiempo. En un spike, el max y el p99 importan tanto como el p95, porque el golpe vive en la cola extrema.

Antes de avanzar deberías poder: nombrar las tres formas y qué revela cada una; explicar por qué un spike no es una rampa rápida; leer la salida de un spike distinguiendo el golpe (el max) de la recuperación (el p95 de vuelta al baseline); y escribir un stages para cada forma.

Lo que sigue es mirar debajo del capó. Hasta ahora dibujaste formas con stages sin preguntarte qué motor las ejecuta. En la lección 5 conocemos los executors de k6 —los motores que deciden cómo se aplica la carga— empezando por los dos que trabajan con VUs: constant-vus (VUs fijos) y ramping-vus (el que hay debajo de stages).

Recursos