jboss内存泄漏导致服务宕机故障排查及分析处理

jboss宕机排查

  • 问题描述
  • 问题排查思路
  • 问题排查步骤
    • 准备应用日志抓取脚本
    • 应用正常运行时抓取对照组
    • 宕机时抓取日志
  • 结果分析
    • 对比两次checklink.sh结果
    • 对比两次checkjstack.sh结果
    • 对比两次checkjmap.sh结果
    • 分析jboss日志。
  • 原因分析
  • 查找原因
  • 问题重现
    • 循环执行nc命令
    • 检测GC日志
    • 检测JMX
    • 检查jboss日志
    • 检查内存溢出与生产原因是否一致
      • 抓取日志
      • 将.hprof文件导入MAT进行分析。
  • 问题修复
  • 修复验证
    • jvisualvm检测内存
    • 检测GC日志
    • 执行日志抓取脚本
  • 结论
  • 上线步骤

问题描述

现有公司某产品运行在jboss上,线上运行一段时间后会出现宕机现象,宕机频率为2周左右。每次宕机后需要重新启动jboss后应用才可使用。运维人员已经多次反馈,此问题影响客户体验,急需解决。

问题排查思路

  1. 网络层。运维人员已有监控,对jboss应用HTTP接入端口9999进行了监听,如果9999端口无响应时,应用无法对外提供服务。此时在网络层Telnet检查9999端口是否可用,同时发送HTTP请求,检查是否有返回。
  2. 线程日志。抓取线程日志,检查是否存在死锁等情况。
  3. 内存堆栈。抓取线程日志,分析是否存在超大对象未释放。
  4. 分析jboss日志,对gc.log、boot.log、server.log等jboss日志与应用日志进行分析,检查报错信息。

问题排查步骤

准备应用日志抓取脚本

  1. 网络监听脚本:checklink.sh
  2. 应用端口状态脚本:checknetstat.sh
  3. 线程日志脚本:checkjstack.sh
  4. 内存堆栈脚本: checkjmap.sh
    具体脚本内容见附件1

应用正常运行时抓取对照组

应用正常运行时,执行日志抓取脚本得到日志文件,作为结果对照组。

宕机时抓取日志

应用宕机时,执行日志抓取脚本,抓取错误日志。并取下当天jboss日志与应用日志。

结果分析

对比两次checklink.sh结果

jboss内存泄漏导致服务宕机故障排查及分析处理_第1张图片
端口都是处于监听状态,配置应用端口与对照组一致。初步排除网络问题,问题应该在应用层。

对比两次checkjstack.sh结果

jboss内存泄漏导致服务宕机故障排查及分析处理_第2张图片两次结果中,比参照组中少了红色部分,当中并未异常线程,同时整个日志中并未查询到死锁等情况。初步排除应用有线程死锁等现象。

对比两次checkjmap.sh结果

将jmap执行出的.hprof文件,使用Eclipse Memory Analyzer Tools进行分析,整体内存占用情况如下:

jboss内存泄漏导致服务宕机故障排查及分析处理_第3张图片
对比两次结果,内存明显增长,逼近配置的最大内存1G。对照组为宕机前3天获取,3天内存由原来的761增长至941。
分析宕机时的内存最大的对象

jboss内存泄漏导致服务宕机故障排查及分析处理_第4张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第5张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第6张图片4个workerThread占用了总计883.7M内存,占用了93.85%的内存消耗。
用MAT工具分析对照组的内存消耗情况。
jboss内存泄漏导致服务宕机故障排查及分析处理_第7张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第8张图片
对比两次的执行结果,workerThread持续增加,初步怀疑是内存泄漏导致的内存溢出。

分析jboss日志。

分析server.log,发现日志中打印如下内容
在这里插入图片描述
分析业务日志,发现日志中打印出内存溢出错误。
jboss内存泄漏导致服务宕机故障排查及分析处理_第9张图片
由此可以断定平台的宕机是由于内存溢出导致。

原因分析

由上面分析的结果来看,推测是jboss中xnio占用的内存未释放导致,由于xnio并非是业务程序所引用,怀疑是jboss调用xnio的bug。网上查询该类问题

查找原因

