四月中旬生产环境的服务器频繁爆出cpu使用率100%的警告,起初这个业务线不是我负责,也就没有深入了解问题。后边,负责这个业务线的同事离职了,这件事就落在我这边了。然后,开始长达两个月的问题排查和解决方案制定的历程,感叹离职的同事错过了这次学习的机会!
在计算机上能引起cpu使用率100%的原因不外乎以下几种:
在我们的业务中不存在什么计算,只是进行数据类型的转换、数据关联、数据入库和简单的数据比对。也就不算是计算密集型业务,剩下就只能从剩下的可能性中排查。
当然,如果存在死循环那么CPU使用率应该是一条直线,不会说服务不重启的情况下CPU的使用率降下来。这种可能性也就排除了。
在这里就需要排查 内存!内存!内存!
执行命令 top -c 查看进程使用资源情况显示如下:
从这个图中可以看到整个资源使用情况,以及各个进程资源使用情况。当然还可以使用不同的列对进程进行排序:
上面的截图中看不出来进程18069占用内存还是不小的,但是还达不到执行full gc的情况。因为我们设置的jvm内存最大是6g,也还可以,能接受。
当然这个是我们最后调整过的,之前是2g。在后边进行问题排查的时候暂时设置为6g,后来发现这个对于我们的服务来说也算是比较合适的值。
从上一步中可以看出来CPU使用率高的进程,接下来就是看一下进程的JVM的垃圾回收情况
1、 jstat -gc 进程号 时间间隔 次数
从这个截图可以看到JVM的各个区域的使用情况。当然了,问题已经解决了这边就没有那么高的次数了,在修复之前这个都是十几万的次数,每秒都在增加。
2、jstat -gcutil 进程号 间隔 次数
相比较这个命令现实的更加简洁直观
通过jstat命令排查出来我们的服务full gc频次过高,此时就有必要进行内存分析
jmap -dump:live,format=b,file=自定义名称.hprof 进程号
通过使用这个命令可以获取当前堆栈数据,然后就是进行内存的分析
关于mat使用方式,自行百度在这里不做详细说明。
通过mat工具分析出来大量的对象得不到及时的释放,无形中有点内存泄漏的赶脚
首先对JVM内存参数调整,2g->6g。先缓解一下报警,也有可能真的是jvm的内存设置太小造成的,至少给排查问题以充足的时间。但是好静不长,只坚持了一个晚上,大量CPU使用率100%报警又来了!
通过以上四步基本可以判定是大量对象得不到释放,怀疑是代码有问题。进行代码分析
1、mat结果锁定代码位置:mat分析结果表明在使用kafka发送消息的时候大量的producer对象不能及时释放,怀疑和使用的方式有问题。在我们的业务中存在使用CompletionService多线程消费消息再发送消息的功能,其中就有用到take这个方法进行阻塞,每次达到一定批量释放。因此怀疑这个地方有一定的问题!(这里一直有一个疑问没有搞明白,CompletionService在线程执行结束到take执行这段时间,线程引用的对象会不会释放?本人认为不会释放,领导认为会释放,截止目前没有搞清楚)
2、修改代码上线:将CompletionService换成原生的线程池,上线发布!
服务刚上线,马上就尴尬了,CPU使用100%报警马上就来
命令:top -Hp 18069
这个命令查看CPU使用率最高的线程
命令:jstack 18069 | grep -C 100 2846
由于问题已经解决这里就不展示截图,有问题可以显示出来是那行代码引起的CPU使用过高
通过堆栈信息的排查,可以看出来是kafka一直在进行rebalance引起CPU使用率100%
通过上面一通骚操作基本上排查出来问题。首先是排查内存,频发full gc。在解决full gc之后,发现CPU使用率仍然很高。后来再进行堆栈信息排查才发现是使用kafka消费消息的方案不对引起的。至此CPU使用率100%的问题已经排查出来,具体的解决方案,将在后边的文章中讲述。