Skip to content

在学校的时候做的项目并没有遇到CPU飙升等相关的问题,以至于针对于线上CPU飙升等问题的排查得不到锻炼,特此记录一下,关于CPU飙升问题的排查。

一、定位问题

一般情况下,在线上遇到了CPU飙升等问题,可以开启弹性扩容或重启服务来暂时性的避免问题,但终究是治标不治本。只有找到问题发生的原因才能从根本上解决问题。而一般来说导致Java程序CPU与内存冲高的原因有如下:

  • 代码中某个位置读取数据量较大,导致系统内存耗尽,从而导致Full GC次数过多,系统缓慢。
  • 代码中有比较耗CPU的操作,导致CPU过高,系统运行缓慢。
  • 代码某个位置有阻塞性的操作,导致该功能调用整体比较耗时,但出现是比较随机的;
  • 某个线程由于某种原因而进入WAITING状态,此时该功能整体不可用,但是无法复现;
  • 由于锁使用不当,导致多个线程进入死锁状态,从而导致系统整体比较缓慢

前两种情况出现的频率较高,可能会导致系统不可用,后三种会导致某个功能运行缓慢,但是不至于导致系统不可用。因此针对于这些情况,需要进行依依排查。

  1. 通过top命令查看所有进程的资源占用情况,找到资源占用较高的进程
  2. 然后通过top -Hp 查看对应进程下的线程资源使用情况
  3. 将线程id转化为16进制,然后jstack pid | grep tip 查看进程下对应线程的栈信息
  4. 通过jstat -gcutil 进程号 统计间隔毫秒 统计次数(缺省代表一直统计)查看对应的full gc等情况
  5. 也可以通过jconsole,MAT等可视化工具查看

二、排查问题

  1. Full GC次数过多:走上述1-4步,查看是因为生成量大对象导致,还是生成大对象导致等
  • 线上多个线程的CPU都超过了100%,通过jstack命令可以看到这些线程主要是垃圾回收线程
  • 通过jstat命令监控GC情况,可以看到Full GC次数非常多,并且次数在不断增加。
  1. 某个业务逻辑执行时间过长:走上述1-4步,查看具体的堆栈信息定位代码进一步排查

  2. 如果有死锁,会直接提示。关键字:deadlock。使用jstack打印线程信息会打印出业务死锁的位置。

  3. 随机出现大量线程访问接口缓慢:首先找到该接口,通过压测工具不断加大访问力度,如果说该接口中有某个位置是比较耗时的,由于我们的访问的频率非常高,那么大多数的线程最终都将阻塞于该阻塞点这样通过多个线程具有相同的堆栈日志,我们基本上就可以定位到该接口中比较耗时的代码的位置。

因此对于线上CPU的排查步骤大致便是如此,到了具体场景需要具体场景具体分析。以上只是一个大致的排查思路记录。

Released under the MIT License.