深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因( 三 )


 
而在消费者启动的时候会开启一个定时任务 , 默认是5s一次 , 会通过网络请求将内存中的每个Queue的消费进度offset发送给RocketMQ服务端 。

深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
由于是定时任务 , 所以就可能出现服务器一旦宕机 , 导致最新消费的offset没有成功告诉RocketMQ服务端的情况
此时 , 消费进度offset就丢了 , 那么消费者重启的时候只能从RocketMQ中获取到上一次提交的offset , 从这里开始消费 , 而不是最新的offset , 出现明明消费到了第8个消息 , RocketMQ却告诉他只消费到了第5个消息的情况 , 此时必然会导致消息又出现重复消费的情况 。
服务端持久化offset失败
上一节说到 , 消费者会有一个每隔5s钟的定时任务将每个队列的消费进度offset提交到RocketMQ服务端
当RocketMQ服务端接收到提交请求之后 , 会将这个消费进度offset保存到内存中
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
同时为了保证RocketMQ服务端重启消费进度不会丢失 , 也会开启一个定时任务 , 默认也是5s一次 , 将内存中的消费进度持久化到磁盘文件中
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
所以 , 整个消费进度offset的数据流转过程如下
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
当RocketMQ服务端重启之后 , 会从磁盘中读取文件的数据加载到内存中 。
跟消费者产生的问题一样 , 一旦RocketMQ发生宕机 , 那么offset就有可能丢失5s钟的数据 , RocketMQ服务端一旦重启 , 消费者从RocketMQ服务端获取到的消息消费进度就比实际消费的进度低 , 同样也会导致消息重复消费 。
主从同步offset失败
在RocketMQ的高可用模式中 , 有一种名叫主从同步的模式 , 当主节点挂了之后 , 从节点可以手动升级为主节点对外提供访问 , 保证高可用 。
在主从同步模式下 , 从节点默认每隔10s会向主节点发送请求 , 同步一些元数据 , 这些元数据就包括消费进度
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
当从节点获取到主节点的消费进度之后 , 会将主节点的消费进度设置到自己的内存中 , 同时也会持久化到磁盘 。
所以整个消费进度offset的数据的流转过程就会变成如下
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
同样 , 由于也是定时任务 , 那么一旦主节点挂了 , 从节点就会丢10s钟的消费进度 , 此时如果从节点升级为主节点对外提供访问 , 就会出现跟上面提到的一样的情况 , 消费者从这个新的主节点中拿到的消费进度比实际的低 , 自然而然就会重复消费消息 。
所以 , 总的来说 , 在消费进度数据流转的过程中 , 只要某个环节出现了问题 , 都有很有可能会导致消息重复消费 。
重平衡
先来讲一讲什么是重平衡 , 其实重平衡很好理解 , 我说一下你就明白了 。
前面说到 , 消费者是从队列中获取消息的
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图


推荐阅读