[JAVA] Réglage des performances JVM: qu'est-ce que le réglage et comment élaborer un bon plan

Something went wrong Le réglage des performances pour ** JVM ** est une tâche systématique et complexe. Cet article explique le concept et montre comment utiliser les paramètres ** JVM ** pour régler votre application.

** Ce blog est une traduction de la version anglaise. Vous pouvez vérifier l'original sur ici. Certaines traductions automatiques sont utilisées. Nous vous serions reconnaissants de bien vouloir signaler toute erreur de traduction. ** **

Couche de réglage des performances

Afin d'améliorer les performances du système, il est nécessaire d'optimiser à partir de différents points de vue et couches. Les couches à optimiser sont les suivantes.

image.png

Comme le montre la figure, l'optimisation est nécessaire dans de nombreuses couches autres que le réglage de la JVM. Le réglage du système ne consiste pas seulement à régler la JVM. Au contraire, il est nécessaire de régler l'ensemble du système afin d'améliorer les performances du système. Cet article traite uniquement du réglage JVM. D'autres aspects de réglage seront discutés plus tard.

Avant le réglage JVM, supposez que l'architecture et le code de votre projet sont réglés ou qu'il s'agit de la meilleure architecture et du meilleur code pour votre projet actuel. Ces deux hypothèses sont à la base du réglage JVM, et le réglage de l'architecture a le plus grand impact sur les performances du système. Vous ne pouvez pas vous attendre à un saut qualitatif d'une application qui présente des défauts architecturaux ou qui nécessite une optimisation du code en effectuant uniquement le réglage JVM.

En outre, vous devez avoir des objectifs d'optimisation des performances clairs et comprendre les goulots d'étranglement des performances actuels avant de commencer le réglage. Pour optimiser les goulots d'étranglement, effectuez des tests de stress et de référence sur votre application et utilisez une variété d'outils de surveillance et de statistiques pour voir si votre application optimisée répond à vos objectifs. besoin de le faire.

Étapes de réglage JVM

L'objectif ultime du réglage est de garantir que votre application dispose d'un débit plus élevé au moindre coût de consommation de matériel. Le réglage JVM ne fait pas exception. Le réglage JVM optimise principalement le ramasse-miettes pour améliorer les performances de collecte, permettant aux applications exécutées sur une machine virtuelle d'atteindre un débit plus élevé tout en connaissant une latence plus faible avec moins d'utilisation de la mémoire. va le faire. Gardez à l'esprit qu'une faible utilisation de la mémoire / une faible latence ne signifie pas de meilleures performances. Il est important de faire le meilleur choix.

Indicateurs de performance

Afin de trouver et d'évaluer les goulots d'étranglement des performances, vous devez connaître la définition des mesures de performances. Pour le réglage JVM, vous devez connaître les trois définitions suivantes et utiliser ces métriques comme base d'évaluation.

Principes de réglage des performances

Au cours du processus de réglage, les trois principes suivants vous aideront à implémenter un réglage plus simple de la récupération de place pour répondre aux exigences de performances de l'application souhaitée.

--Minor GC Collection Principle: Chaque fois qu'un GC mineur doit collecter autant d'objets de déchets que possible afin de réduire la fréquence des GC complets pour l'application.

Procédure de réglage des performances

image.png

La figure ci-dessus montre les étapes de réglage de base de la JVM pour une application. Vous pouvez voir que le réglage JVM implique une optimisation continue de la configuration et plusieurs itérations basées sur les résultats des tests de performances. Chacune des étapes précédentes peut subir plusieurs itérations avant que chaque métrique système souhaitée ne soit atteinte. Dans certains cas, les paramètres précédents peuvent devoir être réglés plusieurs fois pour répondre à une métrique particulière, et toutes les étapes précédentes peuvent devoir être testées à nouveau.

En outre, le réglage commence généralement par la satisfaction des exigences d'utilisation de la mémoire de l'application, suivi de la latence et du débit. Le réglage doit suivre cette série d'étapes. L'ordre de ces étapes de réglage ne peut pas être inversé. Les sections suivantes détaillent chaque étape de réglage avec des exemples.

