RocketMQ Broker 出现OutMemoryError: Direct Buffer memory

问题说明

查看RocketMQ Broker的日志:remoting.log,发现有以下报错:OutOfMemoryError: Direct buffer memory 或者rocketmq-client的日志:

问题分析

问题直接原因

DirectBuffer内存溢出和以下jvm参数有关系,DirectBuffer内存超过MaxDirectMemorySize就会报内存溢出

shell 复制代码
-XX:MaxDirectMemorySize=15g

导致DirectBuffer过大的原因

MessageExtEncoder

DirectBuffer内存在RocketMQ broker中,除了网络外,只有一个地方会使用到: 每个MessageExtEncoder申请的DirectBuffe的内存大小,是由broker的配置maxMessageSize指定:

shell 复制代码
# 限制的消息大小 128M
maxMessageSize=134217728

MessageExtEncoder 又是被CommitLog#putMessageThreadLocal这个ThreadLocal持有的,所以MessageExtEncoder申请的DirectBuffe总的内存大小,和线程数有关系。

使用MessageExtEncoder的场景

消息写入commitlog

消息写commitlog的时候,会使用putMessageThreadLocal 对消息序列化。 代码入口:CommitLog#asyncPutMessage 写入commitlog的线程数由sendMessageThreadPoolNums参数决定,默认值:

shell 复制代码
Math.min(Runtime.getRuntime().availableProcessors(), 4)

延迟消息

代码入口:DeliverDelayedMessageTimerTask#executeOnTimeup RocketMQ延迟消息分为18个等级,也会有18个线程。

事务消息

代码入口:EndTransactionProcessor#sendFinalMessage 事务消息的线程由 endTransactionThreadPoolNums参数决定,默认值:

shell 复制代码
Math.max(8 + Runtime.getRuntime().availableProcessors() * 2, sendMessageThreadPoolNums * 4)

RPC消息

代码入口:ReplyMessageProcessor#processReplyMessageRequest RPC消息的线程由processReplyMessageThreadPoolNums参数决定,默认值:

shell 复制代码
16 + Runtime.getRuntime().availableProcessors() * 2

PULL_OFFSET_MOVED

代码入口: PullMessageProcessor#generateOffsetMovedEvent 出现PULL_OFFSET_MOVED原因有三个: NO_MESSAGE_IN_QUEUE broker的最大偏移量为0

OFFSET_OVERFLOW_BADLY 消息请求偏移量大于broker最大的偏移量

OFFSET_TOO_SMALL消息请求偏移量小于broker最小的偏移量

正常情况下,消息拉取不会用到堆外内存,但是当消费偏移量有问题时,才会使用到堆外内存。

消息拉取线程数量由pullMessageThreadPoolNums参数决定,默认值:

shell 复制代码
16 + Runtime.getRuntime().availableProcessors() * 2

出现PULL_OFFSET_MOVED的时候,在broker.log的日志中会打印以下日志:PULL_OFFSET_MOVED:correction 通过这个日志可以看到出问题的topic和消费者组名称。

问题解决

通过问题的分析,可以知道RocketMQ Broker的最大堆外内存是:

shell 复制代码
(sendMessageThreadPoolNums 
+ endTransactionThreadPoolNums
+ processReplyMessageThreadPoolNums 
+ pullMessageThreadPoolNums 
+ 18) * maxMessageSize

查看broker.conf配置和jvm参数: 发现-XX:MaxDirectMemorySize=15g,而maxMessageSize * pullMessageThreadPoolNums 已经16g,超过了MaxDirectMemorySize。

再查看broker.log日志,的确是出现了 PULL_OFFSET_MOVED:correction 日志。

maxMessageSize和pullMessageThreadPoolNums太大,按理说,不应该配置这么大的值,需要按实际情况将这两个值调小。

相关推荐
熊文豪21 小时前
Apache RocketMQ在Windows下的保姆级安装教程(含可视化界面安装)
rocketmq
嫄码1 天前
Docker部署RocketMQ时Broker IP地址问题及解决方案
tcp/ip·docker·rocketmq
周杰伦_Jay3 天前
【RocketMQ全面解析】架构原理、消费类型、性能优化、环境搭建
性能优化·架构·rocketmq
默 语4 天前
消息中间件选型的艺术:如何在RocketMQ、Kafka、RabbitMQ中做出正确决策
java·架构·kafka·消息队列·rabbitmq·rocketmq·技术选型
心之伊始4 天前
RocketMQ 与 Kafka 架构与实现详解对比
架构·kafka·rocketmq
柳贯一(逆流河版)5 天前
RocketMQ 实战:马拉松系统异步化与延时任务落地(含死信队列处理)
rocketmq
koping_wu7 天前
【RocketMQ】架构原理、消息丢失、重复消费、顺序消费、事务消息
架构·rocketmq·java-rocketmq
Savvy..7 天前
消息队列MQ
kafka·消息队列·rabbitmq·rocketmq·mq
235167 天前
【MQ】RabbitMQ:架构、工作模式、高可用与流程解析
java·分布式·架构·kafka·rabbitmq·rocketmq·java-rabbitmq
会跑的葫芦怪7 天前
RocketMQ 与 RabbitMQ 全面对比:架构、性能与适用场景解析
架构·rabbitmq·rocketmq