Tests de rendimiento con Artillery

0
8827

Índice de contenidos


1. Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: Slimbook Pro 13.3″ (Intel Core i7, 32GB RAM)
  • Sistema Operativo: LUbuntu 16.04
  • Visual Studio Code 1.16.1
  • NodeJS v9.3.0
  • artillery 1.6.0-12


2. Introducción

Quien más quien menos cuando le hablas de pruebas de rendimiento y stress de un API o de una web piensa automáticamente en JMeter, de hecho en Adictos somos muy fans de JMeter.

Pero los tiempos cambian y aunque JMeter sigue siendo una herramienta muy útil para este tipo de tests, han surgido con fuerza otras herramientas más «modernas» como la que presentamos en este tutorial: Artillery.

Se trata de una herramienta implementada en NodeJS que a través de la declaración de un fichero de configuración permite definir, entre otras cosas, el número de usuarios y peticiones que se van a simular y registrar los resultados de latencia y duración para el mínimo, el máximo, la mediana, el percentil 95 y el percentil 99.

También podemos configurar plugins que nos permiten generar otras métricas e integrarlas con herramientas de visualización, es compatible con tecnologías y herramientas como: StatsD, InfluxDB, Graphite, Grafana, ElasticSearch, Kibana…

En este tutorial vamos a ver cómo configurar el plugin que genera las métricas para StatsD y cómo hacer la integración con Graphite y Grafana para la visualización de resultados.


3. Vamos al lío

Como en toda aplicación moderna que se precie, la instalación no puede ser más sencilla gracias a NodeJS.

Nota: si no tienes instalado NodeJS es un buen momento para instalarlo con NVM siguiendo este tutorial (debes utilizar la última versión actual).

Con una instancia de NodeJS y NPM es tan sencillo como:

$> npm install -g artillery

¡Y ya está! 🙂

La herramienta tiene el comando «quick» que nos permite lanzar un test rápido contra la URL que definamos, pudiendo establecer los siguientes modificadores:

  • -d, –duration <número de segundos>
  • -r, –rate <número de segundos para el ratio de llegada de peticiones>
  • -p, –payload <cadena con el Payload de una petición POST>
  • -t, –content-type <cadena con el content type>
  • -o, –output <cadena con el path del archivo de salida>
  • -k, –insecure <deshabilita la verificación del certificado TLS>
  • -q, –quiet <establece el modo «quiet» con lo que no se muestra ningún log>

De esta forma si queremos simular 10 usuarios enviando 20 peticiones cada uno, simplemente tenemos que ejecutar:

$> artillery quick --count 10 -n 20 url_deseada

Y recibiremos un resultado por consola similar a este:

Resultados quick

Como ves nos ofrece un resumen por consola indicando métricas de latencia y de duración así como el número total de peticiones efectuadas y tantas por segundo, entre otra información.

Esto está bien para una prueba rápida y típica de un endpoint de un API que no requiera seguridad. Para otro tipo de pruebas más avanzadas tenemos que recurrir al comando «run» que a parte del fichero de configuración de la prueba, admite los siguientes modificadores:

  • -o, –output <cadena con el path del fichero de salida>
  • -k, –insecure deshabilita la verificación del certificado TLS
  • -e, –environment <cadena con el entorno deseado>
  • -t, –target <url del server, sobrescribe la que haya definida en la propiedad «target» del fichero de configuración>
  • -q, –quiet deshabilita los logs por consola
  • –overrides sobrescribe partes enteras del fichero de configuración

La definición del fichero de configuración puede realizarse en un fichero con extensión .yml que siempre empieza con «config:» y a esta propiedad le pueden seguir:

  • target: define la URL del endpoint que queremos probar. Generalmente almacena la base URL del servidor al que se ataca.
  • phases: en esta propiedad se define los determinados momentos en la prueba, donde podemos definir que las peticiones se comporten de una determinada manera durante un tiempo establecido. Cada «phase» se puede definir con las siguientes propiedades:
    • duration: define la duración completa de la «phase».
    • arrivalRate: es el número de peticiones por segundo que van a llegar durante la duración definida
    • rampTo: define el número que se quiere alcanzar a partir del definido en «arrivalRate» en el período de tiempo establecido.
    • arrivalCount: es el número de usuarios virtuales que se quieren tener en el periodo de tiempo establecido.
    • pause: no hacer nada durante el tiempo determinado.
    • name: es opcional, pero si recomendable para identificar las distintas «phases» en los informes generados.
  • environments: es la propiedad que permite definir las particularidades de los distintos entornos de ejecución.
  • payload: es la propiedad que permite definir un fichero de CSV donde leer distintos casos de prueba, por ejemplo, usuarios y passwords atacando a un mismo endpoint.
  • scenarios: es la propiedad que permite definir un flujo de peticiones a distintos endpoints.
  • defaults: es la propiedad que permite establecer las cabeceras HTTP que van a afectar a todas las peticiones definidas.
  • tls: es la propiedad que configura cómo se debe manejar los certificados auto-firmados.

