En ciertas ocasiones durante el proceso de las pruebas de performance es posible alcanzar el límite de carga que puede ser generado por un solo equipo, ya sea debido al hardware del mismo, o por limitaciones de la herramienta de generación de carga, en este caso, JMeter.
Al enfrentarnos a esta situación, la forma de continuar con las pruebas de performance es realizando una distribución de la generación de la carga en distintos equipos. Desde un equipo “Master” se podrán controlar múltiples nodos remotos “Esclavos” que serán los encargados de generar la carga de manera distribuida y así alcanzar un mayor número de usuarios concurrentes.
Introducción
Esta técnica también se puede aplicar con equipos virtuales en la nube, permitiendo escalar rápidamente y en caso de ser necesario ejecutar desde distintas ubicaciones geográficas.
El objetivo de esta guía es indicar de forma clara y concisa los pasos necesarios para poder realizar una ejecución de pruebas de performance distribuidas a través de la herramienta JMeter, tanto en Windows como en Linux.
Componentes
Antes de comenzar con la configuración, se desplegará aquí la información sobre los principales componentes de la ejecución.
Las imágenes presentadas a continuación ilustran la forma de trabajo de la ejecución distribuida:
Master: La instancia o máquina desde donde se estará controlando las pruebas distribuidas que se ejecuten desde otras máquinas generadoras de carga.
Esclavas: Instancias o máquinas generadoras de carga.
Pasos previos
Antes de comenzar con las configuraciones tanto de las generadoras como del nodo master, es necesario realizar ciertas validaciones:
Versiones
Lo primero que se debe verificar es que los nodos (Master y Esclavas) cuenten con la misma versión de JMeter y Java instalados.
JMeter
Para verificar la versión de JMeter en el equipo ejecute la herramienta abriendo el archivo ApacheJMeter.jar ubicado dentro de la carpeta carpetaJMeter/bin. Luego, cuando se abra la aplicación, verifique la versión titulada junto al nombre en la parte superior izquierda, tal como se muestra en la imagen debajo.
En caso de no contar con interfaz gráfica, desde la terminal, y ubicado en el directorio donde se encuentra JMeter, ejecute el comando Jmeter -v y deberá ver algo similar a la siguiente captura.
Java
Desde la terminal ejecute el comando java -version
Verificación de Subred
Para poder hacer uso de la ejecución de pruebas distribuidas se debe corroborar que tanto la Master como las Esclavas están dentro de la misma subred. Lo dicho anteriormente es una condición que exige la herramienta.
Para verificar que los equipos se encuentran dentro de la misma subred, desde la terminal y en cada uno de los equipos, ejecutar el comando ipconfig (ifconfig en Linux) y verificar que en donde dice Máscara de subred los primeros nueve dígitos sean iguales.
Firewall
Se debe permitir el tráfico a través de ciertos puertos, los cuales son indicados más adelante en el documento.
Configuración SSL del RMI
RMI (Remote Method Invocation) es un protocolo de comunicación que permite a un programa en una máquina virtual de Java (JVM) invocar métodos en un objeto remoto, que se encuentra en otra JVM en una máquina diferente.
En aplicaciones que utilizan RMI, el SSL puede ser utilizado para asegurar la conexión entre el cliente y el servidor.
Para poder correr las pruebas de forma distribuida, JMeter provee un script para generar un almacén de claves RMI que contiene una clave y su certificado correspondiente.
El script se encuentra en el directorio bin y está disponible para sistemas Windows (llamado bin/create-rmi-keystore.bat ) y sistemas Linux (llamado bin/create-rmi-keystore.sh ).
Luego de ejecutado el script (se recomienda ejecutarlo desde dentro del directorio), se generará un par de claves, que serán válidas durante siete días, con una frase de contraseña predeterminada de valor ‘changeit’.
Cuando ejecute el script, le hará algunas preguntas sobre algunos nombres que incluirá en el certificado. Puede ingresar valores propios, siempre que la herramienta de almacenamiento de claves lo acepte. Ese valor tiene que coincidir con la propiedad “server.rmi.ssl.keystore.alias” , que por defecto es ‘rmi’.
Al utilizar Linux, se pedirá una password.
A continuación se presenta un ejemplo para poder crear satisfactoriamente el almacén de claves:
$ cd jmeter/bin
$ ./create-rmi-keystore.sh
What is your first and last name?
[Unknown]: rmi
What is the name of your organizational unit?
[Unknown]: My unit name
What is the name of your organization?
[Unknown]: My organization name
What is the name of your City or Locality?
[Unknown]: Your City
What is the name of your State or Province?
[Unknown]: Your State
What is the two-letter country code for this unit?
[Unknown]: XY
Is CN=rmi, OU=My unit name, O=My organization name, L=Your City, ST=Your State, C=XY correct?
[no]: yes
Luego de configurado el almacén, se debe copiar el archivo bin/rmi_keystore.jks en cada servidor y cliente de JMeter que desee utilizar para su configuración de pruebas distribuidas.
En caso de no desear configurar el SSL para el RMI, se puede simplemente deshabilitar indicando en el jmeter.properties el parámetro server.rmi.ssl.disable con el valor ‘true’. Tanto en el nodo Master como en los Esclavos.
Configuración de JMeter
Luego de realizadas las verificaciones previas y de configurar el SSL para RMI, se deben de configurar los hosts a ser utilizados por la Master.
Los mismos deben ser indicados por extensión dentro del archivo jmeter.properties.
- En el nodo del controlador que actúa como Master, diríjase al directorio jmeter/bin
- Abra el archivo jmeter.properties (utilizando el editor de texto de su preferencia)
- Dirijase a la linea remote_hosts
- Agregue la dirección IP o nombre de host de cada nodo Esclavo (separados por comas)
En el siguiente ejemplo se indican 5 equipos como generadores de carga. Cuatro de ellos a través de IP, y uno por nombre de host:
remote_hosts=192.168.0.10,192.168.0.11,esclava_3,192.168.0.13,192.168.0.14
Especificación de puertos
Para poder llevar a cabo una correcta ejecución del script, los nodos Master y Esclavos deben comunicarse entre sí a lo largo de toda la prueba.
En primera instancia el nodo Master debe realizar una conexión con los nodos Esclavos y ciertas verificaciones, luego se indica el comienzo de la ejecución a todos ellos, y finalmente debe indicar el fin de la ejecución del script. Por otro lado, los nodos Esclavos deben reportar periódicamente los resultados preliminares durante la ejecución de la prueba.
Para poder realizar esta comunicación entre nodos, la herramienta JMeter utiliza distintos puertos los cuales por defecto son asignados de forma aleatoria al momento de la ejecución. Si por el contrario se desea indicar estos puertos de forma manual, ya sea para permitir el tráfico únicamente por estos, o simplemente para tener un mayor control durante la ejecución, se deben realizar las siguientes configuraciones sobre el archivo jmeter.properties.
Puerto RMI
En los nodos Esclavos buscar el parámetro server_port e indicar el puerto deseado como se muestra en la siguiente captura:
En el nodo Master buscar el parámetro remote_hosts e indicar el puerto luego de la dirección IP o nombre de host como se muestra en la siguiente captura:
Puerto local cliente RMI
En el nodo Máster buscar el parámetro client.rmi.localport e indicar el puerto deseado como se muestra en la siguiente imagen:
Tener en cuenta que JMeter utiliza el puerto indicado y el siguiente.
Puerto local servidor RMI
En el nodo Esclavo buscar el parámetro server.rmi.localport e indicar el puerto deseado como se muestra en la siguiente captura:
Ejecución distribuida
Antes de dar inicio a las pruebas, y de ser posible, todas las generadoras deben tener la misma ruta accesible (por ejemplo C:\JMeter\Script\ en Windows o /home/ubuntu/Script/ en Linux) de forma tal que la ejecución del script funcione sin problemas. De lo contrario, dejar todos los archivos necesarios para la ejecución (csv, imágenes, etc.) dentro de la carpeta /bin de JMeter.
Luego de realizados y/o verificados todos los pasos anteriores, procedemos a dar comienzo al inicio de las pruebas. Una vez que esté todo configurado, ejecutar el comando “jmeter-server” en cada uno de los nodos Esclavos para iniciar el servicio de JMeter en modo servidor.
En Windows al ejecutar el jmeter-server.bat, si el proceso logró ejecutarse sin problemas, la terminal quedará como la imagen que se ve a continuación:
En Linux, el archivo a ejecutar es el jmeter-server, y es posible que se necesite otorgar permisos de ejecución sobre los archivos jmeter-server y jmeter.
A partir de este momento, los nodos Esclavos quedarán a la espera de que se les indique el comienzo de las pruebas.
Inicio de las pruebas
Existen distintas formas de iniciar la ejecución distribuida, en primer lugar, y solo a modo de depuración o verificación de la correcta configuración, utilizando la GUI (Graphic User Interface).
Por otro lado y ya enfocado en la ejecución formal de las pruebas, a través del CLI (Command Line Interface).
GUI
Para verificar la correcta configuración de todos los componentes, incluso el script en sí mismo, se recomienda hacer una primera ejecución desde la GUI de ser posible.
Para esto, iniciar JMeter de forma tradicional, abrir el Plan de Pruebas (archivo .jmx), dirigirse al menú Run y elegir la opción Remote Start. Se desplegará un menú con los hosts remotos configurados en el archivo jmeter.properties. Allí se podrá seleccionar uno y verificar el correcto funcionamiento del script con alguno de los elementos de depuración (View Results Tree o cualquier otro Listener de preferencia). También se debe visualizar en la terminal donde está ejecutando jmeter-server el inicio y finalización del script.
En el menú Run también es posible seleccionar la opción Remote Start All. En ese caso se iniciará la ejecución en todas las generadoras configuradas en el archivo jmeter.properties.
Es importante tener en cuenta que la configuración de los Thread Group aplica para cada una de las generadoras. Es decir, si se cuenta con 3 nodos Esclavos y se ejecuta el script desde el nodo Master configurado con 10 usuarios, cada generadora simulará 10 usuarios, llegando a un total de 30.
CLI
Si se cuenta con la configuración correcta en el jmeter.properties, simplemente se debe agregar la opción “-r” a la ejecución por línea de comandos que se utiliza normalmente, por ejemplo:
jmeter -n -t <ruta_al_script> -r
La opción “-r” toma a todas las esclavas mencionadas en la propiedad remote_hosts.
Por el contrario, se pueden indicar los nodos esclavos al momento de la ejecución, utilizando la opción “-R” seguido de las direcciones IP o nombres de hosts de los nodos Esclavos.
jmeter -n -t <ruta_al_script> -R server1,server2,…
Errores conocidos y soluciones
Error de SSL en equipos Linux
En algunas ocasiones, en equipos Linux se pueden presentar errores al configurar el SSL para RMI. En estos casos, la solución encontrada es cambiar el tipo del almacén de claves.
Para esto, se debe generar una nueva keystore rmi (llamada rmi_keystore2) que permita trabajar en este sistema:
- Ingrese al Terminal
- Diríjase a la carpeta /bin
- Ejecute el siguiente código:
keytool -importkeystore -srckeystore rmi_keystore.jks -destkeystore rmi_keystore2.jks -deststoretype pkcs12 -destkeypass <password>
- Ahora ingrese la password de su rmi_keystore2.jks.
A partir de aquí, trabajará con el archivo rmi_keystore2.jks. Se recomienda renombrarlo en los nodos Esclavos como rmi_keystore.jks, igual que el original.
Non HTTP response code
Durante la ejecución de las pruebas, cuando la capacidad de generación de las Esclavas llega a su límite, pueden aparecer excepciones como las siguientes:
- javax.net.ssl.SSLHandshakeException/Non HTTP response message: Remote host terminated the handshake
- javax.net.ssl.SSLException/Non HTTP response message: Connection timed out (Read failed)
En esos casos se recomienda contar con una mayor cantidad de nodos Esclavos y utilizar equipos en la nube aplicando las configuraciones para alta concurrencia.
Configuraciones para alta concurrencia
Dependiendo de la complejidad del script y los recursos necesarios para ejecutarlo, el límite de una generadora de carga puede estar en distintos niveles de concurrencia. Con estas configuraciones, un script de baja complejidad y en equipos con las siguientes características, se probó generar hasta 25.000 usuarios activos por instancia, pudiendo tener hasta 2 instancias de jmeter-server ejecutando en paralelo, llegando a 50.000 usuarios concurrentes por instancia de AWS.
Tipo de instancia esclava en AWS: r5b.12xlarge
RAM: 384GB
vCPU: 48 cores
Network: 10 Gigabit
En caso de que la infraestructura de ejecución este desplegada en AWS, tanto los equipos master como los esclavos deben encontrarse en la misma zona de disponibilidad:Habilitar tráfico en Amazon Web Services (AWS)
Si se utilizan equipos en la nube, por ejemplo AWS, se deberán generar las reglas de entrada para el nodo Master, así como para los nodos Esclavos.
En las siguientes capturas se puede ver la forma de hacerlo:
MasterEsclavos
Cuando se alcanza el límite pueden suceder distintos errores o excepciones de Java, JMeter o del sistema operativo mismo. En esos casos es importante aplicar las siguientes configuraciones:
Parámetros del Sistema Operativo (Linux)
En primer lugar se deben configurar los parámetros de ejecución del kernel. Para esto modificar el archivo /etc/sysctl.d/99-sysctl.conf (archivo de texto, se puede usar nano o vi) e incluir los siguientes parámetros:
kernel.shmall = 4294967296
fs.file-max = 250000
net.ipv4.ip_local_port_range = 1024 65535
kernel.pid_max = 4194303
net.ipv4.tcp_tw_reuse = 1
Actualizar los parámetros de las nuevas configuraciones con el siguiente comando:
sysctl -p
Preparación JMeter
Agregar setenv.sh en la ruta /bin del JMeter y definir los parámetros de la JVM como sigue:
export HEAP=”-Xms32G -Xmx32G -XX:MetaspaceSize=1G -XX:MaxMetaspaceSize=1G”
Configuración de múltiples instancias JMeter
Copiar la carpeta de instalación de JMeter, e incluir un -1 y -2 sobre el final, quedando por ejemplo:Se debe levantar cada uno de los jmeter-server correspondientes para cada instancia JMeter en el equipo, y tener en cuenta las configuraciones de puertos necesarios.
Verificacion
Para verificar si la configuración del equipo soporta los 50.000 usuarios, se puede utilizar un script de prueba y ejecutar de la manera que se muestra a continuación:
Es posible verificar la cantidad de threads durante la ejecución con el siguiente comando:
ps -eLf | grep java | wc -l
Conclusiones
En esta guía se presentaron los pasos para llevar a cabo una prueba de carga de manera distribuida utilizando la herramienta JMeter, sobre sistemas operativos Windows y Linux.
Se plantea una configuración específica para alta concurrencia probada con equipos en la nube AWS generando hasta 1 millón de usuarios concurrentes utilizando hasta 20 nodos Esclavos.
Utilizar instancias en AWS para llevar a cabo la ejecución de las pruebas de carga brinda la escalabilidad necesaria para simular diferentes escenarios.