加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

一次性搞清楚线上CPU100%,频繁FullGC排查套路

发布时间:2019-06-25 09:44:08 所属栏目:教程 来源:爱宝贝丶
导读:副标题#e# 处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及 Full GC 次数过多的问题。 当然,这些问题最终导致的直观现象就是系统运行缓慢,并且有大量的报警。 本文主要针对系统运行缓慢这一问题,提供该问题的排查思路,从而定位出

②等待一段时间之后,比如 10s,再次对 jstack 日志进行 grep,将其导出到另一个文件,如 a2.log,结果如下所示:

  1. "DestroyJavaVM" #12 prio=5 os_prio=31 tid=0x00007fe690066000 nid=0x2603 waiting on condition [0x0000000000000000] 
  2. "Thread-0" #11 prio=5 os_prio=31 tid=0x00007fe690065000 nid=0x5a03 waiting on condition [0x0000700003ad4000] 
  3. "VM Periodic Task Thread" os_prio=31 tid=0x00007fe68d114000 nid=0xa803 waiting on condition 

③重复步骤 2,待导出 3~4 个文件之后,我们对导出的文件进行对比,找出其中在这几个文件中一直都存在的用户线程。

这个线程基本上就可以确认是包含了处于等待状态有问题的线程。因为正常的请求线程是不会在 20~30s 之后还是处于等待状态的。

④经过排查得到这些线程之后,我们可以继续对其堆栈信息进行排查,如果该线程本身就应该处于等待状态,比如用户创建的线程池中处于空闲状态的线程,那么这种线程的堆栈信息中是不会包含用户自定义的类的。

这些都可以排除掉,而剩下的线程基本上就可以确认是我们要找的有问题的线程。

通过其堆栈信息,我们就可以得出具体是在哪个位置的代码导致该线程处于等待状态了。

这里需要说明的是,我们在判断是否为用户线程时,可以通过线程最前面的线程名来判断,因为一般的框架的线程命名都是非常规范的。

我们通过线程名就可以直接判断得出该线程是某些框架中的线程,这种线程基本上可以排除掉。

而剩余的,比如上面的 Thread-0,以及我们可以辨别的自定义线程名,这些都是我们需要排查的对象。

经过上面的方式进行排查之后,我们基本上就可以得出这里的 Thread-0 就是我们要找的线程,通过查看其堆栈信息,我们就可以得到具体是在哪个位置导致其处于等待状态了。

如下示例中则是在 SyncTask 的第 8 行导致该线程进入等待了:

  1. "Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9de08c7000 nid=0x5603 waiting on condition [0x0000700001f89000] 
  2.    java.lang.Thread.State: WAITING (parking) 
  3.     at sun.misc.Unsafe.park(Native Method) 
  4.     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304) 
  5.     at com.aibaobei.chapter2.eg4.SyncTask.lambda$main$0(SyncTask.java:8) 
  6.     at com.aibaobei.chapter2.eg4.SyncTask$$Lambda$1/1791741888.run(Unknown Source) 
  7.     at java.lang.Thread.run(Thread.java:748) 

死锁

对于死锁,这种情况基本上很容易发现,因为 jstack 可以帮助我们检查死锁,并且在日志中打印具体的死锁线程信息。

如下是一个产生死锁的一个 jstack 日志示例:

一次性搞清楚线上CPU100%,频繁FullGC排查套路

可以看到,在 jstack 日志的底部,其直接帮我们分析了日志中存在哪些死锁,以及每个死锁的线程堆栈信息。

这里我们有两个用户线程分别在等待对方释放锁,而被阻塞的位置都是在 ConnectTask 的第 5 行,此时我们就可以直接定位到该位置,并且进行代码分析,从而找到产生死锁的原因。

小结

本文主要讲解了线上可能出现的五种导致系统缓慢的情况,详细分析了每种情况产生时的现象,已经根据现象我们可以通过哪些方式定位得到是这种原因导致的系统缓慢。

简要的说,我们进行线上日志分析时,主要可以分为如下步骤:

①通过 top 命令查看 CPU 情况,如果 CPU 比较高,则通过 top -Hp 命令查看当前进程的各个线程运行情况。

找出 CPU 过高的线程之后,将其线程 id 转换为十六进制的表现形式,然后在 jstack 日志中查看该线程主要在进行的工作。

这里又分为两种情况:

  • 如果是正常的用户线程,则通过该线程的堆栈信息查看其具体是在哪处用户代码处运行比较消耗 CPU。
  • 如果该线程是 VM Thread,则通过 jstat -gcutil 命令监控当前系统的 GC 状况。

然后通过 jmap dump:format=b,file= 导出系统当前的内存数据。

导出之后将内存情况放到 Eclipse 的 Mat 工具中进行分析即可得出内存中主要是什么对象比较消耗内存,进而可以处理相关代码。

②如果通过 top 命令看到 CPU 并不高,并且系统内存占用率也比较低。此时就可以考虑是否是由于另外三种情况导致的问题。

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读