intive Argentina Blog

Llevando tus test de JMeter a otro nivel con Taurus

La necesidad es la madre de la invención… O en este caso, la necesidad es la madre de las búsquedas en Google que nos llevaron a conocer Taurus. Se trata de un “wrapper” para nuestros tests de Jmeter, aunque “wrapper” le queda un poco chico. Este artículo surgió luego de vernos en la necesidad de probar un sistema con más de 100 mil requests por minuto. Esto llevó la infraestructura a sus límites y nos obligó a escalar nuestros tests a otro nivel. A lo largo de las próximas líneas voy a intentar contarles un poco lo que aprendí.

El principio de la historia

Jmeter es una herramienta básica que casi todos los desarrolladores deberíamos saber usar. Con ella podemos hacer pruebas de stress o automatizar sanity tests de una forma bastante eficiente, una vez que le agarramos la mano. Al principio, Jmeter puede parecer un poco tosco. Pero luego, cuando corremos los scripts en cualquier máquina, empezamos a notar su poder. Y cuando comenzamos a usarlo para generar testing distribuido desde varios servers a la vez, vemos que es casi mágico.

Ahora, volviendo al ejemplo práctico de nuestra necesidad inicial (probar ese sistema con más de 100 mil requests por minuto), en este caso JMeter nos interesaba solamente para medir performance relacionada a tiempos de respuesta y códigos http, no necesitando agregar assertions, o extraer datos de los responses. A continuación, el paso a paso de nuestra experiencia.

Creemos una app para testear

Vamos a usar node y express para crear un web server sencillo. Usando la terminal nos paramos en la carpeta donde queremos tener el código y corremos npm init. Completamos los datos que nos pide y luego npm install -D express, y con eso instalamos express. Por último creamos un archivo app.js, con el siguiente contenido (los comentarios en el código explican que hace cada cosa):

 

Son 3 endpoints: uno que siempre responde bien, otro que es lento, y un último que falla intermitentemente.

Con esto hacemos node app.js y nos queda la aplicación corriendo, lista para testearse.

Test con Jmeter

Con Jmeter ahora vamos a crear un test básico, pero configurable para que no necesitemos volver. Lo primero que agregaremos es un elemento “setUp Thread Group”. Allí definiremos nuestros valores por defecto para cantidad de usuarios, rampup y loop count, pero lo haremos de forma que podamos sobrescribir estos valores cada vez que corramos el test. Eso nos facilitará la vida más adelante.

En Number of Threads pondremos ${__P(threads,1)} donde threads es un parámetro que podemos pasar al correr el test, y si no lo pasamos tomará el valor por defecto 1. Luego en Ramp-Up Period pondremos ${__P(rampup,1)} y en Loop Count ${__P(loops,1)}. Nos quedaría algo así:

Para estas pruebas no lo necesitamos, pero podríamos definir, por ejemplo, un elemento de “User Defined Variables” para tener control sobre otros elementos del test.

Luego de esto, vamos a agregar las llamadas a los endpoints que queremos hacer. Agregamos 3 elementos “HTTP Request” y completamos los datos. Server Localhost, Port Number: 3000 y Path, el que corresponda a cada uno (fast, slow, fail). Por ejemplo:

Por último, agregaremos un listener: Aggregate Report, para ver un summary de nuestras pruebas. Este listener nos dará información como el promedio de tiempo de respuesta, la mediana y los percentiles 90, 95 y 99, así como también el % de errores. Los percentiles son especialmente útiles en los escenarios de alta carga, ya que el promedio puede mostrarnos valores que no se condicen con la experiencia general de los usuarios.

Si lo corremos con la configuración actual, solo nos va a servir para verificar que todo esté funcionando, ya que solo hará un request a cada endpoint. Si agregamos más threads la cosa se empieza a poner interesante. Si ponemos 1000 threads, por ejemplo nos encontraremos con esto:

Es mucha información, al principio cuesta entenderlo. De la tabla de datos las columnas Median, 90%, 95% y 99%, nos dan el tiempo máximo que tardaron los request de cada uno de esos percentiles. Por ejemplo, el endpoint /fast: 90%: 272 quiere decir que el 90% de los request tardaron 272 milisegundos o menos.

Así podemos ver que el endpoint lento es muy lento. El 50% de los request tardó más de 582 milisegundos. También podemos sacar la conclusión de que el 40% de los request a ese endpoint demoró entre 582 y 971 milisegundos.

Por otra parte, podemos observar en la columna Error %, que cerca del 76% de los request /fail tuvo errores de algún tipo., considerándose error a todos los request que no tengan un response con código http 200. Eso es configurable, pero para nuestro caso de uso no necesitamos nada más.

Corriendo los tests desde la terminal

El entorno gráfico de JMeter está pensado solo para crear los tests. Para correrlos y aprovechar su poder, se recomienda correrlo de la terminal. Guardemos el test: test.jmx y vayamos a una consola. Allí podremos correr el test con el comando jmeter -n -t test.jmx.

