排查CPU占用过高的问题

摘要:
背景最近测试服出现了CPU异常高的情况,占用率接近100%,所以写篇文章简单地记录下碰到这种情况,该如何去定位导致CPU异常的代码,下文介绍了几种比较常用的工具。总结此文简单介绍了三种排查服务器CPU负载高的方案,其实使用体验都还是比较简单的,但是有两点是万变不离其宗的,那就是底层工具的使用和解决问题的流程。

背景

最近测试服出现了CPU异常高的情况,占用率接近 100%,所以写篇文章简单地记录下碰到这种情况,该如何去定位导致CPU异常的代码,下文介绍了几种比较常用的工具。

下文均基于测试代码。

准备

我们先准备一个测试项目,此处使用的是一个简单的 springboot 的 web 项目,直接跑去官网初始化一个,地址:

地址,然后写了段简单的示例代码,见下图。

排查CPU占用过高的问题

打包后放到我本地的虚拟机上运行:nohup java -jar cputest-0.0.1-SNAPSHOT.jar &

在虚拟机上进行本地访问,运行死循环的那段逻辑:curl 127.0.0.1:7777/api/test

此时使用 top -c 查看服务器的 CPU 信息,发现已经使用了 97%,而且是被我们刚才启动的 java 进程占用的,PID 为 5008。

COMMAND 注释就是 ‘java -jar cputest-0.0.1-SNAPSHOT.jar’,显而易见。

排查CPU占用过高的问题

下面就介绍几种简单的方法来定位有问题的代码。

jstack 查看堆栈信息

此处原生的方法其实就是使用 jdk 自带的工具(需要注意的是:Linux自带的 openJdk 是没有的)。

这是最基础并且最有效的方法,因为很多其它的工具其实还是使用的 openJdk 的这一系列命令,只不过封装得更为友好了而已。

上文已经查出来是5008这个进程有问题。

所以我们就先查看下5008下面是哪些线程在搞鬼:top -Hp 5008

排查CPU占用过高的问题

从面板上我们乍一看,发现了三个异常的线程,PID分别为5010、5092、5093。

要使用 jstack 查看他们的堆栈信息,首先要将 PID 转为 16进制:printf "%x " 5010 5092 5093

排查CPU占用过高的问题

接下来就可以查看堆栈信息了,下面以5092这个为例(注意:16进制要在最前面添加0x):jstack 5008 | grep '0x13e4' -A10

排查CPU占用过高的问题

问题代码立马就找到了。

另外,我们也可以将堆栈信息打印下来:jstack 5008 > cputest.dump然后使用 cat 等命令工具进行过滤查看:cat -n cputest.dump | grep -A10 '0x13e4'

GC 信息也是有问题的:jstat -gcutil 5008 2000 5

比如老年代(O)使用率达到了 84%,元数据区(M)使用率达到了 94%,老年代回收次数(FGC)达到了 540 多

排查CPU占用过高的问题

Arthas(阿尔萨斯)

上文的方法比较繁琐,下面就使用目前特别火的工具来排查下问题。

Arthas 是阿里巴巴开源的一个针对 java 程序的线上诊断工具,全平台支持,有命令行,也有web端,功能非常强大,官网:地址。

我们先安装基础工具:curl -O https://alibaba.github.io/arthas/arthas-boot.jar

也可以从 gitee 下载:curl -O https://arthas.gitee.io/arthas-boot.jar

运行:java -jar arthas-boot.jar

Arthas 会罗列出当前服务器上面的所有 Java 进程,我们选择一个我们想要查看的就行,比如此处输入1即可。另外,首次运行是需要下载一些依赖工具的,如果无法下载,也可以使用全量安装。此时左下角也已经变成了 [arthas@5008],这个5008 就是我们想要查看的程序继进程

排查CPU占用过高的问题

控制台输入 dashboard 即可查看:

排查CPU占用过高的问题

从上面的面板上,其实很容易发现有两个异常的线程,ID 分别为 28 和 27,另外还有异常的 GC 信息。

输入 Ctrl c 退出面板,接下来我们就来为ID为27的这个线程把把脉,输入 thread 27 查看线程的详细信息:

排查CPU占用过高的问题

问题代码就这样被定为了,so cool !

输入 quite 即可退出 Arthas。

另外,Arthas 的功能十分强大,远不限于此,比如自带 jad 反编译工具等,此处暂不赘述

show-busy-java-threads

下面的这个工具,也是很常用并且很强大的,而且 show-busy-java-threads 只是useful-scripts 工具包中的工具之一。

下载:地址

上传 bin 文件夹下的 show-busy-java-threads 脚本到服务器上去。

赋予权限:chmod +x show-busy-java-threads

运行:./show-busy-java-threads

排查CPU占用过高的问题

从上图中就看到了异常代码的出处。

其他命令:

show-busy-java-threads -c 3:3为n,指定显示最耗cpu使用率前3的线程。show-busy-java-threads -c 3 -p 17376:展示进程17376耗费CPU组多的3个线程。

总结

此文简单介绍了三种排查服务器CPU负载高的方案,其实使用体验都还是比较简单的,但是有两点是万变不离其宗的,那就是底层工具的使用和解决问题的流程。

从打印的堆栈信息中我们就可以看出,信息都长的差不多,所以也可以看出,底层所使用的工具都一样,其实都是 jdk 的 jstack 等工具。

还有,此类问题一般的解决流程是:

查看 CPU 高负载的进程查看具体的线程找到对应进程的堆栈信息在上述的堆栈信息中过滤出对应线程的信息

免责声明:文章转载自《排查CPU占用过高的问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇word文档标题级别批量更改——批量降级与升级实例微信开发之如何使用开发工具--weixin-java-tools下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

L3-002 特殊堆栈 (30分) vector容器的模拟、vector容器的一些用法

vector容器的简单应用,我们可以用vector维护一个有序数组,每次对要插入的数用upper_bound或者lower_bound来 为这个数找一个应该插入到vector的位置。另外再找一个数组来维护插入数的顺序,来面对pop操作 在从小到大的排序数组中, lower_bound( begin,end,num):从数组的begin位置到end-1位置...

多线程和异步委托基础详解

在讲多线程前。先回忆下异步委托:       /*            异步委托自我解释:即用.net委托来自动创建次线程(子线程)以处理异步方法的调用         * 当调用BeginInvoke()方法的时候,程序就会自动创建一个子线程去处理异步委托的方法。         */ //线程被定义为可执行应用程序中的基本执行单元 1 //1:S...

由浅入深TheradLocal

线程并发:在多线程并发的场景下 传递数据:我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量 线程隔离:每个线程的变量都是独立的,不会相互影响 常用方法 方法声明 描述 ThreadLocal() 创建ThreadLocal对象 public void set(T value) 设置当前线程绑定的局部变量 public...

mysql半同步(semi-sync)源码实现

      mysql复制简单介绍了mysql semi-sync的出现的原因,并说明了semi-sync如何保证不丢数据。这篇文章主要侧重于semi-sync的实现,结合源码将semi-sync的实现过程展现给大家。最新的semi-sync源码可以参考官方5.7版本的实现,https://github.com/mysql/mysql-server。 打开...

线程及视频解码过程6-16

线程 一、为了让音视频更好的解码,这里我们需要采用多线程,用一个线程解码视频,一个线程解码音频,我们需要: 1.调用线程库 #include <thread> 2.std:thread t1(); 创建相应线程。 3、为了让每个线程更好的区分资源属于哪一个线程,我们可以用类来实现线程,在对应得类中用成员来区分。 例如:      通过新建一个...

synchronized实现原理及其优化-(自旋锁,偏向锁,轻量锁,重量锁)

1.synchronized概述: synchronized修饰的方法或代码块相当于并发中的临界区,即在同一时刻jvm只允许一个线程进入执行。synchronized是通过锁机制实现同一时刻只允许一个线程来访问共享资源的。另外synchronized锁机制还可以保证线程并发运行的原子性,有序性,可见性。 2.synchronized的原理: 我们先通过反编...