O Uber JVM Profiler fornece um agente Java para coletar várias métricas e rastreamentos de pilha para processos Hadoop/Spark JVM de forma distribuída, por exemplo, métricas de CPU/memória/IO.
O Uber JVM Profiler também fornece recursos avançados de criação de perfil para rastrear métodos e argumentos Java arbitrários no código do usuário sem necessidade de alteração do código do usuário. Esse recurso pode ser usado para rastrear a latência de chamada do nó de nome HDFS para cada aplicativo Spark e identificar o gargalo do nó de nome. Ele também pode rastrear os caminhos dos arquivos HDFS que cada aplicativo Spark lê ou grava e identificar arquivos importantes para otimização adicional.
Este criador de perfil é inicialmente criado para criar o perfil de aplicativos Spark que geralmente têm dezenas ou centenas de processos/máquinas para um único aplicativo, para que as pessoas possam facilmente correlacionar métricas desses diferentes processos/máquinas. É também um agente Java genérico e também pode ser usado para qualquer processo JVM.
mvn clean package
Este comando cria o arquivo jvm-profiler.jar com os repórteres padrão como ConsoleOutputReporter, FileOutputReporter e KafkaOutputReporter incluídos nele. Se você deseja agrupar os repórteres personalizados como RedisOutputReporter ou InfluxDBOutputReporter no arquivo jar, forneça o ID do perfil maven para esse repórter no comando de construção. Por exemplo, para construir um arquivo jar com RedisOutputReporter, você pode executar o comando mvn -P redis clean package
. Verifique o arquivo pom.xml para repórteres personalizados disponíveis e seus IDs de perfil.
Você pode fazer upload do arquivo jar jvm-profiler para HDFS para que os executores do aplicativo Spark possam acessá-lo. Em seguida, adicione a configuração a seguir ao iniciar o aplicativo 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
O comando a seguir iniciará o aplicativo de exemplo com o agente criador de perfil anexado, que reportará métricas para a saída do 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
Use o seguinte comando para executar o jvm profiler com o aplicativo jar executável.
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 o criador de perfil jvm em CATALINA_OPTS antes de iniciar o servidor Tomcat. Verifique o arquivo logs/catalina.out para 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"
Use o seguinte comando para usar o jvm profiler com Spring Boot 2.x. Para Spring Boot 1.x, use -Drun.arguments
em vez de -Dspring-boot.run.jvmArguments
no comando a seguir.
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"
O Uber JVM Profiler oferece suporte ao envio de métricas para Kafka. Por exemplo,
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
Ele enviará métricas para o tópico Kafka profiler_CpuAndMemory. Consulte a parte inferior deste documento para ver um exemplo das métricas.
Consulte a postagem do blog do JVM Profiler.
O Uber JVM Profiler oferece suporte aos seguintes recursos:
Depure o uso de memória para todos os executores de aplicativos Spark, incluindo memória heap java, memória não heap, memória nativa (VmRSS, VmHWM), pool de memória e pool de buffer (buffer direcionado/mapeado).
Depurar o uso da CPU, tempo de coleta de lixo para todos os executores do Spark.
Depure métodos arbitrários de classe Java (quantas vezes eles são executados, quanto tempo eles gastam). Chamamos isso de Perfil de Duração.
Depure a chamada arbitrária do método de classe Java e rastreie o valor do argumento. Chamamos isso de Perfil de Argumento.
Faça Stacktrack Profiling e gere flamegraph para visualizar o tempo de CPU gasto para o aplicativo Spark.
Métricas de E/S de depuração (bytes de leitura/gravação de disco para o aplicativo, CPU iowait para a máquina).
Depure métricas de thread JVM, como contagem de threads totais, threads de pico, threads ativos/ativos e threads recentes.
O agente Java suporta os seguintes parâmetros, que podem ser usados na linha de comando Java como "-javaagent:agent_jar_file.jar=param1=value1,param2=value2":
reporter: nome da classe do repórter, por exemplo, com.uber.profiling.reporters.ConsoleOutputReporter ou com.uber.profiling.reporters.KafkaOutputReporter, que já estão implementados no código. Você poderia implementar seu próprio repórter e definir o nome aqui.
configProvider: nome da classe do provedor de configuração, por exemplo, com.uber.profiling.YamlConfigProvider, que já está implementado no código. Você poderia implementar seu próprio provedor de configuração e definir o nome aqui.
configFile: caminho do arquivo de configuração a ser usado pelo YamlConfigProvider (se configProvider estiver definido como com.uber.profiling.YamlConfigProvider). Pode ser um caminho de arquivo local ou URL HTTP.
tag: string de texto simples que será reportada junto com as métricas.
metricInterval: frequência de coleta e relatório das métricas, em milissegundos.
duraçãoProfiling: configure para criar perfil de classe e método específicos, por exemplo, com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod. Ele também suporta caracteres curinga (*) para o nome do método, por exemplo, com.uber.profiling.examples.HelloWorldApplication.*.
argumentProfiling: configure para criar um perfil de argumento de método específico, por exemplo, com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1 (".1" significa obter valor para o primeiro argumento e enviar no repórter).
sampleInterval: frequência (milissegundos) para fazer amostragem de stacktrace, se este valor não for definido ou zero, o profiler não fará amostragem de stacktrace.
ioProfiling: se deseja criar perfil de métricas de IO, pode ser verdadeiro ou falso.
brokerList: lista de corretores se estiver usando com.uber.profiling.reporters.KafkaOutputReporter.
topicPrefix: prefixo do tópico se estiver usando com.uber.profiling.reporters.KafkaOutputReporter. KafkaOutputReporter enviará métricas para vários tópicos com esse valor como prefixo para nomes de tópicos.
outputDir: diretório de saída se estiver usando com.uber.profiling.reporters.FileOutputReporter. FileOutputReporter gravará métricas neste diretório.
Os parâmetros podem ser fornecidos como argumentos no comando java ou em um arquivo de configuração YAML se você usar configProvider=com.uber.profiling.YamlConfigProvider. A seguir está um exemplo do arquivo de configuração YAML:
reporter: com.uber.profiling.reporters.ConsoleOutputReporter
metricInterval: 5000
A seguir está um exemplo de métricas de CPU e memória ao usar ConsoleOutputReporter ou 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
}
]
}
Uma lista de todas as métricas e informações correspondentes pode ser encontrada aqui.
Podemos usar a saída do Stacktrack Profiling para gerar flamegraph para visualizar o tempo de CPU. Usando o script Python stackcollapse.py
, o comando a seguir recolherá o arquivo de saída json do Stacktrack Profiling para o formato de arquivo de entrada para gerar flamegraph. O script flamegraph.pl
pode ser encontrado em FlameGraph.
python stackcollapse.py -i Stacktrace.json > Stacktrace.folded
flamegraph.pl Stacktrace.folded > Stacktrace.svg
Observe que é necessário habilitar a amostragem stacktrace para gerar flamegraph. Para habilitá-lo, defina o parâmetro sampleInterval
. Se não estiver definido ou for zero, o criador de perfil não fará amostragem de stacktrace.