El resultado puede ser algo aburrido… Estamos corriendo el test con los valores por defecto de 1 thread, 1 segundo de rampup y 1 loop. Vamos a pasar esos parámetros para ver su poder. Los parámetros se pasan con -J<parameterName>=<valor>. Por ejemplo, podemos correr: jmeter -n -t test.jmx -Jthreads=2000 -Jrampup=33 lo que nos correrá nuestros tests con 2000 usuarios y esos usuarios irán “conectándose” a lo largo de 33 segundos.

El resultado en la consola puede no ser lo más informativo del mundo. Pero les puedo asegurar que hay mucha información, especialmente cuando hacemos tests de carga durante mucho tiempo. Con estos parámetros podemos ver un output parecido a este:

Si queremos generar un output podemos correr el mismo test con el parámetro -l, para indicar un archivo a donde queremos volcar la información de las pruebas. Así, por ejemplo, podríamos correr: jmeter -n -t test.jmx -Jthreads=2000 -Jrampup=33 -l out.jtl y luego ese archivo out.jtl lo podemos cargar desde el entorno gráfico de JMeter para ver los resultados con los listener que tengamos agregados.

Reporting y corrida de tests con Blazemeter

Para hacer reporte de estas pruebas, JMeter tiene varios listener muy útiles pero algo toscos si se piensan mostrar a usuarios finales o fuera del ámbito de sistemas. Hay algunas opciones para poder tener mejores visualizaciones, incluso existen las que nos permiten correr los tests desde un entorno web. Blazemeter es una de ellas.

Sin dudas, el reporting mejora mucho con esta herramienta. Y los gráficos son súper amigables con el usuario final. La imagen de arriba es del overview, la vista más básica. Entrando a Timeline Report se pueden armar reportes de los KPIs que consideramos más importantes, sin ningún problema.

Blazemeter, en su versión gratuita, nos deja experimentar y hacer algunas pruebas que no impliquen demasiada carga. Si queremos hacer pruebas de stress en serio hace falta alguno de los planes pagos. Incluso los planes pagos pueden quedarse cortos cuando se busca llevar las cosas al límite. Esto nos pasó cuando necesitamos superar los 20 mil requests por minuto y no teníamos presupuesto para un plan custom, el plan que estábamos pagando no nos servía para generar esa carga.

Afortunadamente Blazemeter mantiene una herramienta open source llamada Taurus que nos permite coordinar nuestras pruebas de una forma bastante simple.

Probemos Taurus

Para usar Taurus necesitamos Python. Mi recomendación es hacer estas pruebas dentro de un virtualenv. Suponiendo que tenemos todo instalado es tan sencillo como correr: virtualenv Taurus y luego source ./taurus/bin/activate. Una vez que el virtualenv esté creado, solo nos queda instalar Taurus con pip install bzt

Para validar que tengamos todo bien, la prueba más rápida que podemos hacer es crear un archivo test.yml con el siguiente contenido:

 

Luego de descargar algunas dependencias extras (la primera vez que lo corremos, nomás) intentará tener 100 threads al mismo tiempo durante 5 minutos y nos los mostrará de una forma amigable en la consola. Si eso sucede, es que tenemos todo listo para realizar nuestras pruebas usando Taurus.

El resultado es bastante interesante… Y aunque al principio la interfaz es algo intimidante, tiene un montón de información útil. De izquierda a derecha y de arriba abajo podemos ver:

  • 3 gráficos
    • Usuarios totales y activos
    • Hits y errores
    • Tiempos de respuesta
  • Estadísticas del último intervalo (muestreo)
    • Tiempos de respuesta
    • Percentiles
    • Response codes
  • Estadísticas acumulativas con los mismos datos de antes
  • Principales endpoints
  • Principales errores

Por último, a la derecha debajo del logo de Taurus podemos ver:

  • Estadísticas generales del test
  • Estado del servidor donde estamos corriendo las pruebas
  • Mensajes informativos que genera Taurus

En estas pruebas se ve una serie de errores, probablemente porque estoy haciendo todo en mi máquina y no logra procesar todos los requests.

Corriendo JMeter con Taurus

Para hacer esto, lo más sencillo es tener los archivos .jmx y .yml en la misma carpeta. Al test de JMeter lo renombré como jmeter.jmx únicamente por comodidad. Al archivo de configuración test.yml lo dejamos con este contenido:

 

Allí le estamos diciendo que corra el test que definimos en JMeter y que sobreescriba los threads y el loop count. Con esto, el test correrá bastante rápido y es probable que no veamos la interfaz. Así tenemos todo preparado para correr nuestras pruebas de una forma bastante elegante, solo nos faltaria algo de reporting. Aunque es de destacar que Taurus genera una carpeta con todo el output de JMeter, con algo de paciencia se podrían armar reportes en base a esos datos en crudo.

Podemos, por ejemplo, agregar un reporting para poder comparar ejecuciones. Una forma rápida de hacerlo es usando el módulo final-stats. La configuración nos quedaría así:

 

Agregué iteraciones y concurrencia para tener un volumen de datos más interesante.

Mientras se ejecuta la prueba, podemos ver algo prácticamente idéntico a las ejecuciones anteriores y tal vez un poco más de info por que estamos haciendo muchos más requests.

