Gatling: ametrallando APIS





¿Cómo determinar la estabilidad, medir el rendimiento, establecer o reconocer los posibles cuellos de botella de un servicio?
La respuesta parece obvia, mediante pruebas de carga, estabilidad y estrés.
Existen diversas herramientas y frameworks para diseñar y ejecutar este tipo de pruebas, sin entrar en si uno es mejor que otro, hoy voy a dedicar unas líneas a Gatling.

Gatling es una potente solución, de código abierto, para realizar pruebas de carga, sobre sitios web pero también sobre servicios. En este post voy  a presentar algunos ejemplos, con los que he puesto a  prueba geowe-geometry-service, un servicio Rest que permite realizar operaciones geométricas.

Preparando la prueba

La manera mas rápida de empezar es descargando la versión standalone de Gatling, y por supuesto leer un poquito la documentación (la guía rápida está bien para empezar).
Una vez lo tenemos, podemos empezar a implementar las pruebas. Para ello crearemos nuestras simulaciones en el directorio gatling-charts-highcharts-bundle-3.1.1/user-files/simulations. Yo he creado la clase CentroidBufferSimulation.scala. Sí, Gatling usa Scala como lenguaje base.

Para esta simulación voy a ejecutar pruebas sobre los recursos de Centroide y Bufer (se puede consultar la documentación de la api en el repositorio de GitHub).

Dado un polígono, solicitamos al servicio (GGS) su centroide y un buffer de 5


Voy  a definir por tanto dos escenarios, uno para usuarios que solicitan el centroide del polígono y otro para usuarios que solicita el bufer (área de influencia de 5)

package org.geowe.ggs.gatling

import io.gatling.core.scenario.Simulation
import io.gatling.core.Predef._
import io.gatling.core.structure.ScenarioBuilder
import io.gatling.http.Predef._
import scala.concurrent.duration._

class CentroidBufferSimulation extends Simulation {
private val httpConf = http
.baseUrl("http://127.0.0.1:8080/ggs/operations/jts")
.acceptHeader("application/json")

private val polygon = """{"crs":"EPSG:3857","id":"polygon-1","wkt":
"POLYGON((-530855.1614405491 4527777.944817195,-532460.3390345377 4523191.723120084,
-523822.9548383128 4520898.612271529,-524587.3251211646 4528389.441043475,
-530855.1614405491 4527777.944817195))"}"""
private val centroidScn: ScenarioBuilder = scenario("Centroid Scenario")
.exec(http("Get Centroid").post("/centroid/").body(StringBody(polygon)).asJson
.check(status.is(201)))

private val bufferScn: ScenarioBuilder = scenario("Buffer Scenario")
.exec(http("Get Buffer").post("/buffer?distance=5").body(StringBody(polygon)).asJson
.check(status.is(201)))
  
setUp(
centroidScn.inject(rampUsers(1000) during (10 minutes)),
bufferScn.inject(rampUsers(1000) during (10 minutes))
).protocols(httpConf)
}

Como se ve en el código voy a  inyectar 1000 usuarios para cada escenario con una rampa lineal durante diez minutos. Podemos ver las diversas posibilidades en la documentación de Gatling: simulation setup.


Ejecutanto la prueba


Para lanzar la prueba basta con ejecutar en un terminal:
>bin\gatling.bat -s org.geowe.ggs.gatling.CentroidBufferSimulation

Transcurrido el tiempo especificado en la simulación podemos ver en consola el resultado:



Revisando el resultado


Gatling genera un reporte en html, que me parece genial con las opciones por defecto. Este reporte se puede visualizar en el directorio results, y muestra gráficas con bastante detalle de la simulación y los escenarios ejecutados.






Simulando autenticación JWT

Me ha resultado interesante la facilidad con la que se pueden generar escenarios usando autenticación. Para mostrarlo no he usado el servicio de las pruebas anterirores (ya que no usa autenticación).
La siguiente simulación  presenta un escenario con tres pasos, en los que la autenticaión es por usuario-contraseña y usa JWT para el proceso de securización.

import io.gatling.core.scenario.Simulation
import io.gatling.core.Predef._
import io.gatling.core.structure.ScenarioBuilder
import io.gatling.http.Predef._
import scala.concurrent.duration._

class ScdSimulation extends Simulation {

private val httpConf = http
.baseUrl("https://service-url/api")
.acceptHeader("application/json")

private val auth = """{"login":"userName", "password": "passwd"}"""
val expedientesFeeder = csv("expedientes.csv").batch.random
private val scn: ScenarioBuilder = scenario("load expediente Scenario")
.exec(http("login").post("/signin").body(StringBody(auth)).asJson
.check(status.is(200)))
.pause(3)
.exec(http("load expedientes").get("/expedientes")
.check(status.is(200)))
.pause(5)
.feed(expedientesFeeder)
.exec(http("load expediente").get("/expedientes/${id}")
.check(status.is(200)))
  
setUp(
scn.inject(atOnceUsers(4),
rampUsers(10) during (60 seconds),
rampUsersPerSec(5) to 20 during (10 minutes) randomized)
).protocols(httpConf)
}


Este servicio devuelve el token JWT en una cookie (secured-httpOnly) en la petición de login. Gatling automáticamente se encarga de enviar la cookie en las otras peticiones (igual que el navegador), para cargar listado de expedientes y para cargar un expediente según su identificador (que se recoge del fichero gatling-charts-highcharts-bundle-3.1.1/user-files/expedientes.csv)

Notas finales

Hasta la fecha jmeter era mi herramienta de cabecera para realizar este tipo de pruebas. A partir de ahora le ha salido un fuerte competidor. Me ha resultado divertido el uso de Gatling, y me parece una herramienta muy potente para poner a prueba nuestros servicios y sitios web.

Por supuesto, como siempre la potencia sin control no sirve de nada, una planificación y estudio de los escenarios en cada simulación sigue siendo necesaria, para tener un conjunto de pruebas que validen el software.


P.D.: Si quieres ver las peticiones y respuestas en la simulación es tan sencillo como cambiar la configuración del log en  gatling-charts-highcharts-bundle-3.1.1/conf/logback.xml

Comentarios