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


 
在RocketMQ中 , 有个消费者组的概念 , 一个消费者组中可以有多个消费者 , 不同消费者组之间消费消息是互不干扰的 , 所以前面提到的消费者其实都在消费组下

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

文章插图
 
在同一个消费者组中 , 消息消费有两种模式:
 
  • 集群消费模式
  • 广播消费模式
 
由于RocketMQ默认是集群消费模式 , 并且绝大多数业务场景都是使用集群消费模式 , 所以这里就不讨论广播消费模式了 , 感兴趣的同学可以看看RocketMQ消息短暂而又精彩的一生 这篇文章 。
【深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因】集群消费模式是指同一条消息只能被这个消费者组消费一次 , 这就叫集群消费 。
并且前面提到提交消费进度给RocketMQ服务端的情况只会集群消费模式下才会有 , 在广播消费模式不会提给到RocketMQ服务端 , 仅仅持久化到本地磁盘
同时前面说的消费者提交消费进度真正提交的是消费者组对于这个Queue的消费进度 , 而不是指具体的某个消费者对于Queue消费进度 。
虽然说这里将前面提到的一些含义更深一步 , 但是并不妨碍前面的理解 。
集群消费的实现就是将队列按照一定的算法分配给消费者 , 默认是按照平均分配的 。
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
如图所示 , 假设某个topic有4个Queue , 有个消费者组订阅了这个topic , 这个消费者组有两个消费者1和消费者2 , 此时每个消费者就可以被分配两个队列 , 这样就能保证消息正常情况下只会被消费一次 。如果只有一个消费者 , 那么这个消费者就会消费所有队列 , 很好理解 。
接着后面又启动了一个消费者3 , 此时为了保证刚上线的消费者3能够消费消息 , 就要进行重平衡操作 , 重新分配每个消费者消费的队列 。
在重平衡之后就可能会出现下面这种情况
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
如上图 , 原本被消费者2消费的Queue4被分配给消费者3 , 此时消费者3就能消费到消息了 , 这就是重平衡 。
除了新增消费者会导致重平衡之外 , 消费者数量减少 , 队列的数量增加或者减少都会触发重平衡 。
在了解了重平衡概念之后 , 接下来分析一下为什么重平衡会导致消息的重复消费 。
假设在进行重平衡时 , 还未重平衡完之前 , 消费者2此时还是会按照上面第二节提到的消费消息的逻辑来消费Queue4的消息
当消费者2已经重平衡完成了 , 发现Queue4自己已经不能消费了 , 那么此时就会把这个Queue4设置为dropped , 就是丢弃的意思
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
但是由于重平衡进行时消费者2仍然在消费Queue4的消息 , 但是当消费完之后 , 发现队列被设置成dropped , 那么此时被消费者2消费消息的offset就不会被提交 , 原因如下代码
深扒RocketMQ源码之后,我找出了RocketMQ消息重复消费的7种原因

文章插图
 
这段代码前面已经出现过 , 一旦dropped被设置成true , 这个if条件就通不过 , 消费进度就不会被提交 。
成功消费消息了 , 但是却不提交消费进度 , 这就非常坑了 。。
于是当消费者3开始消费Queue4的消息的时候 , 他就会问问RocketMQ服务端 , 我消费者3所在的消费者组对于Queue4这个队列消费到哪了 , 我接着消费就行了 。


推荐阅读