Un ejemplo completo de fichero de configuración podría ser:

config:
  target: "http://wontresolve.local:3003"
  payload:
      # path relativo a la localización del script de test
      path: "users.csv" 
      fields:
        - "username"
        - "password"
  phases:
    - duration: 10
      arrivalRate: 1
  environments:
    production:
      target: "http://wontresolve.prod:44321"
      phases:
        - duration: 120
          arrivalRate: 10
    staging:
      target: "http://127.0.0.1:3003"
      phases:
        - duration: 1200
          arrivalRate: 20
          rampTo: 50
  scenarios:
    - flow:
        - log: "Realizamos el login"
        - post:
            url: "/auth"
            json:
              username: "{{ username }}"
              password: "{{ password }}"
        - post:
            url: "/search"
            body: "kw={{ keywords }}"
            capture:
              json: "$.results[0].id"
              as: "id"
        - get:
            url: "/details/{{ id }}"
            headers:
              X-My-Header: "123"
        - post:
            url: "/cart"
            json:
              productId: "{{ id }}"

Nota: Como ves existen numerosas propiedades por lo que aconsejo ver la documentación oficial para ir conociéndolas, aquí solo se han descrito las más básicas.


4. Caso práctico e integración con StatsD y Graphite

Para hacer el caso práctico puedes utilizar cualquier endpoint que tengas, pero si no tienes ninguno a mano, puedes descargar el siguiente proyecto de GitHub: https://github.com/raguilera82/api-back-nodejs.git

Se trata de un API escrito con NodeJS haciendo uso del framework NestJS que tiene publicados varios endpoint entre ellos /api/public/users que devuelve un listado de usuarios.

Para utilizarlo simplemente hacemos «clone» del proyecto, nos situamos dentro del directorio raíz y ejecutamos:

$> npm install
$> npm run start:prod

Para verificar que el arranque se ha producido correctamente nos conectamos con el navegador a http://localhost:3001/api/public/users

Ahora vamos a instalar la dependencia necesaria para integrar StatsD con nuestros tests. Ejecutamos:

 
$> npm install -g artillery-plugin-statsd

También necesitamos un servidor con StatsD y Graphite, la forma más rápida, cómoda y elegante es con el siguiente contenedor Docker:

$> docker run -d --name graphite --restart=always -p 80:80 -p 2003-2004:2003-2004 -p 2023-2024:2023-2024 -p 8125:8125/udp -p 8126:8126 hopsoft/graphite-statsd 

Ahora preparamos el script para el test teniendo en cuenta incluir la sección de plugins con la información de conexión al servidor de StatsD que se encuentra escuchando en el puerto 8125 de nuestra máquina y le damos un prefijo para identificar estar métricas dentro de Graphite.

config:
  target: 'http://localhost:3001'
  phases:
    - duration: 30
      arrivalRate: 20
  plugins:
    statsd:
      host: "localhost"
      port: 8125
      prefix: "artillery"
scenarios:
  - flow:
    - get:
        url: "/api/public/users" 

En este caso configuramos que durante 30 segundos queremos llegar a 20 peticiones por segundo.

Guardamos el fichero con el nombre que queramos con extensión .yml, por ejemplo test.yml, y ejecutamos:

$> artillery run test.yml

Ahora si abrimos la URL http://localhost, tenemos que ver la página de administración de Graphite, con todas las métricas a la izquierda en forma de árbol.

Y como ves aquí se encuentran las métricas que acabamos de generar con lo que podemos utilizarlas para crear los «dashboards» que necesitemos.


5. Conclusiones

Como has visto esta herramienta puede ser muy útil para hacer pruebas rápidas en un entorno NodeJS y la facilidad de integración con otras herramientas de su ámbito la hace especialmente útil y sencilla. Ahora para entornos Java, JMeter es el líder indiscutible aunque Gatling le venga pisando los talones,
pero esto ya será otro tutorial 😉

Cualquier duda o sugerencia en la zona de comentarios.

Saludos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad