写点什么

干货第一弹 - 教你如何利用阿里开源工具进行排查线上 CPU 居高问题

  • 2021 年 11 月 11 日
  • 本文字数:3410 字

    阅读完需:约 11 分钟

  1. server.servlet.context-path=/api


</pre>


打包项目,上传测试服务器


<pre style="margin: 0px; padding: 8px 0px 6px; max-width: 100%; box-sizing: border-box; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: 0.544px; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background: rgb(27, 25, 24); border-radius: 0px; overflow-y: auto; color: rgb(80, 97, 109); text-align: start; font-size: 10px; line-height: 12px; font-family: consolas, menlo, courier, monospace, "Microsoft Yahei" !important; border-width: 1px !important; border-style: solid !important; border-color: rgb(226, 226, 226) !important;">


  1. java -jar demo-0.0.1-SNAPSHOT.jar &


</pre>


打开浏览器,访问死循环方法


打开浏览器,地址栏输入 http://xxxx/api/user/testWhile?size=2 返回“Hello 程序执行完毕”,说明调用成功。(开启了 2 个死循环)


到此问题代码,已经在服务器上面跑了。我们发现服务器报警,于是去线上排查。


原生方法


此方法无需额外安装工具,在没法连接互联网的情况下使用此方法排查效果较好。


top、printf 都是 Linux 原生命令,jstack、jstat 是 jdk 自带命令工具


很多功能强大的 Linux 和 java 诊断工具也是以 top、jstack、jstat 为基础命令做的封装


注意:jstack、jstat 等命令需要 jdk 完整安装,linux 自带的 openJdk 一般无此工具,可以在 java 的 bin 目录下查看是否有这些命令。

找到最耗 CPU 的进程

命令:top –c,显示进程运行信息列表


实例:top -c。


交互 1:按 1,数字 1,显示多核 CPU 信息。交互 2:键入 P (大写 p),进程按照 CPU 使用率排序




我们看出了双核 CPU 使用率已经达到 100%。


而第一个进程 PID 是 373 的就是我们要找的罪魁祸首了;可以看到进程最后一列,COMMAND 注释的进程名:“java -jar demo-0.0.1-SNAPSHOT.jar”。

找到最耗 CPU 的线程

命令:top -H -p 【PID】,显示一个进程的线程运行信息列表


实例:top -Hp 373?,如下图所示,可以看到多个高耗 CPU 使用率的线程


转换线程 PID 为 16 进制

命令:printf “%x\n” 【线程 pid】,转换多个线程数字为十六进制,第 4 步使用时前面加 0x。


实例:printf '%x\n' 406 405 375 376,得到结果 196、195、177、178;如下图所示:


查看堆栈,定位线程

命令:jstack 【进程 PID】| grep 【线程转换后十六进制】-A10?, 使用 jstack 获取进程 PID 堆栈,利用 grep 定位线程 id,打印后续 10 行信息。


实例:jstack 373 | grep '0x196' -A10,如下图所示:



我们通过查看堆栈信息,发现了问题是 TestWhile.whileTrue 引起的


而且发现有 2 个 GC 线程,看上图中的“GC task thread#0 (ParallelGC)”,代表垃圾回收线程,该线程会负责进行垃圾回收

存储堆栈,批量查看

查看堆栈信息,我们也可以换个方法查看,可以先将 jstack 堆栈信息存储起来。


命令:jstack 【进程 PID】> 【文件】


实例:jstack 373 > demo.dump,存储 373 进程的堆栈信息。


再使用 cat + grep 查找看看后面几个高 CPU 线程的堆栈信息。


实例:cat -n demo.dump | grep -A10 '0x196',如下图所示:



可以看到线程 0x196【线程 196】产生堆栈信息,直指方法 whileTrue。

GC 查看

我们看到上图中有 4 个线程中的 2 个线程没有看到 java 代码,而是 GC task thread#0 (Paralle


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


lGC),这个是 GC 垃圾回收的线程,是不是死循环导致了 GC 太频繁,导致 CPU 使用率居高不下呢?


我们使用 jstat 看下 jvm 的 GC 信息看看。


命令:jstat -gcutil 【进程 PID】【毫秒】【打印次数】


实例:jstat -gcutil 373 2000 5,查看 373 进程的 GC 信息,每 2 秒打印一次,共打印 5 次,如下图所示:



