提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
背景
该项目是某单位的一个话务系统,基于ssh的单体项目,已经运行好几年。公司协助升级部分功能,但在重新部署后,每到高峰期电话增加,就会出现cpu飙高导致宕机。
一阶段问题排查
- 通过top命令可以定位该应用占用cpu飙到300%,占用内存达到3.8G。
- 通过过top -Hp pid 命令,可以定位到占用cpu最高的几个线程。
- 配合jstack查看对应线程(第2步获取id),可以看到占用cpu最高的线程都是垃圾回收线程。
- 通过jmap -dump:live,format=b,file=/opt/tmp/test.hprof pid获取堆内存转储文件
- 通过jvisualvm和mat进行分析发现关键问题如下图
- 定位关键字QueryPlanCache,查阅资料得知hibernate中的QueryPlanCache会缓存sql,以便于后边的相同的sql重复编译。如果in后的参数不同,hibernate会把其当成不同的sql进行缓存,从而缓存大量的sql导致heap内存溢出。QueryPlanCache默认2G.
- 通过jinfo查看jvm最大的堆内存是4G.
一阶段分析及处理结果
分析是由于堆内存不足,系统运行需要接近2G加上hibernate缓存2G刚好达到堆内存的最大值附近。当高峰期内存往上飙升,但堆内存不足,于是触发垃圾回收,但刚回收的内存马上又被用光,于是不停触发垃圾回收。导致垃圾回收的线程不停抢占cpu,最终导致宕机,但是没有想到从垃圾回收的层面来查看问题,如果当时可以通过jstate -gc ip 命令来查看垃圾回收的频率,可能会更快找到问题。
处理方式
增加最大堆内存的大小
结果及总结
堆内存增加以后,cpu飙高不再出现。但运行2天后又会出现系统宕机的问题,
二阶段问题排查
- 查看日志发现too many openfiles 异常。
- ulimit -a 看到当前的最大连接数是1024。
- 修改最大连接数后,过几天还是会不够,经观察,连接数是不停增加的,显示应该有忘记关闭的连接。
- 通过netstat -anop ip可以查看该进程建立的连接数。原来是程序员调用redis后忘记进行close。修改后问题处理完成。
处理方式
redis连接正确释放。
结果及总结
问题处理完成,良好运行。