Java应用迁移至CCE容器异常问题优化分析
发表于 2025/09/12
0
作者|薛大量
环境信息
服务器型号 |
TaiShan 200 (Model 2280) |
操作系统 |
EulerOS 2.8 |
容器镜像 |
Kylin V10 SP2 |
软件 |
Netty 4.1.72.final |
OpenJDK 1.8.0_242 (上游来源为openEuler社区) |
|
JCTools 3.1.0 |
故障分析
BMC日志分析
-
sel日志主要记录服务器事件打印,近期无硬件故障事件打印(重启时间2022年11月4日)。

-
fdm日志主要记录服务器硬件故障打印,近期无硬件故障。

硬件分析总结:服务器硬件正常,无异常告警。
Netty应用分析
- 堆栈分析
使用jstack工具分析Netty应用运行出现异常时的堆栈,抓取内存的Dump包,存在死循环线程堆栈的情况。MpscChunkedArrayQueue::poll函数存在死循环,导致应用运行一直停留在该函数,死循环不停占用CPU资源,最终导致CPU资源被占满,容器hang死,应用异常。业务应用主要调用Netty的无锁队列BaseMpscLinkedArrayQueue.java,分析源码得知无锁队列消费者在调用poll函数去获取元素时进入了死循环。
- 排查buglist
排查Netty上游社区的buglist,上游社区曾提出相似的问题,相关buglist如下:
https://github.com/netty/netty/issues/11956
https://github.com/netty/netty/issues/13137
https://github.com/netty/netty/pull/11972
https://github.com/netty/netty/pull/12495
https://github.com/netty/netty/pull/10855
Netty在高版本中新创建了一个阻塞队列BlockingMessageQueue.java,通过设置开关“-Dio.netty.recycler.blocking=true”可以使用 BlockingMessageQueue 替代 MpscChunkedArrayQueue,避免进入死循环。 - Netty应用分析总结
Netty应用执行时进入死循环导致出现问题,死循环的原因需要通过java heapdump日志进一步分析,建议客户将测试环境的Netty版本升级到4.1.73,设置开关“-Dio.netty.recycler.blocking=true”使用有锁队列,进行充分测试验证后再上线到业务环境。
OpenJDK分析
OpenJDK分析使用jmap工具导出java heapdump日志进行分析,消费者MpscChunkedArrayQueue的两个无锁队列对象中存在大量的空元素,确认是消费者通过poll函数去获取队列元素时因为元素为空导致死循环。
排查OpenJDK上游社区的buglist,上游社区曾提出相似的问题,相关buglist如下:
https://bugs.openjdk.org/browse/JDK-8209420
https://bugs.openjdk.org/browse/JDK-8179954
客户使用的OpenJDK为麒麟提供,上游来源为openEuler社区,分析社区仓库的源码信息,242低版本源码和OpenJDK社区基本一致,通过OpenJDK的buglist可以确认低版本存在锁实现相关的缺陷,这些缺陷在高版本中已进行修复。
OpenJDK 1.8在242版本时已经进入维护期,主要进行bug修复和CVE修复。当前OpenJDK 1.8最新版本为362,分析OpenJDK 从242到362版本的release note,有50+的CVE修复合入,从安全方面进行分析,使用低版本有安全风险,建议升级OpenJDK版本。
OpenJDK官网发布的release note地址:https://wiki.openjdk.org/display/jdk8u/MainOpenJDK分析总结:
OpenJDK 1.8低版本存在锁相关实现的缺陷,这些缺陷在高版本中已修复,并且低版本存在安全风险,建议客户将测试环境的OpenJDK 1.8升级至最新版本,进行充分验证测试后再上线到业务环境。
根因分析及措施
根因分析
-
Netty低版本无锁队列MpscChunkedArrayQueue,当消费者无锁队列中存在空元素时会进入死循环;
-
OpenJDK 1.8低版本锁相关实现存在缺陷,这些缺陷在高版本中已修复。
建议措施
根据以下建议,进行充分验证测试后再上线到业务环境。
-
将Netty版本升级到4.1.73版本,并添加配置项“-Dio.netty.recycler.blocking=true”以使用有锁队列;
-
将OpenJDK 1.8升级到最新版本。