前言在我们开发过程中,无法避免的会出现所谓的垃圾代码,导致服务器的CPU一直处于100%。但我们应用已经上线,导致服务器CPU居高,但又不知道哪边出现的问题,我们应该怎么去找出哪边的代码出现问题呢?今天老顾就介绍几种工具去快速定位。 演示代码 我们先来编写一下代码,新建springboot的maven项目,创建web服务,引入SpringBoot内置web容器,pom.xml关键引用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. `<dependency>`2. `<groupId>org.springframework.boot</groupId>`3. `<artifactId>spring-boot-starter-web</artifactId>`4. `</dependency>`</pre> 创建service:TestWhile 创建Controller:TestWhile 配置文件application.properties
打包项目,上传测试服务器 <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> 打开浏览器,访问死循环方法
到此问题代码,已经在服务器上面跑了。我们发现服务器报警,于是去线上排查。 原生方法 此方法无需额外安装工具,在没法连接互联网的情况下使用此方法排查效果较好。 top、printf都是Linux原生命令,jstack、jstat是jdk自带命令工具。 很多功能强大的Linux和java诊断工具也是以top、jstack、jstat为基础命令做的封装。
找到最耗CPU的进程命令:top –c,显示进程运行信息列表 实例:top -c。
我们看出了双核CPU使用率已经达到100%。
找到最耗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引起的;
存储堆栈,批量查看查看堆栈信息,我们也可以换个方法查看,可以先将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 (ParallelGC),这个是GC垃圾回收的线程,是不是死循环导致了GC太频繁,导致CPU使用率居高不下呢? 我们使用jstat看下jvm的GC信息看看。 命令:jstat -gcutil 【进程PID】【毫秒】【打印次数】 实例:jstat -gcutil 373 2000 5,查看373进程的GC信息,每2秒打印一次,共打印5次,如下图所示:
上面的原生方法查找要遵循一定的步骤,相对有些麻烦点,有没有比较简单的方法呢?往下看 Arthas(阿尔萨斯)Arthas(阿尔萨斯)是阿里巴巴开源出来的一个针对 java 的线上诊断工具,功能非常强大。Arthas 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。我们来看看 下载Arthas1使用arthas-boot(推荐) 下载arthas-boot.jar,然后用java -jar的方式启动:
进入阿尔萨斯完成,如下图,可以看到登录路径已经变成了[arthas@17376]$,可以输入dashboard,进入监控页面了。 监控查看已经进入Arthas操作界面,输入dashboard,回车后将看到线程及堆栈信息,如图所示,arthas已经将cpu高使用率的线程给安排上了。 上面我们就看到有2个线程居高不下,还有GC的数量和耗时。 thread【ID】查看线程ctrl + c 退出dashboard界面,输入thread 32查看线程信息,如下图所示: 可以看到是TestWhile类中的whileTrue方法中的put方法导致cpu使用率升高。
jad反编译使用Arthas自带的反编译方法jad,输入命令:
可以反编译java的class查看问题函数的具体代码,如下图所示: 退出arthas最后,既然问题已经找到,那就退出Arthas吧。输入命令:quit
老顾在介绍一个更简单的一个脚本,立刻发现问题所在 show-busy-java-threadsshow-busy-java-threads.sh这个工具是useful-scripts工具集的其中一个工具。 show-busy-java-threads用于快速排查Java的CPU性能问题(top us值过高),自动查出运行的Java进程中消耗CPU多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。
下载到当前目录下下载地址:https://github.com/oldratlee/useful-scripts/releases
上传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)看到的一样。 其他命令 与Arthas一样,show-busy-java-threads也有一些其他很好用的增强命令:
总结今天老顾介绍了3中方法排查服务器CPU负载过高的情况,主要流程是:
在排查过程中我们不只使用了原生工具,还使用了增强工具Arthas与show-busy-java-threads,大大简化了我们排查的步骤。 其实增强工具无非就是在原生方法上面封装了而已,有很多这种工具都是在原生方法中封装而成。今天就介绍到这里,谢谢!!! 最后,欢迎大家在评论区提出自己的见解~ 这里小on君也给大家分享一份自己整理的Java进阶宝典《Java核心知识点整理.pdf》,全文覆盖了JVM、锁、高并发、反射、mybatis、Spring原理、微服务、Zookeeper、数据库、数据结构等等一系列的知识点,今天限时免费发放,获取方式~ 私信 :资料 即可 |
|