一、问题
当向RocketMQ频繁push数据,broker负载较高时,会报system busy或broker busy的问题。当发生此类问题时,会导致数据丢失。
报system busy或broker busy 说明PageCache繁忙,向PageCache追加消息时,单个消息发送占用的时间超过一定时间,如果持续往该Broker服务器发送消息并等待,超时后,broker采用快速失败机制返回失败信息。
解决这种问题需要对RocketMQ进行配置调优,提升RocketMQ的吞吐能力。

二、参数调优
默认情况下RocketMQ的broker的数据读写没有进行分离。
可以通过在broker.conf中将transientStorePoolEnable=true,开启读写分离。启用“读写”分离,消息发送时消息先追加到DirectByteBuffer(堆外内存)中,然后在异步刷盘机制下,会将DirectByteBuffer中的内容提交到PageCache,然后刷写到磁盘。消息拉取时,直接从PageCache中拉取,实现了读写分离,减轻了PageCaceh的压力,能从根本上解决该问题。
开启分离后,有一些风险,会增加数据丢失的可能性,如果Broker JVM进程异常退出,提交到PageCache中的消息是不会丢失的,但存在堆外内存(DirectByteBuffer)中但还未提交到PageCache中的这部分消息,将会丢失。但通常情况下,RocketMQ进程退出的可能性不大
开启读写分离后,有一些相关的参数也需要调整,比如提交消息时开启重入锁,增大发送的超时
broker.conf修改如下

useReentrantLockWhenPutMessage=true
osPageCacheBusyTimeOutMills=5000
waitTimeMillsInSendQueue=3000
transientStorePoolEnable=true
transientStorePoolSize=2

同时,需要注意transientStorePoolSize这个参数,这个是堆外缓存池大小,这个这个默认为5,配置成5需要占用5G空间,配置成2就占用2G空间,需要根据生产环境机器配置情况调整。同时,broker的JVM也需要作相应调整,保证有足够的堆外内存可用。

修改,runbroker.sh

JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=4g"

数据丢失也不一定是这种情况,要根据实际业务场景去判断。整个解决方式的流程图如下,看是下面哪一步出了问题,然后去解决

rocketmq springboot对应版本 rocketmq partition_java