Marcio Cunha

Cómo diseñar pruebas de carga realistas y picos de tráfico

Aprende a estructurar pruebas de carga realistas para sistemas críticos usando k6, ingeniería del caos y métricas de SLO para prevenir fallas antes de afectar a los usuarios.

Marcio Cunha•5 min
También disponible en:PortuguêsEnglish
Resumen
  • Las pruebas sintéticas tradicionales fallan al reproducir la imprevisibilidad del comportamiento real de los usuarios bajo presión.
  • La herramienta k6 permite escribir scripts en JavaScript para simular miles de solicitudes concurrentes de forma eficiente.
  • Definir SLOs claros evita que los equipos se enfoquen en métricas de vanidad en lugar de la experiencia real del cliente.
  • La inyección controlada de fallas mediante ingeniería del caos valida si el sistema se recupera solo de los cuellos de botella.
  • Automatizar estas pruebas en el pipeline de entrega continua garantiza que las regresiones de rendimiento se bloqueen temprano.

Por qué las pruebas de carga tradicionales engañan a tu equipo

Muchas empresas descubren que sus sistemas fallan únicamente cuando el tráfico real explota durante una gran promoción o lanzamiento. En la práctica, esto ocurre porque las pruebas de carga tradicionales suelen ser lineales, enviando una cantidad fija de solicitudes por segundo que rara vez refleja el comportamiento caótico e impredecible de los seres humanos reales navegando por la web. Si tu aplicación web soporta mil clics estáticos por minuto en un entorno de pruebas, aún puede colapsar si cientos de usuarios deciden rellenar formularios complejos, buscar datos históricos o subir archivos pesados exactamente al mismo tiempo.

Para evitar sorpresas desagradables en producción, la ingeniería moderna adopta un enfoque mucho más cercano a la realidad mediante simulaciones de comportamiento profundo. En lugar de medir solo el uso bruto de CPU, los arquitectos de software deben comprender cómo los componentes internos se comunican entre sí bajo presión extrema. Cuando un microservicio se atasca, el efecto en cascada suele derribar sistemas enteros de pago o autenticación. Si has enfrentado problemas de lentitud intermitente en entornos distribuidos, vale la pena revisar nuestra guía sobre cómo depurar cuellos de botella con OpenTelemetry para mapear el flujo exacto de cada solicitud antes de lanzar las pruebas de carga.

Configurando escenarios dinámicos con k6

k6 es una herramienta moderna de pruebas de carga basada en código que permite a los desarrolladores escribir escenarios complejos utilizando JavaScript. En la práctica, funciona generando usuarios virtuales que ejecutan flujos de navegación completos, simulando desde clics en botones hasta llamadas a APIs asíncronas. A diferencia de las herramientas heredadas que consumen gigabytes de memoria solo para abrir conexiones, k6 fue construido en Go para generar alta concurrencia utilizando recursos mínimos de hardware en tu máquina o servidor de pruebas.

A continuación se muestra un ejemplo práctico de un script en k6 configurado para simular un aumento gradual de tráfico, imitando una campaña de marketing que comienza lentamente y alcanza su pico en pocos minutos. Este formato ayuda a observar cómo las bases de datos y los cachés reaccionan ante una escalada repentina de solicitudes:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 50 },
    { duration: '5m', target: 200 },
    { duration: '2m', target: 0 },
  ],
};

export default function () {
  const res = http.get('https://api.ejemplo.com/v1/productos');
  check(res, {
    'el estado es 200': (r) => r.status === 200,
    'tiempo de respuesta menor a 500ms': (r) => r.timings.duration < 500,
  });
  sleep(1);
}

Ejecutar este script revela cuellos de botella que las pruebas simples pasan por alto. Sin embargo, simular únicamente el volumen de accesos sigue siendo insuficiente si la infraestructura subyacente sufre cambios de base de datos o migraciones complejas. Cuando tu ecosistema atraviesa transformaciones estructurales profundas, mantener la estabilidad exige cuidados adicionales, como los que discutimos en nuestro artículo sobre cómo migrar bases de datos de un monolito sin downtime.

Midiendo el éxito con SLOs e indicadores de nivel de servicio

Muchos equipos cometen el error de mirar solo métricas de vanidad, como el consumo promedio de memoria o la cantidad total de solicitudes atendidas por minuto. En la práctica, lo que realmente importa para el usuario final es el SLO (Objetivo de Nivel de Servicio), que define un límite aceptable de fallas y lentitud. Si tu SLO determina que el 99% de las solicitudes de pago deben responderse en menos de 800 milisegundos, cualquier prueba de carga que viole esa marca se considera fallida, incluso si el servidor no se ha detenido por completo.

Trabajar con SLOs durante las pruebas de carga transforma la ingeniería de rendimiento en una métrica de negocio medible. Cuando el sistema comienza a sufrir picos de tráfico, las fallas deben ser predecibles y manejarse con gracia, devolviendo mensajes claros en lugar de errores genéricos de servidor. Mantener esta resiliencia en arquitecturas modernas a menudo exige el aislamiento estricto de secretos y credenciales de acceso, un tema que abordamos en detalle al explicar cómo gestionar secretos en Kubernetes con Vault, asegurando que las fallas de autenticación no ocurran bajo estrés.

Simulando el caos para probar la resiliencia real

La ingeniería del caos es la práctica de inyectar fallas deliberadas en un entorno controlado para ver cómo reacciona el sistema antes de que ocurra un desastre en producción. En lugar de rezar para que los servidores nunca fallen, simulas la caída repentina de una base de datos secundaria o una latencia extrema en una API de terceros mientras la prueba de carga de k6 se ejecuta a toda marcha. En la práctica, esto revela si tu mecanismo de reintentos está sobrecargando aún más los servicios o si el sistema puede activar con éxito el modo de degradación gradual.

Combinar pruebas de carga realistas con la inyección deliberada de fallas ayuda a identificar puntos únicos de fallo que las auditorías de código tradicionales pasan por alto. Si un microservicio de caché esencial falla, la aplicación principal debe ser capaz de buscar datos directamente en la base de datos principal sin bloquear la interfaz de usuario. Esta madurez operacional separa los sistemas resilientes de las aplicaciones frágiles que dependen puramente de la suerte para mantenerse en línea durante eventos de tráfico masivo.

Consideraciones finales sobre pruebas de carga y resiliencia

Construir una cultura de pruebas de carga realistas requiere un cambio de mentalidad, convirtiendo el rendimiento de una preocupación de última hora en un pilar continuo de desarrollo. Al utilizar herramientas como k6, definir SLOs centrados en la experiencia real del usuario y validar el comportamiento de la aplicación con ingeniería del caos, tu equipo adquiere la confianza necesaria para operar a gran escala sin temor a sorpresas. El objetivo final nunca es la perfección absoluta con cero errores, sino garantizar que el sistema se degrade de forma controlada y se recupere rápidamente cuando ocurra lo inesperado.