Uber JVM Profiler proporciona un agente Java para recopilar varias métricas y seguimientos de pila para procesos Hadoop/Spark JVM de forma distribuida, por ejemplo, métricas de CPU/Memoria/IO.
Uber JVM Profiler también proporciona capacidades avanzadas de creación de perfiles para rastrear métodos y argumentos Java arbitrarios en el código de usuario sin necesidad de cambiar el código de usuario. Esta característica podría usarse para rastrear la latencia de llamada del nodo de nombre HDFS para cada aplicación Spark e identificar el cuello de botella del nodo de nombre. También podría rastrear las rutas de los archivos HDFS que lee o escribe cada aplicación Spark e identificar archivos activos para una mayor optimización.
Este generador de perfiles se crea inicialmente para perfilar aplicaciones Spark que generalmente tienen docenas o cientos de procesos/máquinas para una sola aplicación, de modo que las personas puedan correlacionar fácilmente las métricas de estos diferentes procesos/máquinas. También es un agente Java genérico y también podría usarse para cualquier proceso JVM.
mvn clean package
Este comando crea el archivo jvm-profiler.jar con los reporteros predeterminados como ConsoleOutputReporter, FileOutputReporter y KafkaOutputReporter incluidos. Si desea agrupar los reporteros personalizados como RedisOutputReporter o InfluxDBOutputReporter en el archivo jar, proporcione la identificación del perfil de Maven para ese reportero en el comando de compilación. Por ejemplo, para crear un archivo jar con RedisOutputReporter, puede ejecutar el comando mvn -P redis clean package
. Consulte el archivo pom.xml para conocer los reporteros personalizados disponibles y sus identificadores de perfil.
Puede cargar el archivo jar jvm-profiler en HDFS para que los ejecutores de la aplicación Spark puedan acceder a él. Luego agregue una configuración como la siguiente al iniciar la aplicación 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
El siguiente comando iniciará la aplicación de ejemplo con el agente generador de perfiles adjunto, que informará las métricas a la salida de la consola:
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
Utilice el siguiente comando para ejecutar jvm Profiler con la aplicación jar ejecutable.
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
Configure el generador de perfiles jvm en CATALINA_OPTS antes de iniciar el servidor Tomcat. Consulte el archivo logs/catalina.out para ver las métricas.
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"
Utilice el siguiente comando para utilizar jvm Profiler con Spring Boot 2.x. Para Spring Boot 1.x use -Drun.arguments
en lugar de -Dspring-boot.run.jvmArguments
en el siguiente comando.
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 admite el envío de métricas a Kafka. Por ejemplo,
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
Enviará métricas al tema Profiler_CpuAndMemory de Kafka. Consulte la parte inferior de este documento para ver un ejemplo de las métricas.
Consulte la publicación del blog de JVM Profiler.
Uber JVM Profiler admite las siguientes funciones:
Depure el uso de la memoria para todos los ejecutores de aplicaciones Spark, incluida la memoria dinámica de Java, la memoria no dinámica, la memoria nativa (VmRSS, VmHWM), el grupo de memoria y el grupo de búfer (búfer dirigido/asignado).
Depurar el uso de la CPU, el tiempo de recolección de basura para todos los ejecutores de Spark.
Depurar métodos de clase java arbitrarios (cuántas veces se ejecutan, cuánto tiempo pasan). Lo llamamos perfil de duración.
Depurar llamadas arbitrarias al método de clase Java y rastrear su valor de argumento. Lo llamamos perfilado de argumentos.
Realice Stacktrack Profiling y genere flamegraph para visualizar el tiempo de CPU invertido en la aplicación Spark.
Depurar métricas de IO (bytes de lectura/escritura de disco para la aplicación, CPU iowait para la máquina).
Depurar métricas de subprocesos de JVM, como el recuento total de subprocesos, subprocesos máximos, subprocesos activos/en vivo y subprocesos nuevos.
El agente Java admite los siguientes parámetros, que podrían usarse en la línea de comandos de Java como "-javaagent:agent_jar_file.jar=param1=value1,param2=value2":
reportero: nombre de clase para el reportero, por ejemplo, com.uber.profiling.reporters.ConsoleOutputReporter o com.uber.profiling.reporters.KafkaOutputReporter, que ya están implementados en el código. Podrías implementar tu propio reportero y establecer el nombre aquí.
configProvider: nombre de clase para el proveedor de configuración, por ejemplo, com.uber.profiling.YamlConfigProvider, que ya están implementados en el código. Podrías implementar tu propio proveedor de configuración y establecer el nombre aquí.
configFile: ruta del archivo de configuración que utilizará YamlConfigProvider (si configProvider está configurado en com.uber.profiling.YamlConfigProvider). Podría ser una ruta de archivo local o una URL HTTP.
etiqueta: cadena de texto sin formato que se informará junto con las métricas.
metricInterval: con qué frecuencia se recopilan e informan las métricas, en milisegundos.
DuraciónProfiling: configurar para perfilar clases y métodos específicos, por ejemplo, com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod. También admite comodines (*) para el nombre del método, por ejemplo, com.uber.profiling.examples.HelloWorldApplication.*.
argumentProfiling: configurar para perfilar un argumento de método específico, por ejemplo, com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1 ("1" significa obtener valor para el primer argumento y enviarlo en el reportero).
sampleInterval: frecuencia (milisegundos) para realizar el muestreo de seguimiento de pila; si este valor no está establecido o es cero, el generador de perfiles no realizará el muestreo de seguimiento de pila.
ioProfiling: si se deben perfilar las métricas de IO, puede ser verdadero o falso.
brokerList: lista de corredores si se usa com.uber.profiling.reporters.KafkaOutputReporter.
topicPrefix: prefijo de tema si se usa com.uber.profiling.reporters.KafkaOutputReporter. KafkaOutputReporter enviará métricas a varios temas con este valor como prefijo para los nombres de los temas.
OutputDir: directorio de salida si se usa com.uber.profiling.reporters.FileOutputReporter. FileOutputReporter escribirá métricas en este directorio.
Los parámetros se pueden proporcionar como argumentos en el comando java o en un archivo de configuración YAML si usa configProvider=com.uber.profiling.YamlConfigProvider. A continuación se muestra un ejemplo del archivo de configuración YAML:
reporter: com.uber.profiling.reporters.ConsoleOutputReporter
metricInterval: 5000
A continuación se muestra un ejemplo de métricas de CPU y memoria cuando se utiliza ConsoleOutputReporter o 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
}
]
}
Puede encontrar una lista de todas las métricas y la información correspondiente a ellas aquí.
Podemos tomar el resultado de Stacktrack Profiling para generar flamegraph para visualizar el tiempo de CPU. Usando el script de Python stackcollapse.py
, el siguiente comando colapsará el archivo de salida json de Stacktrack Profiling al formato de archivo de entrada para generar flamegraph. El script flamegraph.pl
se puede encontrar en FlameGraph.
python stackcollapse.py -i Stacktrace.json > Stacktrace.folded
flamegraph.pl Stacktrace.folded > Stacktrace.svg
Tenga en cuenta que es necesario habilitar el muestreo de seguimiento de pila para generar un gráfico de llamas. Para habilitarlo, configure el parámetro sampleInterval
. Si no está configurado o es cero, el generador de perfiles no realizará muestreo de seguimiento de pila.