几种常见的定位排查手段
一、场景描述
在实际应用场景中,JAVA 进程导致宿主机 CPU 使用率高的情况很常见,可能导致的原因很多:主机配置过低、代码质量低等;通常处于 bug 修复或者性能优化的需求,需要定位耗费大量 CPU 时间的罪魁祸首,这里提供几种常见的定位排查手段。
二、可选排查方式
【方式一】命令行 + jstack
jstack 是 Java 进程内的线程堆栈信息的常用工具,具体使用如下:
- 定位消耗 CPU 的进程 pid(按 P 排序):
top -c
- 可以将进程堆栈导出:
jstack -l <pid> > jstack.txt
,然后加载到本地客户端工具或者网页工具(如:heapdump)中进行分析 - 也可以完全使用命令行分析,定位消耗 CPU 的具体线程及其堆栈:
top -Hp <pid>
;输入 P 按 CPU 使用率排序,记住线程 pid 并转化为 16 进制:printf '%x\n' <nid>
,得到 16 进制的 nid-16;接着在 jstack 中找到对应堆栈信息:jstack -l <pid> | grep <nid-16> -C5 -color
或者jstack -l <pid> | grep <nid-16>
- 检查 JAVA 进程是否存在死锁:
jstack -l -F <pid>
【方式二】Arthas
Arthas 是 Alibaba 开源的一个 Java 诊断工具,方便进行问题的定位和诊断,可以在线排查问题,无需重启;动态跟踪 Java 代码;实时监控 JVM 状态。
- 下载 jar 包:
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
- 使用和业务应用相同的用户运行调试命令(会进入专用控制台并自动识别 java 进程并提供序号列表供选择):
java -jar arthas-boot.jar
- 使用说明:
- 输入
help
命令查看支持的选项,dashboard
命令用于整体展示进程所有线程、内存、GC 等情况,通过thread
的-n 5
选项找出最忙的前 5 个线程、-b
选项找出阻塞其他线程的线程,再输入thread <nid>
查看详情,使用trace
或者tt
命令进行跟踪分析,输入stop
退出。 profiler
命令支持生成应用热点的火焰图,默认生成的是 cpu 的火焰图(即 event 为 cpu,可以用 –event 参数来指定,支持的 event 可以使用profiler list
命令获取), 常规命令:- 启动采样:
profiler start
- 查看已获取的样本数:
profiler getSamples
- 查看采样状态:
profiler status
- 停止采样:
profiler stop
(支持通过--file
指定保存的文件名、--format html
指定输出为 html 格式,默认为 svg)
- 启动采样:
- 输入
- 火焰图分析说明:
- y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数
- x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多、即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的
- 颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调
- 火焰图就是看顶层的哪个函数占据的宽度最大。只要有”平顶”(plateaus),就表示该函数可能存在性能问题
【方式三】show-busy-java-threads 脚本
- 下载安装包:
wget --no-check-certificate https://github.com/oldratlee/useful-scripts/archive/release.zip
- 解压:
unzip release.zip && cd useful-scripts-release
- 使用(找出指定 java 进程中最消耗 CPU 的线程(缺省 5 个),打印出其线程栈):
./show-busy-java-threads -p <pid>