Sélectionnez directement le mode serveur officiellement recommandé dans JDK 1.6 et supérieur pour exécuter la JVM.

Utilisez le collecteur parallèle par défaut JDK 1.6-1.8 comme garbage collector. (Utilisez parallelGC pour les jeunes générations, parallelOldGC pour les générations plus âgées).

Déterminer l'utilisation de la mémoire

Il y a deux choses que vous devez savoir avant de décider de l'utilisation de la mémoire.

1, phase d'opération d'application 2, allocation de mémoire JVM

Phase d'exploitation

Le fonctionnement de l'application est expliqué dans les trois phases suivantes.

--Initialisation: la JVM charge l'application et initialise le module principal et les données de l'application. --Stabilisation: l'application fonctionne depuis longtemps et fait l'objet de tests de résistance. Chaque paramètre de performance est dans un état stable. Les fonctions de base ont été exécutées et réchauffées à l'aide de la compilation JIT.

Allocation et paramètres de mémoire JVM

image.png

L'espace de stockage principal de la JVM est constitué des générations plus jeunes, des générations plus anciennes et des générations persistantes. La taille de la génération la plus jeune, la taille de la génération plus ancienne et la taille de la génération persistante constituent la taille totale du tas. Comment propulser un objet particulier n'est pas discuté ici. Voyons maintenant comment la commande JVM suivante spécifie la taille du tas. Si les paramètres suivants ne sont pas utilisés pour spécifier la taille du tas, la machine virtuelle choisira automatiquement la valeur appropriée, qui peut être ajustée automatiquement en fonction de la surcharge du système.

image.png

Si vous êtes préoccupé par la surcharge de performances, seul FullGC peut implémenter le dimensionnement de la génération permanente, alors définissez la taille initiale et la taille maximale de la génération permanente sur la même valeur chaque fois que possible.

Calculer la taille des données actives

Pour calculer la taille des données actives, procédez comme suit:

image.png

Comme mentionné précédemment, la taille des données actives doit être mesurée par la quantité d'espace occupée par le tas Java par des données actives depuis le début de la phase de stabilité de l'application.

Lors du calcul de la taille des données actives, assurez-vous de répondre aux exigences suivantes:

Quand l'application est-elle en phase stable?

Après un stress suffisant, l'application est en phase de stabilité uniquement si elle atteint une charge de travail qui répond aux exigences de l'entreprise pendant les heures de pointe dans un environnement de production et reste stable après la pointe. .. Par conséquent, les tests de résistance sont essentiels pour déterminer si une application a atteint une phase stable. La procédure de test de résistance de votre application dépasse le cadre de cet article. J'aborderai cette question plus tard dans un autre article.

Après avoir déterminé que l'application est dans une phase stable, faites attention au journal GC de l'application, en particulier au journal Full GC.

GC log directive: -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:<filename>

Les journaux GC sont le meilleur moyen de collecter les informations nécessaires à l'optimisation. Vous pouvez trouver le problème en activant la journalisation GC même dans l'environnement de production. En activant la journalisation GC, vous pouvez fournir une multitude de données tout en minimisant l'impact sur les performances.

Le journal FullGC est requis. Si le journal FullG n'est pas disponible, utilisez un outil de surveillance pour forcer l'appel ou utilisez la commande suivante pour déclencher le journal.

jmap -histo:live pid

Si le CPG complet est activé pendant la période stable, les informations suivantes peuvent être obtenues.

image.png

À partir du journal GC ci-dessus, vous pouvez obtenir une estimation approximative de l'utilisation globale du tas et du temps GC de votre application pendant un GC complet. Pour obtenir une estimation plus précise, collectez les informations plusieurs fois et calculez la moyenne. Alternativement, il peut être estimé en utilisant le FullGC le plus long.

Dans la figure ci-dessus, 93168 Ko (environ 93 Mo) de l'espace de l'ancienne génération sont occupés après un GC complet. Considérez cette quantité de données comme des données actives dans l'espace de l'ancienne génération.

