记一次线上CPU持续飙升的问题排查
最近公司的事务多了很多,都很少有时间来更新了。上周六项目上刚刚发生了一次CPU持续飙高,导致服务不可用的线上事故,在此也简单做下记录。
问题排查的过程大概是这样的:
查看业务日志中最开始报错的信息,发现数据库连接超时,redis也连接超时,而且出现了大量的连接超时。所以一开始怀疑数据库挂了导致业务线程一直积压。
DBA排查了数据库的情况,发现数据库并没有压力,也运行正常。redis的存储是满的。
然后开始排查cpu飙高的进程以及线程。步骤如下:
1、通过top命令可以看到哪个进程的cpu是高的。
2、然后通过top -Hp 进程id,可以查看这个进程对应的线程情况。
3、准备好jstack 进程id > /opt/test.log 命令。最好是新开窗口。再执行命令的那一刻,截图下top -Hp的线程情况,可以看到哪些线程当时是飙高的。
我截图的示例:
然后将线程的pid转化为16进制,然后在导出的jstack文件中查找对应的线程。 如果找不到,多执行几次步骤3(因为线程是不断变化的,所以这块需要手速)
从图中可以看到这个进程总CPU将近190%, 前四个线程各占40%+,经过查看这四个线程,
以28745来看,其16进制是7049, 在文件中查找如下:
可以看到是个GC的线程。同理,其他三个对应其他三个GC线程。还有个11.3%的线程,是VM Thread本身的线程,从这里可以看出,整个jvm已经只干GC的工作了,没有啥业务在进行了。而且在文件中还可以看到,基本其他线程都是阻塞状态:
所以其他线程的CPU基本是0%。
这就说明了GC导致了CPU的持续飙高。那什么引起的GC呢。为此我们导出了jmap文件进行分析。为了尽快恢复业务,导出之后,选择了立马重启了服务。但是我们发现很快CPU又飙高了。而且监控了GC的次数发现很快就不停的GC了。
我们看了下jvm的内存设置,发现堆内存只有1G,新生代512m。结合jmap分析,发现有大量的大对象
而且大对象的方法也进行定位。后来咨询了一下业务方,这个方法会有裂变式的数据增长,项目上新增了一些相关的基础数据,导致数据裂变式增长,jvm内存也比较小,所以大量的数据导致了jvm不停的垃圾回收最终会导致OOM。
结合这个原因我们让项目梳理了基础数据,没用的停用掉。 同时修改jvm内存,堆内存设置3000m,新生代maxnewsize设置为2000m,以让jvm更多的进行YGC,而不是FGC。后续还需要项目扩大redis的内存空间,减少缓存命中不了的情形。
本文地址:https://blog.csdn.net/sdmanooo/article/details/107165084