Qu'y a-t-il dans ma mémoire JVM | Siemens | Mendix

Passer au contenu principal

Qu'y a-t-il dans ma mémoire JVM

« Le Mendix Le runtime exécute le modèle créé dans le modeleur. Il fournit des pages au client et exécute des microflux, appelle des services Web, génère des documents, communique avec la base de données et bien plus encore.

Le Mendix Runtime est un programme écrit en Java et Scala, qui utilise une machine virtuelle Java, ou JVM. Lors de son exécution, il utilise une certaine quantité de mémoire système dans votre système d'exploitation.

Qu'y a-t-il dans ma mémoire JVM ?

Jetons un œil à un graphique possible qui montre l’utilisation de la mémoire de la JVM :

seemsright_mxruntime_jvmheap-jour

Dans ce graphique, nous voyons une application qui dispose de 512 Mo d'espace de tas Java. Il s'agit de l'espace mémoire principalement utilisé par l'application. Mendix Application elle-même. Si vous récupérez un objet dans un microflow, c'est ici que les objets lus dans la base de données sont conservés en mémoire.

Le Mendix Runtime utilise également cet espace pour stocker des objets Java pour les sessions connectées, des objets intermédiaires qui convertissent les données brutes de la base de données en objets pouvant être utilisés dans un microflow, ou en objets pouvant être directement transmis sur le réseau s'il s'agit de données devant être affichées dans une grille de données dans votre navigateur Web. Saviez-vous même que même vos microflows eux-mêmes sont des objets ici ? Mendix Runtime est un interpréteur, il stocke également une copie de votre application modélisée dans sa mémoire.

Différentes parties de cet espace mémoire sont gérées par le garbage collector de la JVM. (voir aussi le Documentation de JVM Heap)

L'exemple précédent est en fait tiré d'une application qui n'est pas réellement utilisée, mais qui a probablement un événement planifié, ce qui entraîne la création d'un tas d'objets qui peuvent être récupérés peu de temps après.


La JVM n’est pas seule…

Maintenant, cette mémoire Java doit également tenir dans la mémoire système du système d'exploitation lui-même. Si vous utilisez le Mendix Cloud, vous pouvez visualiser ces graphiques dans la partie surveillance de notre portail de déploiement.