S0:幸存 1 区当前使用比例 S1:幸存 2 区当前使用比例 E:伊甸园区使用比例 O:老年代使用比例 M:元数据区使用比例 CCS:压缩使用比例 YGC:年轻代垃圾回收次数 FGC:老年代垃圾回收次数 FGCT:老年代垃圾回收消耗时间 GCT:垃圾回收消耗总时间


上面的原生方法查找要遵循一定的步骤,相对有些麻烦点,有没有比较简单的方法呢?往下看

Arthas(阿尔萨斯)

Arthas(阿尔萨斯)是阿里巴巴开源出来的一个针对 java 的线上诊断工具,功能非常强大。Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。我们来看看

下载 Arthas

1 使用 arthas-boot(推荐)


下载 arthas-boot.jar,然后用 java -jar 的方式启动:


<pre style="margin: 0px; padding: 8px 0px 6px; max-width: 100%; box-sizing: border-box; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: 0.544px; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background: rgb(27, 25, 24); border-radius: 0px; overflow-y: auto; color: rgb(80, 97, 109); text-align: start; font-size: 10px; line-height: 12px; font-family: consolas, menlo, courier, monospace, "Microsoft Yahei" !important; border-width: 1px !important; border-style: solid !important; border-color: rgb(226, 226, 226) !important;">


  1. curl -O https://alibaba.github.io/arthas/arthas-boot.jar

  2. java -jar arthas-boot.jar


</pre>



按 1 进入 java 进程,此时 java 进程 PID 已经变成 373


进入阿尔萨斯完成,如下图,可以看到登录路径已经变成了[arthas@17376]$,可以输入 dashboard,进入监控页面了。

监控查看

已经进入 Arthas 操作界面,输入 dashboard,回车后将看到线程及堆栈信息,如图所示,arthas 已经将 cpu 高使用率的线程给安排上了。



上面我们就看到有 2 个线程居高不下,还有 GC 的数量和耗时。

thread【ID】查看线程

ctrl + c 退出 dashboard 界面,输入 thread 32 查看线程信息,如下图所示:



可以看到是 TestWhile 类中的 whileTrue 方法中的 put 方法导致 cpu 使用率升高。


问题一下子就出来了,Arthas 功能不单单止于此,可以直接反编译,看看代码。

jad 反编译

使用 Arthas 自带的反编译方法 jad,输入命令:


?jad com.rainbow.demo.service.TestWhile


可以反编译 java 的 class 查看问题函数的具体代码,如下图所示:


退出 arthas

最后,既然问题已经找到,那就退出 Arthas 吧。输入命令:quit


Arthas 的功能是非常强大的,这里就简单介绍,下一次老顾用专门的文章介绍


老顾在介绍一个更简单的一个脚本,立刻发现问题所在

show-busy-java-threads

show-busy-java-threads.sh 这个工具是 useful-scripts 工具集的其中一个工具。


show-busy-java-threads 用于快速排查 Java 的 CPU 性能问题(top us 值过高),自动查出运行的 Java 进程中消耗 CPU 多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。


注意:此工具的核心还是使用 jdk 的 jstack 方法,只是在其上做了封装展示。

下载到当前目录下

下载地址:https://github.com/oldratlee/useful-scripts/releases


在 bin 下面有很多工具,我们这次只要 show-busy-java-threads.sh


上传 show-busy-java-threads 脚本到服务器

一定赋予执行权限

chmod +x show-busy-java-threads


直接运行


<pre style="margin: 0px; padding: 8px 0px 6px; max-width: 100%; box-sizing: border-box; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: 0.544px; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background: rgb(27, 25, 24); border-radius: 0px; overflow-y: auto; color: rgb(80, 97, 109); text-align: start; font-size: 10px; line-height: 12px; font-family: consolas, menlo, courier, monospace, "Microsoft Yahei" !important; border-width: 1px !important; border-style: solid !important; border-color: rgb(226, 226, 226) !important;">


  1. ./show-busy-java-threads?


</pre>



如下图所示,找到了 CPU 使用率前 5 高的线程,查找非常迅速。


从前面两个线程可以看出,与使用原生工具(jstack)看到的一样。

评论

发布
暂无评论
干货第一弹-教你如何利用阿里开源工具进行排查线上CPU居高问题