现有公司某产品运行在jboss上,线上运行一段时间后会出现宕机现象,宕机频率为2周左右。每次宕机后需要重新启动jboss后应用才可使用。运维人员已经多次反馈,此问题影响客户体验,急需解决。
应用正常运行时,执行日志抓取脚本得到日志文件,作为结果对照组。
应用宕机时,执行日志抓取脚本,抓取错误日志。并取下当天jboss日志与应用日志。
端口都是处于监听状态,配置应用端口与对照组一致。初步排除网络问题,问题应该在应用层。
两次结果中,比参照组中少了红色部分,当中并未异常线程,同时整个日志中并未查询到死锁等情况。初步排除应用有线程死锁等现象。
将jmap执行出的.hprof文件,使用Eclipse Memory Analyzer Tools进行分析,整体内存占用情况如下:
对比两次结果,内存明显增长,逼近配置的最大内存1G。对照组为宕机前3天获取,3天内存由原来的761增长至941。
分析宕机时的内存最大的对象
4个workerThread占用了总计883.7M内存,占用了93.85%的内存消耗。
用MAT工具分析对照组的内存消耗情况。
对比两次的执行结果,workerThread持续增加,初步怀疑是内存泄漏导致的内存溢出。
分析server.log,发现日志中打印如下内容
分析业务日志,发现日志中打印出内存溢出错误。
由此可以断定平台的宕机是由于内存溢出导致。
由上面分析的结果来看,推测是jboss中xnio占用的内存未释放导致,由于xnio并非是业务程序所引用,怀疑是jboss调用xnio的bug。网上查询该类问题
根据现象,在JBossDeveloper上查询该问题,发现已有同样的问题。该问题与本次平台遇到的问一模一样,使用MAT工具分析出来的Biggest Objects也是一致的。查阅内容如下:
按照jboos官方建议,使用nc命令即可重现该问题。
服务端编写如下shell脚本,死循环方式调用nc
#!/bin/bash
while [ true ] ;
do
echo | nc -v 162.16.8.24 9407;
done
执行一段时间后,gc.log一致出现fullGC,且从日志来看每一次FullGC释放的内存为0
使用jvisualvm,持续监听jmx端口,发现内存持续增加,最终达到100%,与gc.log表现一致。
检查server.log,日志最后部分已经打印出内存溢出问题。
此时已经复现内存溢出问题,只需要验证测试环境与生产环境是同一问题导致。
在测试环境执行日志抓取脚本check.sh,抓取.hprof文件。
对比发现,生产上内存溢出原因与测试环境复现保持一致。至此问题已经排查清晰。
根据官方文档, jboss remoting 3.2.13.GA版本解决了该问题,考虑将jboss-remoting3升级至3.2.13.GA版本。
更新jboss remoting时需要同步更新依赖,将jboss xnio 更新至3.0.7.GA版本。
具体操作见上线包及上线说明。
修复后,继续执行nc脚本,检查修复后是否存在内存泄漏。
使用jvisualvm,持续监听jmx端口,发现内存占用呈现锯齿状,内存并未出现持续升高情况。
查看gc.log,GC回收基本一致,与jmx监控一致,每次GC能释放内存。
执行脚本check.sh,抓取.hprof文件,导入MAT进行分析,内存中并未出现较大未释放对象。
根据验证修复结果,并未出现内存泄漏情况。更新jboss-remoting3至3.2.13.GA 版本可以修复此内存泄漏问题。
测试过程中只处理了jboss-remoting问题,并不确定是否还有其他问题,建议在生产配置jmx,定期观察,如有问题继续排查。
更新jboss-remoting
增加jmx监听
cp standalone.conf standalone.conf.20190601.bak
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=162.16.1.20"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=12345"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
附件
抓取日志脚本
jboss模块升级