根据现象,在JBossDeveloper上查询该问题,发现已有同样的问题。该问题与本次平台遇到的问一模一样,使用MAT工具分析出来的Biggest Objects也是一致的。查阅内容如下:
jboss内存泄漏导致服务宕机故障排查及分析处理_第10张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第11张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第12张图片

问题重现

按照jboos官方建议,使用nc命令即可重现该问题。

循环执行nc命令

服务端编写如下shell脚本,死循环方式调用nc

#!/bin/bash
while [ true ] ;
do
 echo | nc -v 162.16.8.24 9407;
done

检测GC日志

执行一段时间后,gc.log一致出现fullGC,且从日志来看每一次FullGC释放的内存为0
jboss内存泄漏导致服务宕机故障排查及分析处理_第13张图片

检测JMX

使用jvisualvm,持续监听jmx端口,发现内存持续增加,最终达到100%,与gc.log表现一致。
jboss内存泄漏导致服务宕机故障排查及分析处理_第14张图片

检查jboss日志

检查server.log,日志最后部分已经打印出内存溢出问题。
jboss内存泄漏导致服务宕机故障排查及分析处理_第15张图片
此时已经复现内存溢出问题,只需要验证测试环境与生产环境是同一问题导致。

检查内存溢出与生产原因是否一致

抓取日志

在测试环境执行日志抓取脚本check.sh,抓取.hprof文件。

将.hprof文件导入MAT进行分析。

jboss内存泄漏导致服务宕机故障排查及分析处理_第16张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第17张图片

对比发现,生产上内存溢出原因与测试环境复现保持一致。至此问题已经排查清晰。

问题修复

根据官方文档, jboss remoting 3.2.13.GA版本解决了该问题,考虑将jboss-remoting3升级至3.2.13.GA版本。
更新jboss remoting时需要同步更新依赖,将jboss xnio 更新至3.0.7.GA版本。
具体操作见上线包及上线说明。

修复验证

修复后,继续执行nc脚本,检查修复后是否存在内存泄漏。

jvisualvm检测内存

使用jvisualvm,持续监听jmx端口,发现内存占用呈现锯齿状,内存并未出现持续升高情况。
jboss内存泄漏导致服务宕机故障排查及分析处理_第18张图片

检测GC日志

查看gc.log,GC回收基本一致,与jmx监控一致,每次GC能释放内存。
jboss内存泄漏导致服务宕机故障排查及分析处理_第19张图片

执行日志抓取脚本

执行脚本check.sh,抓取.hprof文件,导入MAT进行分析,内存中并未出现较大未释放对象。
jboss内存泄漏导致服务宕机故障排查及分析处理_第20张图片
jboss内存泄漏导致服务宕机故障排查及分析处理_第21张图片

结论

根据验证修复结果,并未出现内存泄漏情况。更新jboss-remoting3至3.2.13.GA 版本可以修复此内存泄漏问题。
测试过程中只处理了jboss-remoting问题,并不确定是否还有其他问题,建议在生产配置jmx,定期观察,如有问题继续排查。

上线步骤

更新jboss-remoting

  1. 停用jboss
  2. 进入${HOME}/jboss-as-7.1.1.Final/modules/org/jboss目录
  3. 备份remoting3、logging、xnio文件夹
  4. 删除remoting3、logging、xnio文件夹
  5. 解压jboss-upgrade-package.zip至jboss目录下
  6. 启动jboss

增加jmx监听

  1. 停用jboss
  2. 进入${HOME}/jboss-as-7.1.1.Final/bin目录
  3. 备份standalone.conf文件
    cp standalone.conf standalone.conf.20190601.bak
  4. 编辑standalone.conf文件。
    在JAVA_OPTS="$JAVA_OPTS -Djboss.server.default.config=standalone.xml "后加入如下内容(不同配置可以配置方法有)
  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"
  1. 执行rdpstart启动应用
  2. 在本地打开${JAVA_HOME}\bin目录下的jvisualvm.exe文件
  3. Jvisualvm下添加jmx连接连接地址为:172.16.1.20:12345
  4. 进入Jvisualvm监控jvm内存等参数

附件
抓取日志脚本
jboss模块升级

你可能感兴趣的:(java)