线上占用CPU过高问题排查


前言

最近博主在搬砖的时候遇到了线上的一些问题,大致情况是这样的。表象:服务挂了,CPU占用比较高,一直在百分之九十多。肯定有小伙伴会说常规操作 ,reboot一下完事儿了。其实这样吧没毛病,但是解决不了根本问题。啥也不多说。咱们先说下线上排查三板斧。就算不能解决问题也能猜个差不多。

理论基础

  1. top 命令找出应用 pid-app
  2. top -Hp 命令找出线程 pid-thread printf '%x\n' 命令将线程 pid 转换成 16 进制 pid-thread-hex
  3. jstack | grep 'pid-thread-hex' 命令查看线程信息

示例

1.top 命令找出应用 pid-app

应用 pid 为 10195

2.top -Hp 命令找出线程 pid-thread

线程 pid 为17316

printf '%x\n' 命令将线程 pid 转换成 16 进制 pid-thread-hex 43a4

3. jstack | grep 'pid-thread-hex' 命令查看线程信息

其实我们看这个他正在运行。顾名思义-->线程一直没结束,死循环了。

划重点

截止到这我们其实只是找到了那个CPU高的线程,从上面也没发现什么东西,接下来重点来了。有几个方向可以去做,GC情况,磁盘IO,或者数据库的情况,这些都是需要考虑的地方。别忘了,我们要保留好现场。保留当时的堆栈信息,保留好当时的内存占用情况。

保存堆栈

指令:jstack -l [pid] > /path/[pid].stack

这里面的pid是应用pid,即上面说的 10195。从堆栈上看一下当前都那些线程正在运行,cat 10195.stack | grep runnable -C 20

除了GC多一点之外,其实也没看出啥东西。
我决定把jstack堆栈下载下来,好好看看里面都那些函数在运行,特别是业务代码。我找到一个比较可以的东西。

目测是这里出了问题,但是又不好断定。

分析到这结合上面可能是死循环,这里面显示GC又频繁,还发现了正在运行的业务代码,内心:曹尼玛,谁写的坑逼业务代码,都到这了还不让我找出来,我决定分析一下内存信息,看一看。

保存堆内存信息

指令:jmap -heap [pid]

由于内存信息比较大,我们只导出应用pid的内存信息。紧接着我们用MAT工具分析一下,不会分析的小伙伴,要学习一下了,这也是一个比较好的提示。

注:eclipse Memory Analyzer
Eclipse 提供的一个用于分析JVM 堆Dump文件的插件。借助这个插件可查看对象的内存占用状况,引用关系,分析内存泄露等。

实例结论

然后我把dump文件用MAT打开发现,String对象比较多,集合引用再结合之前的分析,我们发现确实是因为上面业务调用的时候获取时间字符串的时候陷入死循环了。当然这只是这个示例的答案,博主在之前的项目中,线上遇到服务器CPU很高的其他情况也比较多,但是归根接地还是这么写套路。希望对小伙伴排查项目有一点点小小的帮助。

本文由 Janker 创作,采用 CC BY 3.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。