程序访问无响应问题排查
说明
在项目实施过程中,偶尔会出现页面访问卡顿甚至无响应,其中可能的原因之一是程序CPU爆满,这里模拟问题复现并复盘问题排查过程,以便后续出现类似问题作为参考。
模拟问题代码
在程序中写一段死循环逻辑(死循环将导致cpu暴涨),代码如下:
排查过程
当发现访问出现卡顿甚至无响应时,一般会先使用top命令查看CPU占用排名第一的进程,如下图:
可以看到第一个进程占用cpu超过了100%,由于后台服务运行在docker之上,所以再使用docker stats命令查看是哪个容器占用如此多的cpu如下图:
至此,找到了名为service-user-1(容器id为2d10ef8d7323)的容器占用了超常的cpu,至于为何占用百分比超出了100%,是因为它是按照占用单个逻辑cpu的百分比(差不多占用了一整个逻辑CPU),而不是物理机所有cpu的百分比。本服务器有1个物理CPU,6个物理CPU内核个数,12个逻辑CPU个数。
接着进入此容器,jps命令查看Java进程号,这里容器内只运行1个应用程序,且进程号为1
接着在容器内部使用top -H命令找出占用高CPU的线程id
可以看到id为101的线程占用了8%的CPU,这里为什么又是8%而不是超过100%了呢,因为这里是按照所有逻辑cpu算的,宿主机共12个逻辑CPU。
接着可以使用jstack命令查看JVM线程快照,即当前JVM线程正在执行的方法堆栈集合。使用jstack命令可以定位线程出现长时间卡顿的原因,如死锁,死循环等。由于堆栈中的线程id是以16进制展示的,所以需要将上述查到的线程id 101转换为16进制后再去堆栈查找相关信息,101转换为16进制结果为0x65,输入命令jstack -l 1 |grep ‘0x65’ -A 50后结果如下图:
可以看到此占用高CPU的线程堆栈关联的代码在UserServiceImpl类的268行,此时便可针对该代码片上下文进一步分析问题原因了。至此,整个排查过程结束。