Al finalizar las pruebas veremos un resumen con los percentiles, porcentaje de error, duración de la prueba, fails por endpoint, etc.

A su vez, todos estos datos se guardan en un xml que luego podemos importar en alguna herramienta para poder hacer las comparaciones que consideremos.

Hacer reportes de Taurus con Blazemeter

Sin dudas, el reporting de Blazemeter es mucho mejor que cualquier otro que hayamos visto hasta ahora. Pero correr nuestras pruebas en su plataforma es relativamente caro. Una posibilidad es usar la opción de reporting en Blazemeter de Taurus. Con esto tenemos todas las ventajas de ese genial reporting, sin el costo de correr las pruebas en sus servidores.

Este reporting tiene algunas limitaciones: por ejemplo solo es visible durante una semana. Pero, sin dudas, vale la pena probarlo en nuestros proyectos. Para hacerlo tenemos dos opciones: desde la consola ejecutamos la prueba con el parámetro -report quedándonos algo así: bzt test.yml -report o editamos nuestro archivo de configuración y agregamos el módulo blazemeter a la sección de configuración de reporting.

Un punto destacable es que no necesitamos credenciales para tener los reportes en Blazemeter. De todas formas es una buena práctica agregarlas, así cuando nos logueamos podemos ver esos reportes en un mismo dashboard y hacer nuestras comparaciones directamente en la ui que Blazemeter nos proporciona.

Es también digno de mencionar que ejecutándolo en local Taurus nos abre una nueva pestaña en el navegador y podemos ver live como corre el test desde la ui de Blazemeter. Esta funcionalidad es muy útil para las personas menos técnicas. A mí  personalmente me gusta más el reporting live que hace en la consola.

Test summary con Blazemeter

Tenemos un montón de opciones para visualizar los datos que generamos con nuestras pruebas. Algunas de ellas muy poderosas, con muchas opciones. Una de las más sencillas y a la vez más importantes, es la que genera el executive summary. Como el resultado solo se guarda una semana, hice una captura para poder mostrar todos los datos que muestra.

Como podemos observar nos muestra dos gráficos bastante útiles:

  • Usuarios activos (o threads) y requests por segundo.
  • Usuarios activos, response time y latencia por el otro.

En el ejemplo podemos ver cómo, un poco después de la mitad de la prueba, los tiempos de respuesta de esta demo empezaron a ser malos. Luego podemos analizar los por qué: ¿Por que el tiempo de respuesta se disparó? o ¿Por que hay errores en endpoints que no deberían fallar? Pero esa es otra larga historia.

Este conjunto de herramientas sirve para generar muchos tipos de pruebas. Todo depende de la necesidad que estemos tratando de cubrir. Podemos, por ejemplo, generar tests de stress usando la funcionalidad de testing distribuido, o también agregar assertions a nuestras pruebas para verificar el contenido de las respuestas.

¿Es este el mejor stack que podemos elegir?

Seguramente no. Pero fue el que nos permitió cubrir nuestras necesidades de forma más satisfactoria. Tampoco conocíamos muchas otras opciones, salvo tal vez, flood io.

Necesitábamos probar la performance y, para eso, JMeter es una de las soluciones más antiguas y estables. Algo tosca, con documentación no siempre entendible, pero súper potente.

Necesitábamos asimismo reporting “bonito” y entendible para gente no tan técnica. Blazemeter era una de las opciones que barajamos. El correr los tests en su propia infra era una buena opción, pero lo que inclinó la balanza fue el poder correr los tests en nuestra propia infra y solo usarlo para hacer reporting (y esto de forma totalmente gratuita).

Por último, nos hacía falta reconfigurar los tests repetidamente, buscando sacar el mayor provecho de la infraestructura. Aunque eso se puede hacer directamente con JMeter, Taurus nos ofrecía una forma mucho más elegante. A su vez, nos servía como proxy para generar los reportes, así que no había mucho para decir ahí.

Aunque al principio parece mucho overhead configurar estas herramientas y tener algo funcional, todo es bastante rápido. Mientras escribía este artículo nos vimos en la necesidad de medir los tiempos de respuesta de un sitio web con unas 15 secciones y, en solamente 3 horas, teníamos los reportes listos. Esto me lleva a recomendar el stack para casi cualquier tamaño de proyecto que estén necesitando testear.

Gracias por leer. Happy Testing.

Fernando Lescano

Es uno de nuestros líderes técnicos y desarrollador full stack de intive – FDV desde marzo de 2015. En la empresa trabaja con tecnologías como Javascript (NodeJS, AngularJS, Mongodb, Jquery, etc.), Python (Django), Java y PHP e integra la brigada Frontend. Se define como “apasionado del desarrollo de software, pero con muchos otros intereses”. Desde diciembre de 2015 se ocupa del desarrollo y mantenimiento en Java y de nuevos componentes en JavaScript (AngularJS). Es Técnico Universitario en desarrollo de software y tecnologías de la información, graduado de la Universidad Provincial de Ezeiza.

Deja un comentario