本人在在某次投产期间收到某个模块的一个pod的多次CPU与内存冲高告警,登录到目标Pod控制台使用top命令看到是Java进程CPU消耗。
接着使用工具查看Java线程信息,本人这里使用的是一个展示Java busy线程的脚本:showbusyjavathreads.sh,传送门:oldratlee/useful-scripts)。
运行脚本可以显示Java进程中的busy的线程并且按照使用率从上至下排列(附上那一次的截图):
sh showbusyjavathreads.sh
showbusyjavathreads.png
可以看到有四个GC线程在疯狂GC,前三个甚至达到了99.9%,是GC导致的CPU冲高。
使用jstack命令查看线程信息,并没有定位到问题,只是看到相关的四个GC线程在处于RUNNERABLE状态。
jstack pid > stack.txt
jstack.png
到了这里还是没有排查出具体的问题,下一步打算使用jmap命令进行内存分析。
jps # 查看java进程
jmap -dump:format=b,file=jmap.bin pid
把dump好的内存从生产上下载下来后,使用IBM的heapanalyzer进行分析(点击进入下载ha457.jar)。
# 启动带UI界面的Java内存分析器(这里dump的内存文件较大,故调大了JVM最大内存)
java -Xmx5G -jar ha457.jar
启动好后会弹出分析界面,选择dump的jmap.bin进行分析。
内存分析显示有两个WorkLogDomain类型的EntityPage各占了42.5%的堆内存,并且被分析工具标记出了Leak Suspect(蓝色高亮)。
image.png一般EntityPage都是单表交易生成的代码,对应某张表,图中可以看到单个EntityPage的子元素数量为106万个(1067086),感觉像是查了这张表的全量数据。
image.png于是又生产环境工具查询了这张表的记录数量为1069678个,与上面的数量相匹配(这个数据是第二天查的,在此期间内用户又新增了2k条数据)。
image.png
由此可以怀疑在CPU内存告警告警的那段时间,这张表在被频繁的查询全量数据,因此JVM也在疯狂的GC。
进入工程代码,全局搜索WorkLogDomain,发现有一个getAllWorkLogInfo的接口,该方法查询全量WorkLogDomain。至此已找到问题源头。
网友评论