Uber JVM Profiler fournit un agent Java pour collecter diverses métriques et traces de pile pour les processus Hadoop/Spark JVM de manière distribuée, par exemple, les métriques CPU/Mémoire/IO.
Uber JVM Profiler fournit également des fonctionnalités de profilage avancées pour tracer des méthodes et des arguments Java arbitraires sur le code utilisateur sans nécessiter de modification du code utilisateur. Cette fonctionnalité pourrait être utilisée pour tracer la latence d'appel du nœud de nom HDFS pour chaque application Spark et identifier le goulot d'étranglement du nœud de nom. Il pourrait également retracer les chemins de fichiers HDFS que chaque application Spark lit ou écrit et identifier les fichiers chauds pour une optimisation ultérieure.
Ce profileur est initialement créé pour profiler les applications Spark qui comportent généralement des dizaines ou des centaines de processus/machines pour une seule application, afin que les utilisateurs puissent facilement corréler les métriques de ces différents processus/machines. Il s'agit également d'un agent Java générique et peut également être utilisé pour n'importe quel processus JVM.
mvn clean package
Cette commande crée un fichier jvm-profiler.jar avec les rapporteurs par défaut tels que ConsoleOutputReporter, FileOutputReporter et KafkaOutputReporter. Si vous souhaitez regrouper les rapporteurs personnalisés comme RedisOutputReporter ou InfluxDBOutputReporter dans le fichier jar, fournissez l'identifiant de profil maven pour ce rapporteur dans la commande build. Par exemple, pour créer un fichier jar avec RedisOutputReporter, vous pouvez exécuter la commande mvn -P redis clean package
. Veuillez vérifier dans le fichier pom.xml les rapporteurs personnalisés disponibles et leurs identifiants de profil.
Vous pouvez télécharger le fichier jar jvm-profiler sur HDFS afin que les exécuteurs de l'application Spark puissent y accéder. Ajoutez ensuite la configuration comme suivante lors du lancement de l'application Spark :
--conf spark.jars=hdfs://hdfs_url/lib/jvm-profiler-1.0.0.jar
--conf spark.executor.extraJavaOptions=-javaagent:jvm-profiler-1.0.0.jar
La commande suivante démarrera l'exemple d'application avec l'agent de profilage attaché, qui rapportera les métriques dans la sortie de la console :
java -javaagent:target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,tag=mytag,metricInterval=5000,durationProfiling=com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod,argumentProfiling=com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1,sampleInterval=100 -cp target/jvm-profiler-1.0.0.jar com.uber.profiling.examples.HelloWorldApplication
Utilisez la commande suivante pour exécuter le profileur jvm avec l’application jar exécutable.
java -javaagent:/opt/jvm-profiler/target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,metricInterval=5000,durationProfiling=foo.bar.FooAppication.barMethod,sampleInterval=5000 -jar foo-application.jar
Définissez le profileur jvm dans CATALINA_OPTS avant de démarrer le serveur Tomcat. Vérifiez le fichier logs/catalina.out pour les métriques.
export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/jvm-profiler/target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,metricInterval=5000,durationProfiling=foo.bar.FooController.barMethod,sampleInterval=5000"
Utilisez la commande suivante pour utiliser le profileur jvm avec Spring Boot 2.x. Pour Spring Boot 1.x, utilisez -Drun.arguments
au lieu de -Dspring-boot.run.jvmArguments
dans la commande suivante.
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-javaagent:/opt/jvm-profiler/target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,metricInterval=5000,durationProfiling=foo.bar.FooController.barMethod,sampleInterval=5000"
Uber JVM Profiler prend en charge l'envoi de métriques à Kafka. Par exemple,
java -javaagent:target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.KafkaOutputReporter,metricInterval=5000,brokerList=localhost:9092,topicPrefix=profiler_ -cp target/jvm-profiler-1.0.0.jar com.uber.profiling.examples.HelloWorldApplication
Il enverra des métriques au sujet Kafka profiler_CpuAndMemory. Voir au bas de ce document pour un exemple de métriques.
Voir l'article de blog du profileur JVM.
Uber JVM Profiler prend en charge les fonctionnalités suivantes :
Déboguez l'utilisation de la mémoire pour tous les exécuteurs de votre application Spark, y compris la mémoire tas Java, la mémoire non tas, la mémoire native (VmRSS, VmHWM), le pool de mémoire et le pool de mémoire tampon (tampon dirigé/mappé).
Utilisation du processeur de débogage, temps de récupération de place pour tous les exécuteurs Spark.
Déboguez les méthodes de classe Java arbitraires (combien de fois elles s'exécutent, combien de temps elles passent). Nous appelons cela le profilage de durée.
Déboguez l’appel de méthode de classe Java arbitraire et tracez la valeur de l’argument. Nous appelons cela le profilage d’arguments.
Effectuez le profilage Stacktrack et générez un flamegraph pour visualiser le temps CPU passé pour l'application Spark.
Déboguer les métriques IO (octets de lecture/écriture sur le disque pour l'application, iowait CPU pour la machine).
Déboguez les métriques de thread JVM telles que le nombre total de threads, les threads de pointe, les threads en direct/actifs et les nouveaux threads.
L'agent Java prend en charge les paramètres suivants, qui peuvent être utilisés dans la ligne de commande Java comme "-javaagent:agent_jar_file.jar=param1=value1,param2=value2" :
reporter : nom de classe du reporter, par exemple com.uber.profiling.reporters.ConsoleOutputReporter ou com.uber.profiling.reporters.KafkaOutputReporter, qui sont déjà implémentés dans le code. Vous pouvez implémenter votre propre journaliste et définir le nom ici.
configProvider : nom de classe du fournisseur de configuration, par exemple com.uber.profiling.YamlConfigProvider, qui sont déjà implémentés dans le code. Vous pouvez implémenter votre propre fournisseur de configuration et définir le nom ici.
configFile : chemin du fichier de configuration à utiliser par YamlConfigProvider (si configProvider est défini sur com.uber.profiling.YamlConfigProvider). Il peut s'agir d'un chemin de fichier local ou d'une URL HTTP.
tag : chaîne de texte brut qui sera rapportée avec les métriques.
metricInterval : à quelle fréquence collecter et rapporter les métriques, en millisecondes.
durationProfiling : configurez pour profiler une classe et une méthode spécifiques, par exemple com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod. Il prend également en charge le caractère générique (*) pour le nom de la méthode, par exemple com.uber.profiling.examples.HelloWorldApplication.*.
argumentProfiling : configurer pour profiler un argument de méthode spécifique, par exemple com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1 ("".1" signifie obtenir la valeur du premier argument et l'envoyer au journaliste).
sampleInterval : fréquence (millisecondes) pour effectuer l'échantillonnage de stacktrace, si cette valeur n'est pas définie ou nulle, le profileur n'effectuera pas d'échantillonnage de stacktrace.
ioProfiling : le profilage des métriques IO peut être vrai ou faux.
brokerList : liste des courtiers si vous utilisez com.uber.profiling.reporters.KafkaOutputReporter.
topicPrefix : préfixe du sujet si vous utilisez com.uber.profiling.reporters.KafkaOutputReporter. KafkaOutputReporter enverra des métriques à plusieurs sujets avec cette valeur comme préfixe pour les noms de sujets.
OutputDir : répertoire de sortie si vous utilisez com.uber.profiling.reporters.FileOutputReporter. FileOutputReporter écrira les métriques dans ce répertoire.
Les paramètres peuvent être fournis sous forme d'arguments dans une commande Java ou dans un fichier de configuration YAML si vous utilisez configProvider=com.uber.profiling.YamlConfigProvider. Voici un exemple du fichier de configuration YAML :
reporter: com.uber.profiling.reporters.ConsoleOutputReporter
metricInterval: 5000
Voici un exemple de métriques de processeur et de mémoire lors de l'utilisation de ConsoleOutputReporter ou de KafkaOutputReporter :
{
"nonHeapMemoryTotalUsed" : 11890584.0 ,
"bufferPools" : [
{
"totalCapacity" : 0 ,
"name" : " direct " ,
"count" : 0 ,
"memoryUsed" : 0
},
{
"totalCapacity" : 0 ,
"name" : " mapped " ,
"count" : 0 ,
"memoryUsed" : 0
}
],
"heapMemoryTotalUsed" : 24330736.0 ,
"epochMillis" : 1515627003374 ,
"nonHeapMemoryCommitted" : 13565952.0 ,
"heapMemoryCommitted" : 257425408.0 ,
"memoryPools" : [
{
"peakUsageMax" : 251658240 ,
"usageMax" : 251658240 ,
"peakUsageUsed" : 1194496 ,
"name" : " Code Cache " ,
"peakUsageCommitted" : 2555904 ,
"usageUsed" : 1173504 ,
"type" : " Non-heap memory " ,
"usageCommitted" : 2555904
},
{
"peakUsageMax" : -1 ,
"usageMax" : -1 ,
"peakUsageUsed" : 9622920 ,
"name" : " Metaspace " ,
"peakUsageCommitted" : 9830400 ,
"usageUsed" : 9622920 ,
"type" : " Non-heap memory " ,
"usageCommitted" : 9830400
},
{
"peakUsageMax" : 1073741824 ,
"usageMax" : 1073741824 ,
"peakUsageUsed" : 1094160 ,
"name" : " Compressed Class Space " ,
"peakUsageCommitted" : 1179648 ,
"usageUsed" : 1094160 ,
"type" : " Non-heap memory " ,
"usageCommitted" : 1179648
},
{
"peakUsageMax" : 1409286144 ,
"usageMax" : 1409286144 ,
"peakUsageUsed" : 24330736 ,
"name" : " PS Eden Space " ,
"peakUsageCommitted" : 67108864 ,
"usageUsed" : 24330736 ,
"type" : " Heap memory " ,
"usageCommitted" : 67108864
},
{
"peakUsageMax" : 11010048 ,
"usageMax" : 11010048 ,
"peakUsageUsed" : 0 ,
"name" : " PS Survivor Space " ,
"peakUsageCommitted" : 11010048 ,
"usageUsed" : 0 ,
"type" : " Heap memory " ,
"usageCommitted" : 11010048
},
{
"peakUsageMax" : 2863661056 ,
"usageMax" : 2863661056 ,
"peakUsageUsed" : 0 ,
"name" : " PS Old Gen " ,
"peakUsageCommitted" : 179306496 ,
"usageUsed" : 0 ,
"type" : " Heap memory " ,
"usageCommitted" : 179306496
}
],
"processCpuLoad" : 0.0008024004394748531 ,
"systemCpuLoad" : 0.23138430784607697 ,
"processCpuTime" : 496918000 ,
"appId" : null ,
"name" : " 24103@machine01 " ,
"host" : " machine01 " ,
"processUuid" : " 3c2ec835-749d-45ea-a7ec-e4b9fe17c23a " ,
"tag" : " mytag " ,
"gc" : [
{
"collectionTime" : 0 ,
"name" : " PS Scavenge " ,
"collectionCount" : 0
},
{
"collectionTime" : 0 ,
"name" : " PS MarkSweep " ,
"collectionCount" : 0
}
]
}
Une liste de toutes les mesures et informations correspondant à celles-ci peut être trouvée ici.
Nous pouvons utiliser la sortie de Stacktrack Profiling pour générer un flamegraph afin de visualiser le temps CPU. À l'aide du script Python stackcollapse.py
, la commande suivante réduira le fichier de sortie json de Stacktrack Profiling au format de fichier d'entrée pour générer le flamegraph. Le script flamegraph.pl
peut être trouvé sur FlameGraph.
python stackcollapse.py -i Stacktrace.json > Stacktrace.folded
flamegraph.pl Stacktrace.folded > Stacktrace.svg
Notez qu'il est nécessaire d'activer l'échantillonnage de stacktrace, afin de générer un flamegraph. Pour l'activer, veuillez définir le paramètre sampleInterval
. S'il n'est pas défini ou nul, le profileur n'effectuera pas d'échantillonnage de stacktrace.