一、问题情况描述
业务场景:分布式定时任务,灰度测试重构的代码,原始代码处理业务时间为90-100分钟,时间过长,重构新代码,目标处理时间为40分钟
现象:在某项执行任务期间,cpu持续80-90%,系统负载高达30以上(32核cpu),平时负载都是7左右,任务执行时,有明显卡顿,导致当前机器部署的其他程序全部受到影响,迫于无奈,重启应用,重启之后,恢复正常,但第二天情况依旧可以复现
二、排查过程
步骤一
相关业务代码重构过,出现问题时,使用的是新代码,初步判断疑似代码有问题造成相关问题
解决方案:下掉新代码,重新code review
结论:并非代码问题导致
步骤二:猜想jvm可能出现问题,full gc
待问题复现时,打印相关gc日志
发现每三秒一次 full gc,导致cpu持续升高
判断问题是full gc频率过高造成
三、分析原因
业务代码重构导致full gc 频率极高,code review之后发现,新的代码会产生大量对象,这些对象应在ygc被回收才对,但事实正相反,ygc没有回收,内存对象持续在老年代创建,导致高频率但full gc产生,疑似内存担保机制导致该问题产生
检查jvm参数
此项目已经运行了三年,但是未配置任何收集器 - - !
四、修改jvm参数
当前jvm内存6gb,于是直接使用g1收集器
配置相关jvm参数,并观察jvm内存和cpu使用情况
jvm 参数如下
-Xmx6g -Xms6g -Xss256k -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m -Xloggc:/usr/local/logs/server/tomcat_gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/logs/heapdump/server.dump -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -XX:+UseG1GC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Dcom.sun.management.jmxremote.port=19001 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=服务器公网ip
在使用g1之后,对比原始代码和新代码,jvm运行情况如下
原始代码:
新代码:
五、结论:
使用g1收集器作为项目的垃圾回收器
备注:
新代码依然会持续触发gc,g1的ygc时间很短,大概在30-40ms之间,业务可以容忍,cpu还是会有一些抖动,但是并不影响到其他应用程序,cpu使用率可控,业务处理时间为37分钟,代码重构可以满足相应业务需求
复盘结束