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