Voici le graphique qui affiche l'utilisation réelle de la mémoire du système d'exploitation. Il s'agit d'un soi-disant appnode, qui est dédié à l'exécution du processus d'application d'un environnement unique d'un Mendix application (donc, soit un environnement de test, d'acceptation ou de production).

jour-mémoire-semble-juste

Cela semble tout à fait correct, n'est-ce pas ? Environ 500 Mo sont utilisés, ce doit donc être le tas Java que nous avons vu ci-dessus. La base de données s'exécute sur une autre machine virtuelle, donc l'utilisation de la base de données n'est pas visible ici. Apparemment Mendix provisionné une machine virtuelle Linux avec 1024 Mo de mémoire pour adapter votre processus Java.


Attends quoi?

Maintenant, regardons un autre exemple :

wait_what_mxruntime_jvmheap-jour

attendez_quel_jour_mémoire

Attendez une minute… Pourquoi y a-t-il plus de 900 Mo de mémoire utilisée dans le système d’exploitation au lieu des 512 Mo qu’il était censé utiliser ? Mendix exécuter secrètement d’autres processus parallèlement à notre application pour utiliser la mémoire autrement inutilisée ?

Non, ce n'est pas le cas. Vraiment. 🙂 Bon, ok… il y a des processus supplémentaires qui sont toujours en cours d'exécution en plus de l'application elle-même, qui sont par exemple deux agents de surveillance, l'un pour fournir des données au système de tendances (pour produire ces graphiques) et l'autre qui fournit des données au système d'alerte. Et il y a un processus qui peut arrêter et démarrer votre application lorsqu'elle reçoit un signal du portail de déploiement lorsque vous appuyez sur les boutons d'arrêt ou de démarrage.

Mais tous ces éléments étaient également présents dans le premier exemple présenté. Alors, que se passe-t-il ici… ?

Jetons un œil à la sortie de la commande ps, qui peut afficher la quantité de mémoire occupée par chaque processus sur un serveur :

 

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
xxxxx    19137  1.8 84.7 1248796 864696 ?      Sl    2014 1177:33 java -Dfile.encoding=UTF-8 -XX:MaxPermSize=128M -Xmx512M -Xms512M -Djava.io.tmp...

 

Oui, c'est le processus Java qui utilise réellement 864696 XNUMX Ko de mémoire.


Pourquoi s'embêter?

Pourquoi devrions-nous nous en préoccuper ? Après tout, le processus tient toujours dans les 1024 Mo de mémoire disponibles, même si ce processus Java de 512 Mo passe comme par magie à 844 Mo.

En fait, ce type de comportement pose quelques problèmes, car il empêche l'exécution d'autres programmes sur le serveur, qui sont démarrés de temps en temps.

Nous effectuons des mises à jour de versions et de sécurité…

At Mendix, nous apportons régulièrement, et peut-être bien plus souvent que vous ne le pensez, des modifications à notre plateforme d'hébergement. Chaque semaine, ou plus souvent, même plusieurs fois par semaine, de petites modifications sont apportées à l'ensemble de notre plateforme d'hébergement. Au lieu d'accumuler de nouvelles fonctionnalités et des correctifs de bugs dans une énorme version mensuelle, nous les déployons dès qu'elles sont prêtes à être mises en production.

Et ils doivent courir !

Pour déployer les modifications en production, nous utilisons principalement des packages Puppet et Debian pour mettre à jour nos logiciels sur les serveurs d'applications et de bases de données exécutant les projets des clients. En outre, il existe un programme appelé Unattended Upgrades qui installe les mises à jour de sécurité sur tous les serveurs dès qu'elles sont disponibles.

Ainsi, ce processus Java qui prend des proportions démesurées peut empêcher que ces problèmes ne se produisent. Ne pas installer les versions peut signifier que votre application peut rencontrer des problèmes de compatibilité avec le reste du système de déploiement. Ne pas bénéficier des mises à jour de sécurité est quelque chose que personne ne devrait vouloir.

Heureusement, ce problème n’apparaît que dans un nombre très limité d’environnements (0.53 % de tous les environnements d’application, à l’heure actuelle).


Le noyau Linux à la rescousse !

La première étape du processus visant à découvrir ce qui se passe ici, conduisant à une solution à ce comportement, consiste à fournir plus d'informations sur la situation.

Si un processus Java est configuré pour utiliser 512 Mo d'espace de tas… Qu'est-ce que cela signifie ? Le graphique du tas Java tel que présenté ci-dessus montre une partie de la mémoire utilisée pour stocker les objets réels utilisés dans le code Java. Mais, pour exécuter un processus Java… nous devons démarrer le programme Java lui-même. Ce programme doit-il également être présent en mémoire ? Est-il situé dans cette mémoire du tas JVM ? Et qu'en est-il des milliards de fichiers jar que nous venons de placer dans notre emplacement userlib du projet ? Que va-t-il leur arriver ?

Pour avoir une meilleure compréhension de cela, il serait bien d'avoir un graphique qui montre non seulement l'espace du tas Java, mais également l'espace mémoire occupé par l'ensemble du processus Java dans le système d'exploitation.

…en fournissant des informations détaillées sur l’utilisation de la mémoire

Heureusement, le noyau Linux nous permet d'obtenir un aperçu complet de l'espace d'adressage mémoire occupé par un seul processus, en utilisant le système de fichiers proc. Le PID (identifiant de programme) de l'exemple de processus Java que j'ai montré précédemment est 19137. Cela signifie que je peux exécuter la commande suivante sur une invite de commande Linux pour permettre au noyau Linux d'afficher tout ce qui concerne l'allocation de mémoire de ce processus : cat /proc/19137/smaps

En utilisant les informations smaps disponibles, il est possible de faire une estimation assez précise de ce qui se passe à l'intérieur du processus JVM.

Permettez-moi de vous présenter le nouveau graphique d'utilisation de la mémoire du processus JVM qui appartient au tout premier graphique d'application présenté sur cette page :

seemsright_mxruntime_jvm_process_memory-day

Ah ! Ce n'était pas un tas Java de 512 Mo après tout qui occupait la mémoire ! Il s'agissait simplement d'environ 230 Mo, et l'autre partie semble être occupée par de la mémoire allouée en dehors du tas d'objets Java. Une partie de celle-ci est la génération permanente et le cache de code, qui stocke les objets que la JVM considère comme n'étant pas assez intéressants pour le garbage collector, car ils ne disparaîtront jamais tant que l'application est en cours d'exécution. Une autre partie est la partie mémoire native.

Regardons maintenant le graphique appartenant à l’application problématique :

wait_what_mxruntime_jvm_process_memory-day

Dans ce scénario, le tas Java est activement utilisé, il a donc été réellement alloué par le système d'exploitation, au lieu de se voir simplement promettre qu'il pourrait être disponible pour être utilisé lorsque cela est réellement nécessaire.

Le principal point à retenir ici est que nous avons été trompés en pensant que la mémoire réelle du système d’exploitation était entièrement occupée par le tas d’objets JVM alors que ce n’était pas le cas.


Quand ça devient vraiment incontrôlable…

Pour conclure cet article de blog, voici un exemple d’une situation qui dépasse réellement toutes les limites d’un comportement sain.

Nous avons ici une configuration de tas Java de 1024 512 Mo, qui a été mise à niveau d'un tas d'objets Java de 1 Mo vers un tas d'objets de XNUMX Go :

whoah_mxruntime_jvmheap_tr10000-semaine

Malheureusement, l'utilisation de la mémoire du processus JVM a explosé et nous avons dû redimensionner le système d'exploitation pour y faire face :

whoah_semaine-mémoire

Le nouveau graphique de mémoire de processus JVM montre ce qui se passe ici :

whoah_mxruntime_jvm_process_memory_tr10000-week


À suivre ...

Les recherches qui ont été menées sur ce sujet au cours des semaines précédentes montrent déjà un certain nombre de solutions possibles aux problèmes croissants de mémoire hors tas. Dans un prochain article de blog, je les développerai. Les applications clientes qui rencontrent les problèmes de mise à jour de version et de sécurité mentionnés ci-dessus peuvent s'attendre à un appel de Mendix sur la manière dont nous allons gérer ces problèmes à court terme.


fonctionnement

Pour tracer ces graphiques, j'ai examiné toutes les informations disponibles dans le fichier smaps du système de fichiers proc Linux. En rétro-concevant certains éléments et en faisant quelques suppositions éclairées, j'ai créé une extension à la configuration du graphique de surveillance m2ee que nous utilisons pour créer des tendances. Le code du plug-in de surveillance qui examine les informations smaps du noyau Linux se trouve à l'intérieur du fichier Code source des outils m2eeL’ documentation du plugin munin contient quelques conseils sur la façon dont vous pouvez activer ce plugin vous-même si vous le souhaitez.

Choisissez votre langue