"Stress test" pour une application Web - cas pratique sur Raspberry

Ceux qui auront lu mon précédent article ne seront pas étonnés si j'annonce que j'ai tout récemment déployé une application web (Zend Framework 1 + Doctrine 2 + PHP5 + MySQL) sur un (petit - euh... enfin normalement petit) Raspberry Pi (modèle B). Toutefois, je décidai d'étudier plus avant le système mis en place en le soumettant à un 'stress test' simulant un fort afflux d'utilisateurs effectuant diverses requêtes au sein de l'application.

Les applications de 'stress test' ne manquent pas et j'avais déjà entendu parler de JMeter et Tsung. Mais pour ce test, je décidai d'utiliser Gatling : logo-Gatling-StressTool.png

Gatling (open source, disponible sur http://gatling-tool.org/) est codé en Scala et s'exécute sans difficulté dans un environnement disposant d'une machine virtuelle Java. Pas d'installation nécessaire : on décompresse l'archive et les binaires de l'application sont disponibles dans /bin/.

Mise en place d'un scénario de stress : à la main...

Les scénarios de test de Scala sont à créer et placer dans /user-files/simulations dans des fichiers scala. La structure de base d'un fichier est la suivante :

import com.excilys.ebi.gatling.core.Predef._
import com.excilys.ebi.gatling.http.Predef._
import com.excilys.ebi.gatling.jdbc.Predef._
import Headers._
import akka.util.duration._
import bootstrap._
import assertions._

class SimulationWithFollowRedirect extends Simulation {
  val scn = scenario("My scenario")
            .exec(http("My Page")
              .get("http://mywebsite.com/page.html"))
  
  setUp(scn.users(1))
}

Il est donc possible en Scala de coder la liste des actions qu'effectueront les utilisateurs virtuels (des requêtes GET, des requêtes POST, le lancement de certaines routines PHP...). A la fin du fichier, la simulation est lancée par

  setUp(scn.users(x))

où x (entier naturel strictement positif) représentera le nombre d'utilisateurs qui seront simulés concurremment sur l'application.

Mise en place d'un scénario de stress : en automatique pour aller plus vite !

L'écriture du scénario "à la main" est très souple mais un petit peu complexe. Il existe donc un petit utilitaire (recorder) particulièrement pratique qui peut venir à notre rescousse. Il s'agit d'une application qui vient se positionner comme un proxy sur le navigateur web et qui enregistre toutes les opérations effectuées par le navigateur directement sous la forme d'un fichier Simulation.scala utilisable par Gatling.

Le 'recorder' se lance par :

sh bin/recorder.sh

Si les ports du proxy (HTTP/HTTPS, spécifiés en haut à gauche) conviennent, on clique sur 'Start' et désormais l'application enregistrera tout mouvement réalisé au travers du proxy.

Gatling-recorder.png

Une fois l'enregistrement terminé, on peut bien sûr modifier le scénario de simulation (suppression des pauses non nécessaires, suppression de certaines étapes...) en éditant le fichier MaSimulationDuJour.scala qui aura été créé dans /user-files/simulations. On peut notamment augmenter le nombre d'utilisateurs qui seront simulés :

  setUp(scn.users(100))

et on peut simuler une montée en charge progressive par la commande finale :

  setUp(scn.users(100).ramp(200)

qui signifie que 100 utilisateurs se connecteront progressivement pendant 200 secondes (soit 1 nouvel utilisateur toutes les 2 secondes). Bien sûr, si votre serveur répond bien et que la durée de simulation est courte alors il est possible que vous n'ayez jamais 100 utilisateurs connectés en même temps (car une fois que l'utilisateur simulé a terminé toutes les étapes alors il se déconnecte à moins que vous ne paramétriez des boucles). Le rapport d'analyse (cf. infra) vous permettra de bien visualiser ce phénomène.

Lancement du stress test

On lance donc gatling

sh bin/gatling.sh

qui propose de choisir la simulation à lancer. Et c'est parti !

L'état d'avancement du 'stress test' s'affiche dans la console. Une fois celui-ci terminé, un rapport est généré et est accessible dans le dossier /results/.

Voici un petit aperçu d'un rapport obtenu (sur un PC de bureau 4 coeurs +4 Go de RAM) : Gatling_-_stresstest1.png Gatling_-_stresstest2.png

Conclusion du stress test

Sur mon Raspberry Pi, je suis un peu déçu car dès 10 utilisateurs en concurrence les accès à la base de données et les requêtes pour les contenus non statiques mettent un temps long (les moyennes vont de 20 à 40 secondes selon les requêtes) à s'exécuter... Je m'attendais à ce que la Raspberry Pi ne tienne pas bien la charge mais je pensais la limite atteinte moins vite. C'est également le signe que le code de l'application n'est pas optimisé pour une exécution très légère et très économe en ressources ! Il va me falloir plonger dans le code pour optimer tout cela !

Très bonne journée à tous et bons 'stress tests' !