Uber JVM Profiler bietet einen Java-Agenten zum verteilten Sammeln verschiedener Metriken und Stacktraces für Hadoop/Spark-JVM-Prozesse, beispielsweise CPU-/Speicher-/IO-Metriken.
Uber JVM Profiler bietet außerdem erweiterte Profilierungsfunktionen, um beliebige Java-Methoden und -Argumente im Benutzercode zu verfolgen, ohne dass eine Änderung des Benutzercodes erforderlich ist. Diese Funktion könnte verwendet werden, um die Latenz von HDFS-Namensknotenaufrufen für jede Spark-Anwendung zu verfolgen und Engpässe bei Namensknoten zu identifizieren. Es könnte auch die HDFS-Dateipfade verfolgen, die jede Spark-Anwendung liest oder schreibt, und heiße Dateien zur weiteren Optimierung identifizieren.
Dieser Profiler wurde ursprünglich erstellt, um Spark-Anwendungen zu profilieren, die normalerweise Dutzende oder Hunderte von Prozessen/Maschinen für eine einzelne Anwendung haben, sodass Benutzer die Metriken dieser verschiedenen Prozesse/Maschinen problemlos korrelieren können. Es handelt sich außerdem um einen generischen Java-Agenten, der auch für jeden JVM-Prozess verwendet werden kann.
mvn clean package
Dieser Befehl erstellt die Datei jvm-profiler.jar mit den darin gebündelten Standardreportern wie ConsoleOutputReporter, FileOutputReporter und KafkaOutputReporter. Wenn Sie die benutzerdefinierten Reporter wie RedisOutputReporter oder InfluxDBOutputReporter in der JAR-Datei bündeln möchten, geben Sie im Build-Befehl die Maven-Profil-ID für diesen Reporter an. Um beispielsweise eine JAR-Datei mit RedisOutputReporter zu erstellen, können Sie den Befehl mvn -P redis clean package
ausführen. Bitte überprüfen Sie die Datei pom.xml auf verfügbare benutzerdefinierte Reporter und deren Profil-IDs.
Sie könnten die JVM-Profiler-JAR-Datei in HDFS hochladen, damit die Spark-Anwendungsausführer darauf zugreifen können. Fügen Sie dann beim Starten der Spark-Anwendung eine Konfiguration wie die folgende hinzu:
--conf spark.jars=hdfs://hdfs_url/lib/jvm-profiler-1.0.0.jar
--conf spark.executor.extraJavaOptions=-javaagent:jvm-profiler-1.0.0.jar
Der folgende Befehl startet die Beispielanwendung mit angehängtem Profiler-Agenten, der Metriken an die Konsolenausgabe meldet:
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
Verwenden Sie den folgenden Befehl, um den JVM-Profiler mit einer ausführbaren JAR-Anwendung auszuführen.
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
Legen Sie den JVM-Profiler in CATALINA_OPTS fest, bevor Sie den Tomcat-Server starten. Überprüfen Sie die Datei logs/catalina.out auf Metriken.
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"
Verwenden Sie den folgenden Befehl, um den JVM-Profiler mit Spring Boot 2.x zu verwenden. Verwenden Sie für Spring Boot 1.x im folgenden Befehl -Drun.arguments
anstelle von -Dspring-boot.run.jvmArguments
.
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 unterstützt das Senden von Metriken an Kafka. Zum Beispiel,
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
Es werden Metriken an das Kafka-Thema „profiler_CpuAndMemory“ gesendet. Ein Beispiel für die Metriken finden Sie unten in diesem Dokument.
Siehe JVM Profiler-Blogbeitrag.
Uber JVM Profiler unterstützt folgende Funktionen:
Debuggen Sie die Speichernutzung für alle Ihre Spark-Anwendungsausführer, einschließlich Java-Heap-Speicher, Nicht-Heap-Speicher, nativem Speicher (VmRSS, VmHWM), Speicherpool und Pufferpool (gerichteter/zugeordneter Puffer).
Debuggen Sie die CPU-Auslastung und Garbage Collection-Zeit für alle Spark-Executoren.
Debuggen Sie beliebige Java-Klassenmethoden (wie oft sie ausgeführt werden und wie lange sie dauern). Wir nennen es Dauerprofilierung.
Debuggen Sie beliebige Java-Klassenmethodenaufrufe und verfolgen Sie den Argumentwert. Wir nennen es Argument Profiling.
Führen Sie Stacktrack Profiling durch und generieren Sie Flamegraph, um die für die Spark-Anwendung aufgewendete CPU-Zeit zu visualisieren.
Debug-IO-Metriken (Lese-/Schreibbytes der Festplatte für die Anwendung, CPU-Iowait für die Maschine).
Debuggen Sie JVM-Thread-Metriken wie die Anzahl der Threads insgesamt, Peak-Threads, Live-/Aktiv-Threads und neue Threads.
Der Java-Agent unterstützt die folgenden Parameter, die in der Java-Befehlszeile wie „-javaagent:agent_jar_file.jar=param1=value1,param2=value2“ verwendet werden können:
Reporter: Klassenname für den Reporter, z. B. com.uber.profiling.reporters.ConsoleOutputReporter oder com.uber.profiling.reporters.KafkaOutputReporter, die bereits im Code implementiert sind. Sie können hier Ihren eigenen Reporter implementieren und den Namen festlegen.
configProvider: Klassenname für den Konfigurationsanbieter, z. B. com.uber.profiling.YamlConfigProvider, die bereits im Code implementiert sind. Sie könnten Ihren eigenen Konfigurationsanbieter implementieren und den Namen hier festlegen.
configFile: Konfigurationsdateipfad, der von YamlConfigProvider verwendet werden soll (wenn configProvider auf com.uber.profiling.YamlConfigProvider gesetzt ist). Dies kann ein lokaler Dateipfad oder eine HTTP-URL sein.
Tag: Nur-Text-Zeichenfolge, die zusammen mit den Metriken gemeldet wird.
metricInterval: Wie oft werden die Metriken erfasst und gemeldet, in Millisekunden.
DauerProfiling: Konfigurieren, um eine bestimmte Klasse und Methode zu profilieren, z. B. com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod. Es unterstützt auch Platzhalter (*) für Methodennamen, z. B. com.uber.profiling.examples.HelloWorldApplication.*.
argumentProfiling: Konfigurieren, um ein bestimmtes Methodenargument zu profilieren, z. B. com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1 („.1“ bedeutet, dass ein Wert für das erste Argument abgerufen und im Reporter gesendet wird).
sampleInterval: Häufigkeit (Millisekunden) für die Stacktrace-Abtastung. Wenn dieser Wert nicht festgelegt oder auf Null gesetzt ist, führt der Profiler keine Stacktrace-Abtastung durch.
ioProfiling: Ob E/A-Metriken profiliert werden sollen, kann wahr oder falsch sein.
BrokerList: Brokerliste bei Verwendung von com.uber.profiling.reporters.KafkaOutputReporter.
topicPrefix: Themenpräfix bei Verwendung von com.uber.profiling.reporters.KafkaOutputReporter. KafkaOutputReporter sendet Metriken an mehrere Themen mit diesem Wert als Präfix für Themennamen.
Ausgabeverzeichnis: Ausgabeverzeichnis bei Verwendung von com.uber.profiling.reporters.FileOutputReporter. FileOutputReporter schreibt Metriken in dieses Verzeichnis.
Die Parameter können als Argumente im Java-Befehl oder in einer YAML-Konfigurationsdatei bereitgestellt werden, wenn Sie configProvider=com.uber.profiling.YamlConfigProvider verwenden. Im Folgenden finden Sie ein Beispiel für die YAML-Konfigurationsdatei:
reporter: com.uber.profiling.reporters.ConsoleOutputReporter
metricInterval: 5000
Im Folgenden finden Sie ein Beispiel für CPU- und Speichermetriken bei Verwendung von ConsoleOutputReporter oder 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
}
]
}
Eine Liste aller Kennzahlen und zugehörigen Informationen finden Sie hier.
Wir können die Ausgabe von Stacktrack Profiling nutzen, um einen Flammengraphen zur Visualisierung der CPU-Zeit zu erstellen. Mithilfe des Python-Skripts stackcollapse.py
reduziert der folgende Befehl die JSON-Ausgabedatei von Stacktrack Profiling auf das Eingabedateiformat zum Generieren eines Flamegraphs. Das Skript flamegraph.pl
finden Sie bei FlameGraph.
python stackcollapse.py -i Stacktrace.json > Stacktrace.folded
flamegraph.pl Stacktrace.folded > Stacktrace.svg
Beachten Sie, dass es erforderlich ist, Stacktrace-Sampling zu aktivieren, um Flamegraph zu generieren. Um es zu aktivieren, legen Sie bitte den Parameter sampleInterval
fest. Wenn es nicht gesetzt oder auf Null gesetzt ist, führt der Profiler kein Stacktrace-Sampling durch.