Les autres espaces de tas sont alloués selon les règles suivantes.

image.png

À partir des règles ci-dessus et des informations FullGC de la figure précédente, l'espace du tas d'application peut être planifié comme suit.

Espace de tas Java: 373 Mo = 93168 Ko (espace de l'ancienne génération) x 4

Espace jeune génération: 140 Mo = 93168 Ko (espace ancienne génération) x 1,5

Espace de génération permanent: 5 Mo = 3135 Ko (espace de génération permanent) x 1.

espace ancienne génération: 233 Mo = 373 Mo (espace de tas) -140 Mo (espace jeune génération)

Les paramètres de lancement d'application correspondants sont

java -Xms373m -Xmx373m -Xmn140m -XX:PermSize=5m -XX:MaxPermSize=5m

Réglage de la latence

Après avoir déterminé la taille des données actives pour votre application, vous devez régler la latence. À ce stade, la taille de la mémoire du tas et la latence ne peuvent pas répondre aux exigences de l'application, l'application doit donc être déboguée en fonction des exigences réelles de l'application.

Au cours de cette phase, vous devrez peut-être réoptimiser la configuration de la taille de votre tas, évaluer la durée et la fréquence de votre GC et décider si vous devez basculer vers un autre garbage collector.

Exigences de latence du système

Avant de procéder au réglage, vous devez savoir quelles sont les exigences de latence de votre système et quelles mesures peuvent être réglées pour la latence.

--Temps d'arrêt moyen moyen acceptable pour l'application: ce temps est comparé à la durée mesurée du GC mineur 2011.

Parmi les mesures mentionnées ci-dessus, portez une attention particulière au temps d'arrêt moyen et au temps de pause maximal. Ces deux paramètres sont très importants pour l'expérience utilisateur.

En fonction des exigences ci-dessus, vous devez obtenir les données suivantes:

--Durée minimale du GC --Nombre de GC mineurs --Durée maximale de FullGC --Fréquence GC complète dans le pire des cas

Taille optimisée de la jeune génération

image.png

Par exemple, dans le journal GC précédent, la durée moyenne du GC mineur est de 0,069 seconde et le GC mineur se produit une fois toutes les 0,389 secondes.

Le temps d'arrêt moyen est fixé à 50 ms et la durée actuelle (69 ms) est clairement trop longue pour être ajustée.

Nous avons constaté que plus l'espace de la ** jeune génération ** est grand, plus le MinorGC durera longtemps et moins fréquemment.

Pour réduire la durée, vous devez réduire la taille de l'espace de la jeune génération.

Pour réduire la fréquence, vous devez augmenter la taille de l'espace de la jeune génération.

Lors du redimensionnement de l'espace de la jeune génération, laissez la taille de l'espace de l'ancienne génération si possible pour minimiser l'impact du redimensionnement de l'espace de la jeune génération sur les autres sections.

Par exemple, si vous réduisez la taille de l'espace de jeune génération de 10%, ne modifiez pas la taille de l'espace de génération ancienne et de l'espace de génération permanent. Les paramètres après optimisation dans cette étape sont les suivants.

java -Xms359m -Xmx359m -Xmn126m -XX:PermSize=5m -XX:MaxPermSize=5m

The size of the young generation is changed from 140 MB to 126 MB; the heap size is changed accordingly; the old generation has no changes at this point.

Optimiser la taille de ** Old Generation **

Comme pour l'étape précédente, nous devons obtenir des données du journal GC avant l'optimisation. Cette étape se concentre sur la durée et la fréquence de FullGC.

image.png

Les informations suivantes peuvent être obtenues à partir de la figure précédente.

The average FullGC frequency is 1 FullGC every 5.8s.

The average FullGC duration is 0.14s.

(This is only a test. FullGC lasts longer in real projects.)

Taux de promotion d'objets

Est-il possible d'évaluer s'il n'y a pas de journal FullGC? Il est possible d'utiliser le taux de promotion pour l'évaluation.

Par exemple, dans le paramètre de démarrage ci-dessus, la taille de l'ancienne génération est de 233 Mo.

Le temps qu'il faut pour occuper ces 233 Mo d'espace libre dépend du taux de promotion de la jeune génération à la vieille génération.

Utilisation promotionnelle de l'ancienne génération = utilisation du tas Java après chaque utilisation de la génération MinorGC-Young après MinorGC

Taux de promotion d'objet = valeur moyenne (promouvoir l'utilisation de l'ancienne génération à chaque fois) / espace de l'ancienne génération

Avec le taux de promotion d'objet, vous pouvez calculer le nombre de GC mineurs nécessaires pour occuper l'espace dans l'ancienne génération et la durée approximative d'un GC complet.

Laisse moi te donner un exemple.

image.png

Dans la figure ci-dessus, il est décrit comme suit.

After the first minor GC, the usage of the old generation space is 8 KB (13740 KB - 13732 KB).

After the second minor GC, the usage of the old generation space is 4489 KB (22394 KB - 17905 KB).

After the third minor GC, the usage of the old generation space is 16822 KB (34739 KB - 17917 KB).

After the fourth minor GC, the usage of the old generation space is 30230 KB (48143 KB - 17913 KB).

After the fifth minor GC, the usage of the old generation space is 44195 KB (62112 KB - 17917 KB).

Utilisation de la promotion de l'ancienne génération après chaque GC mineur

Between the second and the first minorGCs: 4481 KB

Between the third and the second minorGCs: 12333 KB

Between the fourth and the third minorGCs: 13408 KB

Between the fifth and the fourth minorGCs: 13965 KB

Après le calcul, vous pouvez obtenir les informations suivantes.

The average usage promotion for each minorGC is 12211 KB (about 12 MB).

In the preceding figure, the minorGC happens once every 213ms on average.

Promotion rate = 12211 KB/213ms = 57 KB/ms

It takes about 4.185s (233*1024/57 = 4185ms) to fully occupy 233 MB of the old generation space.

La pire fréquence GC complète peut être estimée en utilisant les deux méthodes décrites ci-dessus. Vous pouvez ajuster la fréquence de Full GC en redimensionnant la génération précédente. Si le GC complet est trop long pour répondre aux exigences de latence minimales de l'application, vous devrez peut-être changer le garbage collector. L'article suivant détaille comment basculer vers un autre garbage collector (par exemple, balayage de marque actuel, basculement vers CMS, etc.). Le réglage du CMS est un peu différent.

Débit de réglage

Après avoir suivi les étapes de réglage mentionnées ci-dessus, nous sommes enfin dans la dernière étape de réglage. Dans cette étape, vous effectuerez un test de débit sur les résultats précédents et effectuerez des ajustements précis.

Tout au long du réglage, il est principalement basé sur les exigences de débit de votre application. L'application doit avoir une métrique de débit complète dérivée des exigences et des tests globaux de l'application. Le réglage peut être interrompu lorsque le débit de l'application atteint ou dépasse l'objectif de débit attendu.

Si vous ne parvenez toujours pas à atteindre les objectifs de débit de votre application après l'optimisation, vous devez examiner vos exigences en matière de débit et évaluer l'écart entre votre débit actuel et vos objectifs. Si l'écart est d'environ 20%, vous pouvez modifier les paramètres pour augmenter la mémoire et déboguer à nouveau l'application. Si l'écart est trop important, vous devez déterminer si les objectifs de conception et de débit correspondent et réévaluer les objectifs de débit du point de vue de l'application.

Pour les garbage collector, l'objectif du réglage du débit est de réduire ou d'éviter l'occurrence d'un GC complet et d'un CMS Stop-The-World. Les deux méthodes de garbage collector peuvent entraîner une réduction du débit des applications. Essayez de recycler autant d'objets que possible pendant la phase MinorGC pour éviter qu'ils ne soient rapidement promus auprès des générations plus anciennes.

Conclusion

Plumbr a enquêté sur l'utilisation de ramasseurs d'ordures spécifiques sur la base de 84 936 cas. Parmi les cas où le garbage collector est explicitement spécifié, le collecteur Concurrent Mark Sweep (CMS) est le plus fréquemment utilisé dans 13% des cas. Cependant, dans la plupart de ces cas, le ramasse-miettes optimal n'a pas été sélectionné. Ce cas majoritaire représente environ 87%.

image.png

Le réglage de la JVM est une tâche systématique et complexe. Pour le moment, le réglage automatique sous la JVM est très bon et la définition des paramètres initiaux de base peut garantir un fonctionnement stable pour les applications courantes. Certaines équipes peuvent ne pas donner la priorité aux performances des applications. Dans ce cas, le garbage collector par défaut est généralement suffisant pour répondre aux exigences souhaitées. Le réglage doit être basé sur votre propre situation.

Recommended Posts

Réglage des performances JVM: qu'est-ce que le réglage et comment élaborer un bon plan
Qu'est-ce qu'un objet immuable? [Explication comment faire]
Comment créer un conteneur Java
Comment créer un pilote JDBC
Comment créer un écran de démarrage
Comment créer un plug-in Jenkins
Comment faire un projet Maven
Comment créer un tableau Java
Comment identifier le chemin sur lequel il est facile de se tromper
Comment créer un résumé de calendrier Java
Comment créer un robot Discord (Java)
Comment créer une application avec un mécanisme de plug-in [C # et Java]
Introduction aux fonctions récursives: qu'est-ce qu'une fonction récursive?
Comment créer un JRE léger pour la distribution
Trouvez une valeur pratique pour avoir une méthode et en faire un ValueObject
Comment créer un plugin Vagrant que vous avez appris lorsque vous avez forké et publié vagrant-mutagen
[Rails] [Docker] Le copier-coller est OK! Comment créer un environnement de développement Rails avec Docker
Comment faire fonctionner JavaScript sur une page spécifique
Comment convertir A en A et A en A en utilisant le produit logique et la somme en Java
Comment faire un cache sans trop réfléchir
Comment faire un MOD pour Slay the Spire
Qu'est-ce qu'un constructeur
Qu'est-ce qu'un flux
Comment faire un pot ombré
Qu'est-ce qu'un servlet?
Apprendre Ruby avec AtCoder 13 Comment créer un tableau à deux dimensions
Que s'est-il passé dans «Java 8 to Java 11» et comment créer un environnement
Qu'est-ce que c'est? Découvrez comment n'importe qui peut écrire un programme
Comment développer et enregistrer une application Sota en Java
Comment joindre une table sans utiliser DBFlute et SQL
Comment créer et lancer un Dockerfile pour Payara Micro
Qu'est-ce qu'une classe wrapper?
Qu'est-ce qu'un type booléen?
Java - Comment créer JTable
Qu'est-ce qu'un commentaire significatif?
Comment laisser un commentaire
Qu'est-ce qu'un fichier JAR?
Qu'est-ce qu'une collection Java?
Qu'est-ce qu'une expression lambda?
[Rails] Comment faire des graines
Introduction à Ratpack (1) - Qu'est-ce que Ratpack?
Qu'est-ce que Fat⁉ enum?
Comment insérer une vidéo
Comment créer une méthode
Qu'est-ce que les microservices et les frameworks de microservices
Comment créer un hinadan pour un projet Spring Boot à l'aide de SPRING INITIALIZR
[Java] Comment utiliser les modificateurs statiques (Que sont l'importation statique finale et statique)
Comment charger un fichier de téléchargement Spring et afficher son contenu
Comment lire un fichier et le traiter comme une entrée standard
Quelle est la différence entre un serveur Web et un serveur d'applications?
Comment faire coexister CsrfRequestDataValueProcessor et RequestDataValueProcessor original sur Spring Boot
J'ai essayé de faire un Numeron qui n'est pas bon avec Ruby
[Swift5] Comment communiquer de ViewController à Model et transmettre une valeur
Comment faire un diamant révolutionnaire en utilisant Java pour déclaration wwww