Cuando estamos desarrollando una nueva funcionalidad es posible que exista una necesidad de saber cuales son nuestras limitaciones y de esta manera armamos tooling que nos permita monitorear nuestros deployments, por otro lado creamos una expectativa y somos capaces de planear en base a datos capturados. De manera similar si existe algún cambio o solución a un bug que busque mejorar el rendimiento de un desarrollo existente tenemos que poder medir este cambio de punto A a B, de lo contrario solo estamos dependiendo de nuestra percepción.
Afortunadamente existen múltiples herramientas que nos permiten medir varios valores sobre cómo operan nuestros desarrollos. Podemos ir desde escenarios sencillos hasta un suite de prueba que parametrice cada ángulo de interés. Este tipo de pruebas tradicionalmente requieren una inversión de tiempo substancial, sin embargo no todos los desarrollos necesitan el mismo grado de evaluación, además es posible realizar pruebas que no necesiten este tipo de inversión, en particular si buscamos un indicador rápido que confirme que nuestros cambios apuntan a la dirección correcta.
Performance testing es un término que agrupa distintos tipos de pruebas que nos permiten conocer el nivel de rendimiento de nuestros proyectos, funcionalidades o cambios. Entre los tipos de performance testing más comunes tenemos stress testing y load testing.
Load testing nos valida si nuestro sistema opera de manera razonable bajo una “carga esperada”, por ejemplo: puede nuestro sistema satisfacer la cantidad de solicitudes de un viernes al mediodía? Stress testing nos indica como se ve nuestro sistema antes de que rompa, después de correr un stress test podemos decir algo como: “Nuestro sistema comienza a operar mal cuando tenemos más de 50 solicitudes concurrentes”.
Ahora que tenemos un marco conceptual en mente, exploremos herramientas que tenemos disponibles de forma inmediata y después otras que requieren un poco más de esfuerzo.
Los browsers modernos usualmente vienen equipados con dev tools. Para propósitos de este artículo estaremos referenciando “Google Chrome”. Si activamos los devtools en chrome y nos vamos a la pestaña de network somos capaces de visualizar datos valiosos si buscamos medir de manera limitada aspectos del rendimiento. El tiempo de respuesta es fácilmente la columna más importante si buscamos comparar un “antes y después” en el rendimiento para un cambio que busque optimizar algún servicio.
Un plan sencillo que pueda establecer si existe una mejora en el rendimiento utilizando los devtools se veria asi:
En términos relativos esta prueba establece si en nuestro ambiente local (o donde sea que se ejecute la prueba) hay una mejora o no, asumiendo que estamos trabajando con el mismo dataset.
El ejercicio que hicimos con los devtools de chrome se puede hacer de manera mas rapida e inclusive podemos obtener mas datos si usamos Apache Bench. Esta es una herramienta de Apache que el mismo describe como un “http web server benchmarking tool”.
Antes de replicar el mismo ejercicio tenemos que instalar la herramienta.
Recomendamos empezar una migracion para mejorar la experiencia de desarrollo utilizando WSL y despues seguir los recursos de linux para usar Apache Bench. De igual manera dejamos este link para poder seguir usando exclusivamente windows.
Apache Bench viene con Macos a partir de su release Big Sur, una vez estés en la terminal deberías poder confirmar ejecutando un simple:
> which ab
El cual nos debería dar una salida así:
< /usr/sbin/ab
Con este comando o equivalente en tu distribución de linux:
> apt-get install apache2-utils
Y después confirmamos por medio del PATH si está disponible ab:
> which ab
< /usr/bin/ab
Retomando nuestro ejercicio anterior ahora podemos hacer la misma prueba pero automatizando algunas partes y también obteniendo otros resultados:
> ab -c 50 -n 400 http://localhost:8080/login
< This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
< Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
< Licensed to The Apache Software Foundation, http://www.apache.org/
< Benchmarking localhost (be patient)
< Completed 100 requests
< Completed 200 requests
< Completed 300 requests
< Completed 400 requests
< Finished 400 requests
< Server Software:
< Server Hostname: localhost
< Server Port: 8080
< Document Path: /login
< Document Length: 6588 bytes
< Concurrency Level: 50
< Time taken for tests: 4.675 seconds
< Complete requests: 400
< Failed requests: 0
< Total transferred: 3046800 bytes
< HTML transferred: 2635200 bytes
< Requests per second: 85.55 [#/sec] (mean)
< Time per request: 584.430 [ms] (mean)
< Time per request: 11.689 [ms] (mean, across all concurrent requests)
< Transfer rate: 636.39 [Kbytes/sec] received
< Connection Times (ms)
< min mean[+/-sd] median max
< Connect: 0 0 0.4 0 2
< Processing: 43 533 98.6 537 669
< Waiting: 43 533 98.7 537 669
< Total: 44 533 98.4 537 669
< Percentage of the requests served within a certain time (ms)
< 50% 537
< 66% 566
< 75% 579
< 80% 598
< 90% 620
< 95% 643
< 98% 660
< 99% 663
< 100% 669 (longest request)
Primero inspeccionamos el comando, la opción -c con valor 50 indica que queremos una concurrencia de 50 requests, -n un total de 400 requests y como argumento el url a probar en este caso se trata de un endpoint que nos entrega una página en html para un formulario de login.
Los resultados son expresados en milisegundos (ms), rápidamente vemos como el interés de obtener un tiempo de respuesta promediado es resuelto, pero además bajo un contexto de múltiples demandas paralelas y también con un resumen de promedio, media, modal y rangos mínimo y máximo.
Ya con esta herramienta es posible armar un plan simple pero con una cobertura decente si queremos probar load, stress o inclusive algo como una prueba de paralelismo para comprobar algo como thread safety. Antes de ir con la última herramienta les dejamos un link con las opciones disponibles ya que estas nos dan flexibilidad para armar nuestras pruebas, inclusive capacidad de armar reportes csv y tablas personalizadas con outputs.
Otro dato importante es que usualmente vamos a querer utilizarlo sobre urls privadas que requieren autenticación. La opción -H nos permite entregar headers a los requests, aquí bien podemos agregar uno de “Authorization” e incluir nuestro jwt o oauth2 token.
Siguiendo el tema de este artículo, realizaremos una prueba similar con Jmeter. Jmeter también es una herramienta desarrollada por Apache, nos permite realizar pruebas funcionales (comportamiento) y performance.
Windows: Este es un buen link para instalar jmeter en windows.
Para macos recomendamos usar homebrew o brew para instalar jmeter:
> brew install jmeter
> which jmeter
< /opt/homebrew/bin/jmeter
Dependiendo de su equipo el path a Jmeter puede ser diferente. Y podemos ejecutar así:
> open /opt/homebrew/bin/jmeter
Primero verifique que java está instalado ya que es un requerimiento para correr jmeter:
> java --version
Ahora descargamos los binarios aqui y una vez lo guardamos podemos ejecutarlo así:
> ./opt/apache-jmeter-5.6.3/bin/jmeter
Opcional se puede exponer al PATH para convenientemente solo ejecutar:
> jmeter
Jmeter es una herramienta más sofisticada y por lo tanto su curva de aprendizaje tiene más detalles a considerar que las otras dos pruebas. Con Jmeter podemos básicamente hacer un “script” y ejecutar flujos completos. Vamos a replicar la misma prueba que hemos hecho pero consideren que podríamos simular un flujo de login completo y analizar los resultados desde ese punto de vista.
Para poder replicar la prueba tenemos que armar nuestro plan, lo podemos lograr de la siguiente forma:
La estructura de tu test plan se deberia ver asi:
Ahora salvamos con el botón de “Save” los cambios al plan y ejecutamos con el botón de “Play”:
Result tree nos permite ver de manera “tabulada” cada request hecho para inspeccionar algún detalle de interés:
Summary report es similar a lo que hemos hecho con los otros ejercicios:
Queremos enfatizar que tanto con AB como Jmeter en particular podemos hacer pruebas más personalizadas para simular escenarios reales, sin embargo también queremos comprobar que se pueden obtener resultados decentes con una pequeña inversión de tiempo.
Otro aspecto importante, si combinamos estas pruebas con alguna solución de profiling somos capaces de encontrar bottlenecks, puntos de falla o redundancias que podrían ser eliminadas. Por último esto puede ser incluido en flujo CI/CD si hay una necesidad de probar de manera recurrente como parte de algo como un smoke test, pero tendríamos que ejecutar jmeter en modo non-gui.
¿Cuáles son los puntos ciegos en tu proyecto que no tienes seguridad o confianza de poder probar antes de salir a producción? Prioriza las funcionalidades más críticas que deberían tener cobertura y arma un plan para las mismas. De igual manera las funcionalidades existentes se pueden medir en su estado actual y después podemos comparar con los nuevos cambios para sacarle más provecho a nuestros esfuerzos.