Optimiser une application JEE : mesurer l’impact sur un cas pratique (2ème partie)

2ème volet de notre analyse de performance :

Après avoir revu les niveaux de logs de notre serveur d'application en 1ère partie d'analyse et en avoir mesuré l'impact du correctif sur le temps de réponse, il est maintenant temps de s'approcher de notre objectif initial : rendre stable l'application avec une moyenne de 1000 utilisateurs actifs simultanés.

On va donc augmenter notre charge et passer de 40vu à 300vu :

Reprenons notre scénario JMeter, augmentons le nombre de threads de 40 à 300 avec un ramp-up de 1 utilisateur supplémentaire toutes les 2 secondes (ce qui laisse suffisamment de temps au serveur pour gérer ses nouvelles allocations de Context Http) :

Les 1er symptômes ne mettent pas longtemps à apparaître : des erreurs apparaissent lors de la montée en charge, autour de 100 users simultanés

Sur l'arbre d'erreurs JMeter, on voit apparaitre plusieurs Java.net.SocketException, dont le HTTP result code est Null sur un nombre important d'itérations. Impossible d'isoler une étape en particulier, l'erreur se produit aléatoirement sur chaque étape .... ça sent les problèmes de connexions TCP ... ou peut être bien un rejet des threads worker Glassfish à traiter des sockets entrantes !

Allons faire un tour côté logs Glassfish

" java.util.concurrent.RejectedExecutionException: The thread pool's task queue is full, limit: 10 "

Intuition confirmée ! le pool de threads est saturé , et la file d'attente qui stack les threads supplémentaires (acceptCount) a également atteint sa limite.

Vous pourrez vous attarder sur une explication détaillée du paramétrage du pool de threads dans l'article http://blog.aliecom.com/optimisation-tomcat-serveur/, Tomcat et Glassfish restant dans le même principe de gestion des threads.

Voyons de que nous dévoile la console Glassfish :

Beaucoup trop léger pour faire face à une volumétrie de plusieurs centaines d'utilisateurs simultanés. D'autant plus que nous avons encore beaucoup de marge en termes de ressources machines.

Outre les ressources machines, la taille du pool va également dépendre des temps d’exécution des transactions Java les plus coûteuse (contexte transactionnel JTA ou autre ...) qui mobiliseront les threads autant de temps qu'il faudra avant de s'acquitter (et donc de les libérer).

De part les temps de réponse collectés dans JMeter, nous avons déjà une petite idée des transactions qui pourraient être optimisées. Pour affiner voire isoler techniquement les transactions java les plus lentes, nous serons obligés de passer par du profiling Java (prochain article).

Revenons à nos moutons : passons nos threads à Min=200, Max=400, et une file d'attente à 500.

Profitons-en pour faire un tour côté Pool JDBC et passons le min à 8, max à 32. Nous aurons l'occasion d'analyser les temps d’exécution des requêtes Sql pour ajuster ces paramètres si besoin.


Relançons à nouveau notre tir à 300vu :

Côté Glassfish : plus d'erreur de limite de Threads.

Côté Arbre d'erreurs JMeter : plus de SocketException.

Côté ressource systèmes : une légère augmentation de la CPU dû à l'augmentation du nombre de threads et donc de l'activité du serveur. Cela dit, on oscille seulement autour de 15%.

Allons voir nos temps de réponse :

Ok la charge tient à 300 utilisateurs  ... mais à quel prix : clairement au détriment des temps de réponse sur les étapes de recherche (31sec de moyenne) et d'affichage du détail de la fiche client (27 secondes de moyenne).

 

Conclusion de la 2ème partie

Passage important de 40 utilisateurs simultanés à 300 grâce à l'augmentation du pool de threads qui par défaut sous Glassfish reste complètement sous-dimentionné. On a donc fait sauter les verrous de l'acceptation de charge supplémentaire, mais qui comme on le voit dans le dernier graphe des temps de réponse, se fait au détriment d'un comportement dégradé du serveur. Affaire à suivre ...

 

Avant goût de ce qui nous attend au prochain post

On se focalisera entièrement sur la gestion de la Heap. (Old/Eden/GC policy ...)
Pour cela, on activera le port JMX pour aller analyser le comportement de la mémoire Java de Glassfish.
Nous  serons également amené à faire du profiling Java sur Petclinic pour mettre le doigt sur certains ralentissements.

 <<  Optimiser une application JEE : mesurer l'impact sur un cas pratique (1ère Partie)

 

Laisser un commentaire

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

Mots-clés
RSS Feed