Cet article décrit certains outils de diagnostic des performances ** Java ** courants et met en évidence les principes de base et les meilleures pratiques de ** JProfiler **.
Les diagnostics de performance sont un problème auquel les ingénieurs logiciels sont souvent confrontés et qu'ils doivent résoudre dans leur travail quotidien. Vous pouvez obtenir de grands avantages en améliorant les performances de votre application. Java est l'un des langages de programmation les plus populaires. Ses diagnostics de performance ont longtemps été au centre de l'attention dans toute l'industrie. Dans les applications Java, de nombreux facteurs peuvent entraîner des problèmes de performances. Ces facteurs incluent le contrôle des threads, les E / S disque, l'accès à la base de données, les E / S réseau et le garbage collection (GC). Pour trouver ces problèmes, vous avez besoin d'un bon outil de diagnostic des performances. Cet article décrit certains outils de diagnostic des performances Java populaires et est représentatif de ces outils [JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html? Présentation des principes de base et des meilleures pratiques de spm = a2c65.11461447.0.0.4e294d65AIiUSB). La version de JProfiler présentée dans cet article est «JProfiler10.1.4».
Il existe une variété d'outils de diagnostic des performances dans le monde Java, des simples outils de ligne de commande tels que jmap et jstat aux outils de diagnostic graphiques complets tels que JVisualvm et JProfiler. Les sections suivantes décrivent brièvement chacun de ces outils.
Le kit de développement Java (JDK) fournit de nombreux outils de ligne de commande intégrés. Ces outils vous aident à obtenir des informations sur la machine virtuelle Java cible (JVM) sous différents aspects et différentes couches.
--jinfo - Vous pouvez afficher et ajuster divers paramètres de la JVM cible en temps réel. --jstack - Vous pouvez obtenir des informations sur la pile de threads pour le processus Java cible, détecter les blocages et trouver des boucles infinies. --jmap - Obtient des informations relatives à la mémoire pour le processus Java cible. Cela inclut différentes utilisations du tas Java, des statistiques sur les objets du tas Java, des classes chargées, etc. --jstat --Un outil de surveillance léger et polyvalent. Vous pouvez obtenir de nombreuses informations sur les classes chargées du processus Java cible, la compilation juste-à-temps (JIT), le garbage collection et l'utilisation de la mémoire. --jcmd --Complet que jstat. Vous pouvez obtenir diverses informations sur les statistiques de performances des processus Java cibles, l'enregistreur de vol Java (JFR), l'utilisation de la mémoire, le garbage collection, l'empilement des threads et le runtime JVM.
Vous pouvez utiliser tout ou partie des outils de ligne de commande ci-dessus pour obtenir des informations de base sur les performances de votre application Java cible. Cependant, ces outils présentent les inconvénients suivants:
Vous trouverez ci-dessous quelques outils de diagnostic des performances graphiques complets.
JVisualvm JVisualvm est un diagnostic de performance visuelle intégré fourni par JDK. C'est un outil. Utilisez diverses méthodes telles que JMX, jstatd et Attach API pour acquérir des données d'analyse de la JVM cible, telles que l'utilisation du processeur, l'utilisation de la mémoire, le nombre de threads, le nombre de segments de mémoire et le nombre de piles. Vous pouvez également afficher la quantité et la taille de chaque objet dans le tas Java, le nombre d'appels de méthode Java, le temps d'exécution de la méthode Java, etc.
JProfiler JProfiler est un outil de diagnostic des performances pour les applications Java développé par ej-technologies. Il se concentre sur quatre sujets importants.
Si vous souhaitez simplement diagnostiquer un goulot d'étranglement des performances dans une application Java autonome, les outils de diagnostic ci-dessus sont suffisants pour répondre à vos besoins. Cependant, à mesure que les systèmes autonomes modernes évoluent progressivement vers des systèmes distribués et des microservices, les outils ci-dessus ne répondront plus aux exigences. Par conséquent, Jaeger et [ARMS](https://cn.aliyun.com/product/arms?spm=a2c65. Vous devez profiter des capacités de traçage de bout en bout des systèmes de traçage distribués tels que 11461447.0.0.4e294d65AIiUSB) et SkyWalking. Divers systèmes de traçage distribués sont disponibles dans le commerce, mais le mécanisme de mise en œuvre est similaire. Il enregistre les informations de trace par suivi de code, envoie les données enregistrées au système de traitement central via le SDK ou l'agent, et fournit une interface de requête pour afficher et analyser les résultats. Pour plus d'informations sur les principes des systèmes de traçage distribués, consultez l'article intitulé Jaeger's Open Tracing Implementation.
JProfiler se compose d'un agent JProfiler pour collecter les données d'analyse de la JVM cible, d'une interface utilisateur JProfiler pour analyser visuellement les données et d'un utilitaire de ligne de commande qui fournit diverses fonctions. Voici un aperçu complet des interactions importantes entre eux.
L'agent JProfiler est implémenté en tant que bibliothèque native. Chargez au moment de l'exécution lorsque la JVM démarre en utilisant le paramètre -agentpath: <chemin vers la bibliothèque native> ou [JVM Attach Mechanism](http://lovestblog.cn/blog/2014/06/18/jvm-attach/?spm = a2c65.11461447.0.0.4e294d65AIiUSB) peut être utilisé pour charger pendant que l'application est en cours d'exécution. Une fois l'agent JProfiler chargé, il configure l'environnement JVM Tools Interface (JVMTI) pour surveiller tous les types d'événements générés par la JVM, comme la création de threads et le chargement de classes. Par exemple, lorsqu'il détecte un événement de chargement de classe, l'agent JProfiler insère son propre bytecode dans ces classes pour effectuer la mesure.
JProfiler UI L'interface utilisateur de JProfiler est lancée individuellement et se connecte à l'agent de profilage via un socket. Autrement dit, peu importe si la JVM profilée s'exécute sur la machine locale ou sur une machine distante - le mécanisme de communication entre l'agent de profilage et l'interface utilisateur de JProfiler est toujours le même.
À partir de l'interface utilisateur de JProfiler, vous pouvez demander à l'agent d'enregistrer des données, d'afficher les données de profilage dans l'interface utilisateur et d'enregistrer les instantanés sur le disque.
JProfiler fournit un ensemble d'outils de ligne de commande pour implémenter diverses fonctionnalités.
--jpcontroller - Utilisé pour contrôler la manière dont l'agent collecte les données. Envoyez des instructions à l'agent via le MBean JProfiler enregistré par l'agent. --jpenable - Utilisé pour charger l'agent dans une JVM en cours d'exécution. --jpdump - Utilisé pour capturer un instantané de tas d'une JVM en cours d'exécution. --jpexport & jpcompare - Utilisé pour extraire les données des instantanés précédemment enregistrés et créer des rapports HTML.
JProfiler prend en charge les diagnostics de performances pour les applications Java locales et distantes. Si vous avez besoin de collecter et d'afficher des données d'analyse pour une machine virtuelle Java distante en temps réel, procédez comme suit:
Pour plus de détails sur la procédure d'installation, consultez «Installation de JProfiler» et «[JVM Voir Profilage (https://www.ej-technologies.com/resources/jprofiler/help/doc/main/introduction.html#jprofiler.profiling).
Ici, les performances de la bibliothèque de classes LogHub Alibaba Cloud LOG Java Producer (ci-après, Producteur) Je vais vous montrer comment diagnostiquer avec JProfiler. Si vous rencontrez des problèmes de performances lors de l'utilisation de votre application ou Producer, vous pouvez prendre des mesures similaires pour trouver la cause première. Si vous êtes nouveau dans Producer, nous vous recommandons de lire cet article en premier. Alibaba Cloud LOG Java Producer - Un outil puissant pour la migration des journaux vers le cloud.
L'exemple de code utilisé ici est [SamplePerformance.java](https://github.com/aliyun/aliyun-log-producer-sample/blob/master/src/main/java/com/aliyun/openservices/aliyun/log /producer/sample/SamplePerformance.java?spm=a2c65.11461447.0.0.4e294d65AIiUSB&file=SamplePerformance.java).
JProfiler a deux méthodes de collecte de données: l'échantillonnage et la mesure.
--Échantillonnage --Convient aux scénarios qui ne nécessitent pas une grande précision de collecte de données. L'avantage de cette méthode est qu'elle a moins d'impact sur les performances du système. L'inconvénient est que certaines fonctionnalités, telles que les statistiques au niveau de la méthode, ne sont pas prises en charge.
--Instrumentation - Un mode de collecte de données complet qui prend en charge une haute précision. Les inconvénients sont que de nombreuses classes doivent être analysées et l'impact sur les performances de l'application est relativement important. Pour réduire l'impact, il est recommandé de l'utiliser avec un filtre.
Dans cet exemple, nous devons obtenir des statistiques au niveau de la méthode, nous choisissons donc la méthode d'instrumentation. Le filtre est configuré de manière à ce que l'agent enregistre les données du processeur pour seulement deux classes sous le package java: com.aliyun.openservices.aliyun.log.producer
et com.aliyun.openservices.log.Client
. Je suis.
Vous pouvez spécifier divers paramètres à l'agent JProfiler pour contrôler le mode de lancement de l'application.
--Attendez une connexion depuis l'interface graphique JProfiler --L'application ne se lancera que si l'interface graphique JProfiler établit une connexion avec l'agent de profilage et complète les paramètres de profilage. Cette option vous permet de profiler la phase de lancement de votre application. Commandes pouvant être utilisées pour activer cette option: -agentpath: <chemin vers la bibliothèque native> = port = 8849
Lancez maintenant et connectez-vous plus tard avec l'interface graphique JProfiler - L'interface graphique JProfiler établit une connexion avec l'agent de profilage et envoie les paramètres de profilage si nécessaire. Cette option est flexible, mais elle ne vous permet pas de profiler la phase de lancement de votre application. Commandes pouvant être utilisées pour activer cette option: -agentpath: <chemin vers la bibliothèque native> = port = 8849, nowait.
Si le profil est hors ligne et que JProfiler ne peut pas se connecter - Vous devez définir un déclencheur pour enregistrer les données et enregistrer l'instantané qui peut être ouvert plus tard dans l'interface graphique de JProfiler. Les commandes que vous pouvez utiliser pour activer cette option sont -agentpath: <chemin vers la bibliothèque native> = offline, id = xxx, config = / config.xml.
Dans un environnement de test, vous devez déterminer les performances de votre application pendant la phase de lancement. Par conséquent, nous utiliserons ici l'option par défaut WAIT.
Une fois que vous avez configuré votre profilage, vous pouvez procéder au diagnostic des performances du producteur.
Sur la page de présentation, vous pouvez voir clairement les graphiques (télémétrie) de diverses mesures telles que la mémoire, l'activité du GC, les classes, les threads et la charge du processeur.
Sur la base de cette télémétrie, nous pouvons faire les hypothèses suivantes:
Le nombre d'exécutions, le temps d'exécution et les relations d'appel de chaque méthode dans l'application sont affichés dans la vue CPU. Ceux-ci vous aideront à trouver les méthodes qui ont le plus d'impact sur les performances de votre application.
L'arbre d'appels utilise un graphe d'arbre pour afficher de manière hiérarchique les relations d'appels entre les différentes méthodes. De plus, JProfiler trie les sous-méthodes par durée totale d'exécution, afin que vous puissiez trouver rapidement les méthodes clés.
Pour Producer, la méthode SendProducerBatchTask.run ()
prend la plupart du temps à s'exécuter. Si vous continuez à regarder vers le bas, vous pouvez voir que la plupart du temps il faut pour exécuter la méthode Client.PutLogs ()
.
Si vous disposez de nombreuses méthodes d'application et que de nombreuses sous-méthodes s'exécutent à de courts intervalles, vous pouvez utiliser la vue hotspot pour trouver rapidement les problèmes de performances. Cette vue vous permet de trier les méthodes en fonction de divers facteurs tels que le temps d'exécution individuel, le temps total d'exécution, le temps d'exécution moyen et le nombre d'appels. Le temps d'exécution individuel est le temps d'exécution total de la méthode moins le temps d'exécution total de toutes les sous-méthodes.
Dans cette vue, vous pouvez voir que les trois méthodes suivantes sont les plus lentes à exécuter: Vous pouvez voir que les trois méthodes «Client.PutLogs ()», «LogGroup.toByteArray ()» et «SamplePerformance $ 1.run ()» prennent le plus de temps à s'exécuter individuellement.
Après avoir trouvé les méthodes clés, vous pouvez afficher toutes les méthodes directement liées à ces méthodes clés dans la vue graphique des appels. Cela vous aidera à trouver une solution à votre problème et à développer la meilleure politique d'optimisation des performances.
Ici, vous pouvez voir que la plupart du temps d'exécution de la méthode Client.PutLogs () est passé à sérialiser l'objet. Par conséquent, la clé de l'optimisation des performances est de fournir une méthode de sérialisation plus efficace.
La vue Live Memory vous donne une allocation et une utilisation détaillées de la mémoire, ce qui peut vous aider à déterminer s'il y a une fuite de mémoire.
All Objects La vue Tous les objets affiche le nombre et la taille totale des différents objets du tas actuel. Comme vous pouvez le voir dans la figure suivante, de nombreux objets LogContent sont créés pendant l'exécution de l'application.
Allocation Call Tree La vue de l'arborescence des appels d'allocation montre la quantité de mémoire allouée à chaque méthode sous la forme d'un diagramme arborescent. Comme vous pouvez le voir, «SamplePerformance $ 1.run ()» et «SendProducerBatchTask.run ()» consomment beaucoup de mémoire.
Allocation Hot Spots Si vous disposez de nombreuses méthodes, vous pouvez voir rapidement quelle méthode a le plus d'objets affectés dans la vue Points sensibles d'allocation.
Thread History La vue Historique des threads affiche l'état de chaque thread à des moments différents.
Les tâches exécutées par différents threads ont des caractéristiques différentes.
--Thread Pool-1-thread- <M>
appelle périodiquement la méthodeProducer.send ()
pour envoyer des données de manière asynchrone. Ceux-ci ont continué à s'exécuter pendant que l'application était en cours d'exécution, mais la plupart d'entre eux ont été bloqués par la suite. La cause de ce comportement est que la vitesse de transmission des données de Producer est plus lente que la vitesse de génération de données et que la taille du cache de chaque instance de Producer est limitée. Après le lancement de l'application, pool-1-thread- <M>
est resté en cours d'exécution pendant un certain temps car Producer avait suffisamment de mémoire pour mettre en cache les données en attente d'envoi. Cela explique pourquoi l'utilisation du processeur était élevée au lancement de l'application. pool-1-thread- <M>
doit attendre que le producteur libère suffisamment d'espace. En conséquence, un grand nombre de threads sont bloqués.
--ʻAliyun-log-Producer-0-moverdétecte les lots expirés et les envoie à iothreadPool. La vitesse d'accumulation des données est rapide et le lot producteur est envoyé à IOThreadPool par
pool-1-thread-
--ʻAliyun-log-Producer-0-io-thread- Envoie les données d'IOThreadPool au magasin de journaux spécifié et passe la plupart du temps sur l'état des E / S du réseau. --ʻAliyun-log-Producer-0-success-batch-handler
traite les lots envoyés avec succès au magasin de journaux. Le rappel est simple et prend très peu de temps à exécuter. Par conséquent, SuccessBatchHandler est resté inactif la plupart du temps.
--ʻAliyun-log-Producer-0-failure-batch-handler` gère les lots qui ne parviennent pas à être envoyés au magasin de journaux. Dans notre cas, il n'y a aucune donnée qui n'a pas pu être envoyée. Il est resté inactif tout le temps.
Selon notre analyse, le statut de ces fils est conforme à nos attentes.
Une fois l'application terminée, JProfiler affiche une boîte de dialogue qui affiche les méthodes fréquemment appelées avec des temps d'exécution très courts. La prochaine fois, vous pourrez atténuer l'impact de JProfiler sur les performances des applications en configurant l'agent JProfiler pour ignorer ces méthodes.
Sur la base des diagnostics de JProfiler, l'application n'a pas de problèmes de performances majeurs ni de fuites de mémoire. La prochaine étape d'optimisation consiste à améliorer l'efficacité de la sérialisation des objets.