[Nantes JUG] Stresser vos applications web avec Gatling

Le 17 novembre dernier avait lieu une soiré JUG Nantes sur Gatling, présentée par Rossi Oddet. Vous avez besoin de faire des tests de charge sur votre application web et vous ne savez pas comment faire ? Ou bien vous avez testé JMeter et vous en avez encore des cauchemars ? Gatling est sûrement ce qu’il vous manque… Voici un rapide compte-rendu de la session.

Rossi nous a présenté cinq bonnes raisons d’utiliser Gatling :

  • sa prise en main facile : bien que basé sur scala, il n’est pas nécessaire de connaître ce langage ni même la programmation fonctionnelle pour l’utiliser. Il est aisé d’écrire un scénario (c’est-à-dire le comportement d’un utilisateur). On greffe sur ce scénario une politique d’injection (nombre d’utilisateurs, arrivée simultanée ou non), et ça roule.
  • sa performance : avec JMeter, un utilisateur correspond à un thread, ce qui le rend très gourmand en ressources. Gatling utilise l’asynchronicité, ce qui lui permet de simuler le comportement de nombreux utilisateurs sans difficulté. Il est même possible de continuer à utiliser sa machine pendant des tests Gatling !
  • son intégration officielle avec Maven, Jenkins, Graphite. Il est possible également de l’intégrer avec Play et Gradle.
  • sa mailing-list active ;
  • une bonne activité sur Github.

Ces avantages sont également visibles sur le support de la présentation.

Nous avons ensuite suivi une démonstration de l’utilisation de Gatling. L’installation est très simple, puisqu’il s’agit d’un zip à extraire à l’endroit désiré. Deux exécutables sont présents : gatling permet d’exécuter les scénarios, et recorder est un outil graphique pour enregistrer les scénarios. *Recorder *est pratique pour débuter ; cependant, les scénarios générés comportent parfois des erreurs et il est nécessaire de les relire. Ils sont aisés à comprendre et à manipuler, et à la longue, on apprend à les créer soi-même sans passer par le recorder.

Une manière de créer un scénario avec recorder est de lui transmettre un fichier de type har. Il est facile de créer ce fichier en utilisant les outils de développement de Chrome. Aller dans Network, démarrer un enregistrement (en cochant Preserve log pour qu’elle ne disparaisse pas au changement de page) et faire les manipulations que l’on veut reproduire lors de nos tests de charge. Une fois terminé, on peut l’enregistrer sous format har.

creerHar

On lance ensuite le recorder et on lui injecte le fichier* .har précédemment créé.* Selon notre besoin on peut décider de ne pas prendre en compte les ressources statiques (mises alors dans la blacklist).

gatlingrecorder

Le scénario est généré dans gatling/user-files/simulation. Voici à quoi il ressemble :


import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

class RecordedSimulation extends Simulation {

	val httpProtocol = http
		.baseURL("http://computer-database.herokuapp.com")
		.inferHtmlResources(BlackList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.(t|o)tf""", """.*\.png"""), WhiteList())
		.acceptHeader("""text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8""")
		.acceptEncodingHeader("""gzip, deflate, sdch""")
		.acceptLanguageHeader("""fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4""")
		.connection("""keep-alive""")
		.userAgentHeader("""Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36""")

	val headers_0 = Map("""Cache-Control""" -> """max-age=0""")

    val uri1 = """http://computer-database.herokuapp.com/computers"""

	val scn = scenario("RecordedSimulation")
		.exec(http("request_0")
			.get("""/computers""")
			.headers(headers_0))
		.pause(5)
		.exec(http("request_1")
			.get("""/computers?f=test"""))
		.pause(3)
		.exec(http("request_2")
			.get("""/computers/378"""))
		.pause(4)
		.exec(http("request_3")
			.get("""/computers"""))

	setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocol)
}

On remarque que, même sans rien connaître de Scala, ce code est facilement lisible. Rossi recommande l’utilisation de Scala IDE pour le manipuler. La suite de la démonstration s’est faite sur l’amélioration du code généré pour le rendre plus lisible et maintenable. Il est ainsi possible de séparer notre scénario en plusieurs processus. Voici alors à quoi pourrait ressembler le code :

object Recherche {

  val recherche = exec(http("Search")
			.get("""/computers?f=test"""))
		.pause(3)
}

object Selection {

  val selection = exec(http("Browse")
			.get("""/computers/378"""))
		.pause(4)
}

object Browse {

  val browse = exec(http("Home")
		.get("""/computers"""))
		.pause(5)

}

L’intérêt est de créer plus facilement différents enchaînements de scénarios, correspondant à plusieurs types de comportement, et donc des utilisateurs différents pour notre simulation. Imaginons que nous avons un scénario supplémentaire dans lequel l’utilisateur édite l’entrée sélectionnée. Nous pouvons alors écrire :

val users = scenario("Users").exec(Browse.browse, Recherche.recherche, Selection.selection, Browse.browse)
val admins = scenario("Admins").exec(Browse.browse, Recherche.recherche, Selection.selection, Edit.edit)

Et si nous voulons maintenant simuler l’arrivée progressive de 1000 utilisateurs et celle simultanée de 10 administrateurs, il nous reste à réécrire la dernière ligne :

setUp(
  users.inject(rampUsers(1000) over (10 seconds)),
  admins.inject(atOnceUsers(10))
).protocols(httpProtocol)

La suite de la démonstration s’est portée sur l’utilisation d’un feeder pour pouvoir varier les données passées à un formulaire, depuis un fichier de type csv ou une base de données.

Voila comment déclarer un feeder :

val feeder = csv("search.csv").queue

Ce feeder prendra les lignes dans l’ordre et s’arrêtera quand il arrivera à la fin, il faut donc veiller à avoir au moins autant de lignes que d’utilisateurs. Si on a moins de lignes que d’utilisateurs, on utilisera alors circular à la place de queue pour revenir au début du fichier. On peut également prendre les lignes aléatoirement avec random.

Enfin, il est possible d’ajouter des vérifications dans le scénario : statut de la réponse ou recherche d’une expression régulière dans la réponse.

Une fois notre scénario bien écrit, on peut le tester en lançant gatling. L’application nous demande alors de choisir quelle simulation on souhaite jouer, puis nous en voyons le déroulement dans la console. Un rapport très complet et lisible est généré sous format html.

gatlingrapport

Pour aller plus loin, le blog de Rossi Oddet contient plusieurs articles sur Gatling et Scala. Vous pouvez aussi consulter le tutoriel avancé de Gatling que j’ai outrageusement pompé pour compléter mes notes éparses de la session du JUG.

Crédit photo
https://flic.kr/p/72zZMX