Uber JVM Profiler 提供了一个 Java Agent,以分布式方式收集 Hadoop/Spark JVM 进程的各种指标和堆栈跟踪,例如 CPU/内存/IO 指标。
Uber JVM Profiler 还提供高级分析功能,可以跟踪用户代码上的任意 Java 方法和参数,而无需更改用户代码。此功能可用于跟踪每个 Spark 应用程序的 HDFS 名称节点调用延迟并识别名称节点的瓶颈。它还可以跟踪每个 Spark 应用程序读取或写入的 HDFS 文件路径,并识别热点文件以进行进一步优化。
该分析器最初是为了分析 Spark 应用程序而创建的,这些应用程序通常在单个应用程序中具有数十或数百个进程/机器,因此人们可以轻松地将这些不同进程/机器的指标关联起来。它也是一个通用的 Java 代理,也可用于任何 JVM 进程。
mvn clean package
此命令创建jvm-profiler.jar文件,其中捆绑了默认报告器(例如 ConsoleOutputReporter、FileOutputReporter 和 KafkaOutputReporter)。如果您想将自定义报告器(如 RedisOutputReporter 或 InfluxDBOutputReporter)捆绑到 jar 文件中,请在构建命令中提供该报告器的 Maven 配置文件 ID。例如,要使用 RedisOutputReporter 构建 jar 文件,可以执行mvn -P redis clean package
命令。请检查 pom.xml 文件以获取可用的自定义记者及其个人资料 ID。
您可以将 jvm-profiler jar 文件上传到 HDFS,以便 Spark 应用程序执行器可以访问它。然后在启动 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
以下命令将启动附加了探查器代理的示例应用程序,该代理将向控制台输出报告指标:
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
使用以下命令运行带有可执行 jar 应用程序的 jvm profiler。
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
在启动 tomcat 服务器之前,在 CATALINA_OPTS 中设置 jvm profiler。检查logs/catalina.out 文件中的指标。
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"
使用以下命令将 jvm profiler 与 Spring Boot 2.x 结合使用。对于 Spring Boot 1.x,在以下命令中使用-Drun.arguments
而不是-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 支持将指标发送到 Kafka。例如,
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
它将向 Kafka 主题 profiler_CpuAndMemory 发送指标。有关指标的示例,请参阅本文档底部。
请参阅 JVM 探查器博客文章。
Uber JVM Profiler 支持以下功能:
调试所有 Spark 应用程序执行器的内存使用情况,包括 java 堆内存、非堆内存、本机内存(VmRSS、VmHWM)、内存池和缓冲池(定向/映射缓冲区)。
调试所有 Spark 执行器的 CPU 使用情况、垃圾收集时间。
调试任意 java 类方法(它们运行了多少次,它们花费了多少时间)。我们称之为持续时间分析。
调试任意 java 类方法调用并跟踪它的参数值。我们称之为参数分析。
进行 Stacktrack 分析并生成火焰图,以可视化 Spark 应用程序所花费的 CPU 时间。
调试 IO 指标(应用程序的磁盘读/写字节,机器的 CPU iowait)。
调试 JVM 线程指标,例如总线程数、峰值线程、活动/活动线程和新线程。
java代理支持以下参数,可以在Java命令行中使用,例如“-javaagent:agent_jar_file.jar=param1=value1,param2=value2”:
reports:报告器的类名,例如 com.uber.profiling.reporters.ConsoleOutputReporter 或 com.uber.profiling.reporters.KafkaOutputReporter,这些已在代码中实现。您可以实现自己的记者并在此处设置名称。
configProvider:配置提供程序的类名,例如 com.uber.profiling.YamlConfigProvider,已在代码中实现。您可以实现自己的配置提供程序并在此处设置名称。
configFile:YamlConfigProvider 使用的配置文件路径(如果 configProvider 设置为 com.uber.profiling.YamlConfigProvider)。这可以是本地文件路径或 HTTP URL。
tag:纯文本字符串,将与指标一起报告。
metricInterval:收集和报告指标的频率(以毫秒为单位)。
urationProfiling:配置以分析特定的类和方法,例如com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod。它还支持方法名称的通配符(*),例如com.uber.profiling.examples.HelloWorldApplication.*。
argumentProfiling:配置为分析特定方法参数,例如 com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1(“.1”表示获取第一个参数的值并在报告器中发送)。
SampleInterval:进行堆栈跟踪采样的频率(毫秒),如果该值未设置或为零,则探查器将不会进行堆栈跟踪采样。
ioProfiling:是否分析 IO 指标,可以是 true 或 false。
BrokerList:如果使用 com.uber.profiling.reporters.KafkaOutputReporter,则为代理列表。
topicPrefix:如果使用 com.uber.profiling.reporters.KafkaOutputReporter,则为主题前缀。 KafkaOutputReporter 会将指标发送到多个主题,并以此值作为主题名称的前缀。
outputDir:如果使用 com.uber.profiling.reporters.FileOutputReporter,则为输出目录。 FileOutputReporter 会将指标写入此目录。
这些参数可以作为 java 命令中的参数提供,如果您使用 configProvider=com.uber.profiling.YamlConfigProvider,也可以在 YAML 配置文件中提供。以下是 YAML 配置文件的示例:
reporter: com.uber.profiling.reporters.ConsoleOutputReporter
metricInterval: 5000
以下是使用 ConsoleOutputReporter 或 KafkaOutputReporter 时的 CPU 和内存指标示例:
{
"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
}
]
}
您可以在此处找到所有指标及其对应信息的列表。
我们可以利用 Stacktrack Profiling 的输出来生成火焰图来可视化 CPU 时间。使用 Python 脚本stackcollapse.py
,以下命令会将 Stacktrack Profiling json 输出文件折叠为用于生成火焰图的输入文件格式。脚本flamegraph.pl
可以在 FlameGraph 中找到。
python stackcollapse.py -i Stacktrace.json > Stacktrace.folded
flamegraph.pl Stacktrace.folded > Stacktrace.svg
请注意,需要启用堆栈跟踪采样才能生成火焰图。要启用它,请设置sampleInterval
参数。如果未设置或为零,探查器将不会进行堆栈跟踪采样。