Escribiendo una herramienta de prueba de carga en Go

Motivación :

En una de mis organizaciones anteriores, teníamos el requisito de realizar pruebas de carga de microservicios basados ​​en Python y Scala que interactuaban en RabbitMQ (usando el protocolo AMQP 0.9, que es bastante diferente de AMQP 1.0)

Ya usábamos Jmeter como nuestra herramienta de prueba de carga preferida para las API Rest. Así que tenía pocas opciones para trabajar con

  1. Jmeter con algo de AMQP basado enchufar
  2. RabbitMQ en sí proporciona una forma cruda de cargar colas a través de su prueba de rendimiento herramienta
  3. La última opción era construir algo propio.

La herramienta Jmeter y RabbitMQ podría haber cumplido el propósito hasta cierto punto, pero eran más adecuadas para mensajes asíncronos. Algunos de nuestros microservicios utilizaron la funcionalidad rpc (llamada a procedimiento remoto) de RabbitMQ, que es más una comunicación síncrona entre el consumidor y el editor a través de las colas.

Ahora, si el uso de RPC sobre las colas de mensajes fue una elección de diseño correcta o no, es un tema de discusión para otro momento. 😃

La conclusión fue no usar el complemento Jmeter o la herramienta RabbitMQ Perf Test, sino construir algo propio

Estaba aprendiendo Go en ese momento y quedé muy impresionado con el modelo de concurrencia de Go. Pensé que era un buen momento y una oportunidad para convertir mi aprendizaje de Go en la implementación de algo útil, así que decidí crear una herramienta generadora de carga en Go.

Por cierto, hay una buena herramienta generadora de carga escrita en Go llamada Vegeta, pero es principalmente para HTTP.

Antes de comenzar a construir la herramienta, quería confirmar algunas cosas

  1. Había una biblioteca de cliente RabbitMQ disponible en Go porque RabbitMQ no proporciona una, afortunadamente había un cliente de código abierto biblioteca
  2. Supervisión de RabbitMQ en términos de CPU, memoria, E/S de disco del host que ejecuta el nodo RabbitMQ y luego las métricas de las colas individuales, como el total de conexiones, el total de consumidores, el total de mensajes, etc. en un momento determinado. Hay varias formas de hacer esto como se documenta aquí

Diseño:

Una vez que se confirmaron las cosas anteriores, comencé a pensar en la funcionalidad mínima que debería tener esta herramienta y decidí seguir el diseño de Jmeter para lo mismo. necesitaba controlar

  1. Número de subprocesos/usuarios
  2. Aumentar el tiempo para estos usuarios
  3. Tiempo de ejecución de la prueba.
  4. Manera de definir muestras/pruebas

Eso es todo. Si pudiera manejar estas 4 cosas, mi herramienta debería estar lista para usar.

Código:

Lo primero fue aceptar la entrada del usuario para No of User, Ramp Up time y Execution time. Esto fue bastante sencillo, pude configurarlo con banderas de línea de comando

1*icrb5c1Yu9ceOfl7dHvbww.png

Go recomienda tener nombres de variables más cortos. Si alguien está más interesado en saber más, aquí hay uno. presentación

Lo segundo fue calcular cuánto tiempo debería esperar Go antes de comenzar el siguiente hilo de usuario, lo cual también fue sencillo ya que tenía el número total. de usuarios para cargar y tiempo en el que todos los subprocesos de usuario deben estar en funcionamiento, por lo que el tiempo de espera entre el inicio de dos subprocesos de usuario consecutivos fue

1*jHzQ-ozIzGNGDIjHfNPKdA.png

Entonces, por ejemplo, si mi tiempo de aceleración fuera de 30 segundos y tuviera un total de 10 usuarios, crearía un nuevo hilo de usuario cada 3 segundos.

Ahora quería algo que pudiera incrementar el número de subprocesos del usuario según los cálculos de incremento. La mejor manera era iniciar una gorutina para ese trabajo.

gorutina es un subproceso ligero creado por el tiempo de ejecución de Go cuando se invoca cualquier función nombrada o anónima con una palabra clave prefijada go

A continuación, goroutine empuja el conteo de usuarios al canal cada vez que se incrementa, pero no iniciará el hilo del usuario real.

Canal objeto en Go es un medio de comunicación para que las gorutinas interactúen entre sí mediante el envío y la recepción de mensajes y se define por palabra clave chan

1*myPJnH_m2eJ-_94HP5NITg.png

Lo siguiente fue obtener un canal de tiempo que ayudaría a indicar el final de la duración de la ejecución.

1*Cbvpdo3dU0xyHUfOK4OdyA.png

Después de esto, el bit final fue usar los dos canales definidos en el código anterior para controlar el flujo y ejecutar las pruebas requeridas.
Este fragmento de código reúne todas las características principales de Go, lo que hace que la simultaneidad sea tan sencilla.

select es una declaración especial en Go que bloquea la ejecución hasta que cualquiera de los canales en caso de que las declaraciones estén listas para la operación de envío/recepción

1*-trWwnQgyC0HTKDNryDGEQ.png

¡¡Y eso era todo lo que necesitaba!! Acabo de agregar todas las llamadas de prueba requeridas en lo anterior for loop y pude bombardear las colas de mensajes de RabbitMQ con cientos de usuarios que ocupaban muy poca memoria en mi máquina generadora de carga.

Para monitorear e informar, ingresé todas las métricas en InfluxDB y usé Grafana para la visualización en tiempo real.

Go es un lenguaje extremadamente poderoso cuando se trata de concurrencia. Recomendaría a todos los entusiastas de Go que lean el libro. Concurrencia en Go escrito por Katherine Cox-Buday

Puede encontrar la esencia completa del código anterior aquí

Similar Posts

Leave a Reply

Your email address will not be published.