RocketMQ:底层Netty频繁OS OOM

简介: 某核心应用出现少量机器OOM被杀,排查发现容器内存8G,JVM堆4G、MaxDirectMemorySize设为1G,但实际RSS远超预期。通过NMT定位到“Other”内存持续增长,结合Arthas发现7个不同ClassLoader加载了Netty的PooledByteBufAllocator,每个独立占用堆外内存,导致总使用量突破1G限制。其中rocketmq-client实例几乎占满1G,最终确认为多ClassLoader引发的堆外内存超额使用问题。

某核心应用的负责同学反馈应用存在少量机器OOM被OS kill的问题。看sunfire监控信息,的确如此。

初步收集到的信息:
容器内存=8G,Java 11,G1 GC=4G,MaxDirectMemorySize=1G。详见下图:

业务同学已经做过Java dump,可以看到堆外对象几乎没有,堆内的使用量也不大,<3G。上机器查看Java进程的内存使用量的确很大:

通过目前掌握到的信息来看,4G(Java堆)+1G(堆外)+512M(元空间)+250M(CodeCache)+其它,离6.8G还是有不少差距,无法简单的明确原因,需要深入排查分析了。
问题结论
省流版
中间件中多个不同的ClassLoader加载了多个netty的io.netty.buffer.PooledByteBufAllocator,每一个都有1G的内存配额,所以存在实际使用的堆外内存超出1G限制的问题。
通过Arthas可以看到存在这个类的7个不同的实例:

而其中rocketmq-client的这一个,已经基本用完1G的内存(其它几个使用量大多在100多M的样子):

详细版
中间件中多个不同的ClassLoader加载了多个netty的io.netty.buffer.PooledByteBufAllocator,每个Allocator都用自己的计数器在限制堆外内存的使用量,这个限制值大多数情况下取值至MaxDirectMemorySize,所以会存在无法限制堆外内存使用量在1G以内的问题。
这个应用是饿了么弹内的应用,io.netty.buffer.PooledByteBufAllocator,有7个ClassLoader加载了它,分别:
● sentinel's ModuleClassLoader:流量监控软件
● rocketmq-client's ModuleClassLoader:消息中间件
● tair-plugin's ModuleClassLoader:云数据库
● hsf's ModuleClassLoader:远程调用(类似dubbo)
● XbootModuleClassLoader
● pandora-qos-service's ModuleClassLoader:类似springboot
● ele-enhancer's ModuleClassLoader
相比弹内应用的4个(数据来自淘天集团的核心应用ump2,如下图),多了3个。

在Java8,以及Java11中(JVM参数设置了-Dio.netty.tryReflectionSetAccessible=true过后),netty会直接使用unsafe的方法申请堆外内存,不通过Java的DirectMemory分配API,所以通过监控看不到堆外内存的占用量,也不受JVM MaxDirectMemorySize的管控。
查看DirectByteBuffer实现代码可以发现,它限制MaxDirectMemorySize的方法是在Java层(代码标记处1),实际上在JVM底层是没有任何限制的,netty是直接用了这里代码标记处2的API分配内存。
排查过程
1.1.通过NativeMemoryTracking看Native内存的占用分布
通过在JVM参数上加上-XX:NativeMemoryTracking=detail,就可以打印出详细的内存分类的占用信息了,观察了一整天,发现主要的可疑变化是在Other部分,即堆外的部分,如下图。( Java NMT的详细使用可以参考相应的技术文章)

明明是限制的堆外1G,怎么超过了这么多。再多观察一会,发现它还会继续缓慢上涨的,最高达到接近1.5GB。这就和最开始查看Java进程的RSS占用对上了。

相关文章
|
测试技术
JMeter 随机数生成器详细指南:利用 Random 和 UUID 实现
在压力测试中,经常需要生成随机值来模拟用户行为。JMeter 提供了多种方式来生成随机值,本文来具体介绍一下。
|
1月前
|
数据采集 自然语言处理 监控
2026年企业有哪些agent应用场景?Agent在客服与营销中的落地场景应用
2026年,企业Agent深度落地客服与营销场景:Quick Audience实现全域用户识别与智能旅程编排;Quick Service支持多层级意图理解与情感化服务;Quick BI提供自然语言分析与实时决策辅助;Dataphin夯实数据治理底座。五大能力闭环协同,驱动人机共智升级。(239字)
|
11月前
|
人工智能 自然语言处理 监控
究竟怎样从零开始构建一个实用且高效的AI代理?
产品专家三桥君提出构建高效AI代理的关键步骤包括:明确任务、设计操作流程、构建最小可行产品(MVP)、连接与编排、测试与迭代,以及部署、扩展与优化。通过定义现实任务、编写详细操作流程,并利用提示工程工具构建核心提示,确保代理流畅执行任务。测试阶段包括手动和自动化测试,验证代理在不同场景下的表现。部署后,根据用户反馈和监控数据持续扩展和优化功能,确保代理在实际使用中高效稳定。持续迭代和用户反馈是成功的关键。
865 0
|
SQL 存储 缓存
Fluss 实战:用 Partial Update 构建实时宽表的新范式
传统流式数据管道通过多表 Join 构建宽表,如实时推荐引擎需整合用户偏好、购买记录等8个数据源,但此方法在大规模场景下状态管理复杂、资源消耗高且调试困难。Fluss 提出部分更新方案,基于主键将各数据源独立写入共享宽表,避免复杂 Join 操作。示例中,通过 Flink SQL 创建推荐、曝光、点击等表,并逐步插入数据实现宽表构建。最终,借助 Fluss 的高效合并机制,输出包含最新信息的统一视图,提升可扩展性和维护性。
549 8
Fluss 实战:用 Partial Update 构建实时宽表的新范式
|
11月前
|
存储 缓存 测试技术
开发文档的模版(参考)
本文档为[模块名称]的开发文档,详细介绍了系统模块的数据库表结构设计、接口定义、关键设计方案及外部API集成等内容,涵盖了核心表、从表、废弃表的设计规范,以及接口请求方式、参数说明、响应格式和异常处理机制。
757 0
|
Cloud Native Java 开发工具
云原生 阿里云分布式文件系统 对象存储OSS 服务配置
【1月更文挑战第8天】云原生 阿里云分布式文件系统 对象存储OSS 服务配置
|
Arthas 监控 Java
记一次内存利用率问题排查
记一次内存利用率问题排查
|
监控 数据可视化 Linux
Linux Docker图形化工具Portainer如何进行远程访问
Linux Docker图形化工具Portainer如何进行远程访问
|
监控 Java 数据库连接
解决Spring Boot中的数据库连接池问题
解决Spring Boot中的数据库连接池问题
|
Java Spring
使用 `BindingResult` 的步骤
使用 `BindingResult` 的步骤
494 0

热门文章

最新文章