问题描述:
服务器正常启动,但一段时间后就出现CPU满载,客户端无法得到响应,服务端进入假死状态。
排查步骤:
1.看症状:CPU满载
使用top命令,发现有进程大量占用cpu资源,在top交互界面按c,显示详细command,按1可以查看每个cpu的负载情况,发现所部署的java应用大量占用CPU资源
2.排查导致CPU满载的线程
由第一步得到占用cpu资源的进程pid,使用top -Hp pid查看进程的线程运行信息列表。将cpu使用率高的线程PID转化为16进制,printf "%x" 13609,结合jstack工具查看到对应的堆栈信息jstack pid|grep -C5 上面得到的16进制值,得到如下图信息,可以得知为GC线程导致的cpu满载。使用jstat -gcutil pid 1000可以每秒打印应用的gc情况,得知应用的fullgc比较频繁。
3.针对上述暴露出的内存问题,使用jprofiler对应用进行内存监控
应用启动参数加上 -agentpath:/app/jprofiler9/bin/linux-x64/libjprofilerti.so=port=8849,nowait(路径根据jprofile服务端实际情况配置),这里有个前提,服务器需要安装相同版本的jprofiler服务端。启动应用后,启动jprofile客户端连接应用进行监控。点击左端的Memory栏目,默认的heap内存的可视化界面。可以对堆内存进行异常可视化监控,如下图:
同时,点击左方的Live memory下的all Object展示所有的对象,点击界面上方的Mark current可以以当前的数据作为参考基准,可以用来看堆内存剧增时什么对象数量在增加。
由上面的堆内存监控界面,可以看到在某个时间点开始,堆内存频繁gc和递增,鼠标放到堆内存异常波动的位置上,可以得到一个时间点。而在live memory界面中,可以看到CustCoreInfo占用了228M的内存,这个明显不合理。结合两个信息a、某个时间点,堆内存开始波动 b、堆中有大量的CustCoreInfo对象,到应用日志中查看信息,可以看到以下日志
发现在这个时间点,有ApproveResultNotify接口的请求,随后堆内存开始波动递增。于是进一步跟进,查看ApproveResultNotify接口代码,如下图:
发现代码中有一个漏洞,当loginUser没有客户号custNo时,会查全表的客户信息出来,创建上千万(生产量级)的对象出来,也符合jprofiler对象监控得到的数据(228M的CustCoreInfo对象且不被GC回收)。重新启动应用,参照上面时间点发起的请求信息,以相同的参数重新进行请求,场景重现,内存剧增。
福利时间
经过多年的技术学习和项目经验,积累了一下关于技术的视频,希望对各位有所帮助,这里免费分享给大家
1.关注+转发+点赞
2.请私信发:jvm