Imagina que llevas semanas desarrollando tu aplicación. Todo funciona de maravilla en tu ordenador, las peticiones responden rápido y no parece haber ningún problema.
Pero llega el dÃa del lanzamiento, entran cientos de usuarios a la vez y… ¡boom! La aplicación empieza a ir lenta, aparecen errores y el servidor parece estar pidiendo vacaciones.
¿Se podÃa haber evitado?
En muchos casos, sÃ. Y aquà es donde entran en juego los tests de estrés, una de esas herramientas que conviene conocer antes de que nuestra aplicación se convierta en una pequeña pesadilla.
Hoy vamos a ver qué son, para qué sirven, qué herramientas podemos utilizar y cómo hacer una prueba sencilla con una API desarrollada en Java.
¿Qué es un test de estrés?
Un test de estrés consiste en enviar a una aplicación, un servidor o una API una carga elevada para comprobar cómo se comporta cuando las cosas se ponen difÃciles.
No se trata simplemente de comprobar que todo funciona cuando hay dos personas conectadas. La idea es descubrir qué ocurre cuando aumentamos considerablemente el número de peticiones, reducimos los recursos disponibles o nos acercamos a los lÃmites del sistema.
Por ejemplo, imagina una tienda online que normalmente recibe 50 peticiones por segundo. ¿Qué ocurrirÃa si, durante una promoción, recibiera 500 o 1.000?
Puede que todo siguiera funcionando correctamente. O puede que los tiempos de respuesta se disparasen y empezaran a aparecer errores.
Precisamente eso es lo que queremos descubrir antes de que suceda en un entorno real.
El objetivo no es romper la aplicación por diversión, sino descubrir sus lÃmites para poder mejorarla. Bueno, y evitar algún que otro dolor de cabeza.
Test de carga, test de estrés y test de resistencia: no son lo mismo
Aunque estos términos suelen utilizarse indistintamente, existen diferencias importantes.
Test de carga (Load Testing)
Sirve para comprobar cómo responde una aplicación ante una cantidad de usuarios o peticiones prevista.
Por ejemplo, queremos saber si nuestra API puede atender 200 usuarios simultáneos manteniendo unos tiempos de respuesta aceptables.
Test de estrés (Stress Testing)
Aquà aumentamos la carga por encima de los niveles habituales para descubrir dónde empieza a fallar el sistema y cómo se comporta cuando se acerca a sus lÃmites.
Es especialmente útil para localizar cuellos de botella.
Test de resistencia (Soak Testing)
En este caso, mantenemos una carga determinada durante un periodo prolongado.
¿Para qué? Para detectar problemas que aparecen con el tiempo, como fugas de memoria, acumulación de conexiones o degradación progresiva del rendimiento.
En resumen: uno comprueba la carga esperada, otro explora los lÃmites y el tercero busca problemas que aparecen después de muchas horas de funcionamiento.
Herramientas para realizar tests de estrés
Por suerte, no necesitamos desarrollar nuestro propio sistema de pruebas desde cero. Existen varias herramientas bastante conocidas que nos facilitan el trabajo.
1. Apache JMeter
Apache JMeter es una herramienta muy popular para probar el rendimiento de aplicaciones y servicios.
Permite configurar escenarios con múltiples usuarios virtuales, definir peticiones HTTP, establecer tiempos de espera y recopilar estadÃsticas.
Su interfaz gráfica puede resultar cómoda si prefieres configurar las pruebas visualmente en lugar de escribir todos los escenarios mediante código.
Es una opción interesante para aplicaciones web, APIs y otros servicios compatibles.
Más información: https://jmeter.apache.org/
2. k6
k6 es una herramienta de pruebas de rendimiento que permite definir escenarios utilizando JavaScript.
Una de sus ventajas es que puedes guardar los tests como código, versionarlos junto con tu proyecto y ejecutarlos automáticamente dentro de un proceso de integración continua.
Además, resulta bastante cómoda para probar APIs REST.
Si te gusta programar y quieres tener control sobre lo que hace cada prueba, merece la pena echarle un vistazo.
Más información: https://grafana.com/docs/k6/ latest/
3. Gatling
Gatling es otra alternativa para realizar pruebas de rendimiento y analizar cómo se comportan los sistemas bajo carga.
Es especialmente interesante en entornos de desarrollo donde las pruebas automatizadas forman parte del proceso habitual de trabajo.
Si trabajas con Java o Scala, puede encajar bien en determinados proyectos, aunque la elección dependerá de tus necesidades y del tipo de pruebas que quieras realizar.
Más información: https://docs.gatling.io/
¿Cuál elegirÃa para empezar?
Probablemente k6 si quiero probar rápidamente una API REST, o JMeter si prefiero una interfaz gráfica. Gatling también es una buena opción para proyectos que requieren escenarios de prueba más elaborados.
Vamos a hacer una prueba con Java y k6
Pasemos a la práctica, que es donde empieza lo interesante.
Imagina que tenemos una aplicación desarrollada con Java y Spring Boot que expone un endpoint REST para consultar productos.
Por ejemplo:
Este endpoint devuelve una lista de productos y queremos comprobar cómo responde cuando varias peticiones llegan casi al mismo tiempo.
Para el ejemplo utilizaremos k6.
Paso 1. Instalar k6
Sigue las instrucciones oficiales de instalación según tu sistema operativo:
También necesitarás una API funcionando en tu entorno local. En este ejemplo, asumiremos que Spring Boot está escuchando en el puerto 8080 y que la ruta "/api/productos" existe.
Paso 2. Crear nuestro test
Crea un archivo llamado "test-estres.js" y añade el siguiente código:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 10 },
{ duration: '1m', target: 10 },
{ duration: '30s', target: 0 },
],
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<500'],
},
};
export default function () {
const response = http.get(
);
check(response, {
'la respuesta es HTTP 200': (r) => r.status === 200,
});
sleep(1);
}
¿Qué estamos haciendo exactamente?
- Durante 30 segundos aumentamos progresivamente la carga hasta alcanzar 10 usuarios virtuales.
- Mantenemos esos usuarios durante un minuto.
- Reducimos la carga gradualmente hasta finalizar la prueba.
- Comprobamos que las peticiones no fallen y que el percentil 95 del tiempo de respuesta sea inferior a 500 milisegundos.
Este último punto es importante: el percentil 95, o p95, indica el tiempo por debajo del cual termina el 95 % de las peticiones medidas.
Los lÃmites que hemos establecido son ejemplos orientativos, no una garantÃa de que la aplicación sea suficientemente rápida para cualquier proyecto.
Un detalle: los usuarios virtuales de k6 no equivalen necesariamente a usuarios reales navegando por una web. Además, el tiempo de espera de un segundo entre iteraciones hace que la frecuencia de peticiones dependa también de la duración de las respuestas.
Paso 3. Ejecutar el test
Desde el directorio donde has guardado el archivo, ejecuta:
k6 run test-estres.js
Si todo está correctamente configurado, k6 comenzará a realizar las peticiones y mostrará estadÃsticas al finalizar.
Recuerda que esta prueba es relativamente pequeña: sirve para aprender y comprobar que la configuración funciona, no para demostrar que una aplicación soportará miles de usuarios.
Paso 4. Interpretar los resultados
Aquà es donde empieza la parte interesante.
Cuando termine la prueba, fÃjate especialmente en estas métricas:
- "http_req_duration": cuánto tardan las peticiones HTTP.
- "http_req_failed": qué proporción de peticiones ha fallado.
- "http_reqs": cuántas peticiones se han realizado y a qué ritmo.
- "vus": cuántos usuarios virtuales están activos durante la prueba.
Imagina que el p95 es de 180 milisegundos y no se producen errores. Para este escenario, los resultados cumplirÃan los lÃmites definidos.
Ahora imagina que el p95 sube a 1.500 milisegundos y empiezan a aparecer respuestas con errores 500. TendrÃamos indicios de que algo necesita atención, aunque todavÃa habrÃa que investigar la causa.
PodrÃa ser la base de datos, un problema de concurrencia, la configuración del servidor, la falta de memoria o incluso la propia máquina desde la que ejecutamos las pruebas.
Un test de estrés no siempre te dice directamente cuál es el problema, pero te ayuda a reproducirlo y encontrar pistas.
¿Qué deberÃamos vigilar en una aplicación Java?
Además de las métricas HTTP, en Java hay varios aspectos que conviene observar durante una prueba de rendimiento.
Uso de memoria
Si el consumo de memoria aumenta continuamente, conviene investigar qué está ocurriendo. PodrÃa tratarse de una fuga de memoria, de una caché que crece sin control o simplemente de un comportamiento esperado que necesita más recursos.
Garbage Collector
El recolector de basura puede influir en los tiempos de respuesta. Conviene comprobar si la actividad de recolección aumenta considerablemente cuando sube la carga.
Base de datos
Una aplicación puede tener un código perfectamente razonable y, aun asÃ, rendir mal porque la base de datos no da abasto.
Las consultas lentas, la falta de Ãndices o un número insuficiente de conexiones disponibles pueden convertirse en auténticos cuellos de botella.
Hilos y concurrencia
También merece la pena revisar los hilos de ejecución, las colas de trabajo y los bloqueos.
Si muchas peticiones quedan esperando el mismo recurso, añadir más usuarios virtuales no hará que el problema desaparezca. De hecho, puede empeorarlo.
Para investigar estas situaciones podemos utilizar herramientas como Java Flight Recorder, Java Mission Control y las métricas de Spring Boot Actuator, según la configuración de nuestro proyecto.
Errores habituales al realizar pruebas de estrés
Hay algunos errores que pueden hacer que los resultados sean engañosos.
Probar únicamente en el ordenador de desarrollo. Si tanto el generador de carga como la API comparten los mismos recursos, es posible que el propio ordenador se convierta en el cuello de botella.
Lanzar demasiadas peticiones desde el principio. Es mejor empezar con una carga moderada, observar el comportamiento y aumentar progresivamente.
Mirar solo la media. Un tiempo medio bajo puede ocultar peticiones especialmente lentas. Por eso es útil observar percentiles como p95 y p99.
Ignorar la base de datos. La aplicación Java no trabaja aislada. Sus dependencias también influyen en el resultado.
No repetir las pruebas. Una sola ejecución puede verse afectada por la caché, el calentamiento de la JVM y otros factores. Conviene repetir los escenarios y comparar resultados.
Y una última recomendación: realiza estas pruebas únicamente contra sistemas propios o para los que tengas autorización, preferiblemente en un entorno de pruebas controlado. Una prueba de estrés mal planificada puede dejar un servicio inaccesible o afectar a otros usuarios.
Conclusión: mejor descubrir los problemas antes del lanzamiento
Los tests de estrés son una herramienta muy útil para conocer los lÃmites de una aplicación y evitar sorpresas desagradables cuando aumenta el tráfico.
No necesitas empezar con una infraestructura enorme ni lanzar millones de peticiones. Con una API sencilla, una herramienta como k6 y unas cuantas métricas puedes empezar a detectar problemas reales.
Si desarrollas aplicaciones Java, merece la pena incorporar estas pruebas a tu flujo de trabajo, especialmente cuando el rendimiento es importante.
Al final, no se trata de conseguir que una aplicación soporte cualquier cantidad de usuarios imaginable. Se trata de entender qué puede soportar, detectar sus puntos débiles y tomar decisiones con datos en lugar de hacerlo a ciegas.
---
Recursos para seguir aprendiendo
- "Apache JMeter" (https://jmeter.apache.org/)
- "Documentación oficial de k6" (https://grafana.com/docs/k6/ latest/)
- "Documentación de Gatling" (https://docs.gatling.io/)
- "Java Flight Recorder" (https://docs.oracle.com/en/ java/javase/)
