Les tests de charge à caractère technique (robustesse) sont ils importants ?

Introduction

Mettons-nous d’abord d’accord sur la définition de « tests de charge à caractère technique (ou test de robustesse) ».
Il s’agit de tester un système en mode dégradé : ralentissement de l'application, un des serveurs est non disponible, réseau saturé, panne mémoire, disque plein, réseau défaillant, etc. sous forte charge.
Maintenant que nous sommes d’accord, commençons.

Votre application a réussi tous les tests, qu’ils soient unitaires, d’intégration, fonctionnels ou de charge et nous voilà enfin prêts à la mettre en production.
Mais vous vous posez toujours des questions sur comment va réagir votre application en cas de fonctionnement dégradé.

Les délais font que l’application est mise en production sans la réalisation de ces tests.
Deux jours plus tard, après une campagne de publicité qui vous a apporté beaucoup de nouveaux utilisateurs, on vous réveille à deux heures du matin pour que vous veniez d’urgence au bureau, car l’application est dans un état instable.
Dommage, car des tests de robustesse auraient sûrement pu vous éviter ce désagrément.

Vous ne me croyez pas, vous avez raison.

Et si je vous dit que lors de mes missions j'ai rencontré :

  • des crashs de l'application à cause d'un consommateur JMS non démarré ;
  • des crashs de l'application à cause d'un load balancer mal configuré ;
  • des problèmes de répartition de charge dans un cluster d'Apache ActiveMQ après l'arrêt/relance d'un noeud.

Toujours pas. Et si je vous dit que ces problèmes sont arrivés dans des grosses structures sur des projets plus ou moins gros et avec des gens compétents ?

Bon vous ne me laisser plus le choix, nous allons voir un exemple qui vous prouvera (enfin je l'espère) l'importance de ces types de tests.

Mais avant cela comment allez vous reproduire ce bug qui est arrivé en environnement de production sur votre environnement de test ?

Avec un test de robustesse bien sûr 😉

Une preuve

Notre application est la fameuse Spring PetClinic.

Pour simuler la charge nous allons utiliser Apache JMeter.

Notre script réalisera les actions suivantes :

  • Aller sur la page d’accueil.

JMeter_HTTP_101_ex7_tdc1

  • Aller sur la page de recherche

JMeter_HTTP_102_ex7_tdc2

  • Exécuter une recherche.

JMeter_HTTP_103_ex7_tdc3

Notre script aura la forme suivante :

JMeter_script_vide

 

Maintenant nous voulons savoir « Que se passe-t-il si votre fonctionnalité de recherche (module critique de votre applicatif) met plus de huit secondes à répondre ? ».

Pour simuler ce ralentissement nous allons utiliser JBoss Byteman qui se présente sous la forme d’un agent Java capable de modifier le comportement de notre application en instrumentant son bytecode.

Les avantages de JBoss Byteman sont nombreux :

  • on peut déclencher ce que l’on veut (ralentissement de l’application, perte de connexion à la base de données, disque plein, etc.) lorsqu’on veut (il suffit d’uploader les règles Byteman sur l’application cible) ;
  • on peut simuler des choses difficilement testables avec un test de charge (ralentissement d’une partie de l’application, disque dur plein, avoir un problème de connexion à la base une fois sur cinq, etc.) ;
  • le tout sans intervention extérieur (pas besoin de l’équipe d’exploitation pour arrêter la base de données (il suffit d’avoir le même compte pour le lancement de Byteman et de l’application).

Ajoutons Byteman à notre script (connexion de Byteman à la JVM, chargement des règles de modification du comportement de l’application dix minutes après le début du test, suppression de ces mêmes règles vingt minutes après le début du test).

JMeter_HTTP_111_ex7_delay8

 

Avec ce script, Apache JMeter s’occupera de tout (simulation des utilisateurs, de la charge et du lancement de JBoss Byteman).

Lançons notre test avec une charge faible.

PetClinicWait_Low

On voit bien l’impact sur les temps de réponse.

À ce moment-là on peut se dire « c’est dommage pour les utilisateurs mais ça pourrait être pire ».

Exécutons le test à nouveau mais avec une charge plus élevée et regardons plus en détails cette fois ci.

Changement de comportement, les temps de réponse ne reviennent pas à la normale après la suppression des règles de modification du comportement de l’application.
PetClinicWait_01_tdr

Si on regarde le nombre de requêtes traitées par notre application, on remarque une baisse importante de celui-ci (et adieu à notre prime indexée sur les ventes réalisées dans le cas d’un site de e-commerce).

PetClinicWait_02_nbreq

Et comme pour les temps de réponse, elles ne reviennent pas à la normale.

Afin de comprendre ce comportement nous allons utiliser JProfiler qui va nous faciliter l’analyse de notre application.

On remarque que la mémoire de notre application est moins stressée (moins de passage du GarbageCollector).

PetClinicWait_04_tomcat_gc

PetClinicWait_04_tomcat_gc2

Ce qui est normal, car notre application traite moins de requêtes.

La contention ne venant pas de la gestion de la mémoire, on regarde du côté des threads.

Bingo, on remarque :

  • qu’un ou plusieurs threads sont bloqués à partir du chargement des règles Byteman ;
  • que les threads répondant aux requêtes HTTP (en bleu) sont utilisés de manière « chaotique » lorsque les règles Byteman sont actives (encadré en rouge) ;
  • que l'utilisation des threads répondant aux requêtes HTTP (en bleu) atteint un plafond après la suppression des règles Byteman.

PetClinicWait_05_tomcat_thread_global

Le « Thread Views » de JProfiler nous confirme bien nos remarques.

Ici l’utilisation « chaotique » (beaucoup plus de threads en pause sur la partie encadrée en rouge) puis l’atteinte du plafond (plus aucune thread en pause).
PetClinicWait_06_tomcat_catalina

Et ici la saturation du thread qui accepte les connexions HTTP.
PetClinicWait_07_tomcat_catalina2

On en déduit que l’on a saturé notre pool de threads (paramétré à dix afin de faciliter la lecture des captures d’écran et notre analyse) et que l'application n'arrive plus à « sortir la tête de l'eau ».

Et en voilà la preuve.
PetClinicWait_03_tomcat_qv

On vient de voir l’effet boule de neige (blocage de notre application) provoqué par le ralentissement d’une partie de cette même application.

Plusieurs solutions existent pour corriger ce problème :

  • optimisation du code (solution à court terme car la probabilité que le problème arrive en production ne sera jamais nul) ;
  • tuning d'Apache Tomcat ;
  • duplication de votre module de recherche sur le même serveur (Vertical Scaling) ;
  • duplication de votre module de recherche sur d'autre serveur (Horizontal Scaling) ;
  • changement de technologie pour votre module de recherche (par exemple ElasticSearch).

Conclusion

Ma réponse à la question « Les tests de charge à caractère technique (robustesse) sont ils importants ? » est oui.

Mes conseils sont :

  • de faire des tests de charge à caractère technique en plus des tests de charge ;
  • si possible les automatiser (dans cet exemple avec Apache JMeter et JBoss Byteman) ;
  • de bien vous outiller (ici JProfiler) ;
  • ces tests ne sont qu’une simulation et donc de bien superviser l’environnement de production (par exemple avec AppDynamics, Nagios).

Si vous avez déjà rencontré ce type de problème, n’hésitez pas à rédiger un commentaire.

Laisser un commentaire

Merci d'effectuer cette opération simple pour valider le commentaire *

Mots-clés
RSS Feed