RocketMq什么时候会重复消费

1.消费者负载均衡

当我们的Consumer定义为BroadCast广播模式的话,每个ConsumerGroup下的consumer都会获得全量消息。此时拉取消息时不同的节点会得到相同的消息。

而cluster集群模式下,负载均衡策略(RebalanceImpl)会将多个ConsumerQueue平均分配给ConsumerGroup下的消费者实例(默认平均分配策略),不会出现同一个消费者组中有两个或以上的consumer实例消费同一个队列。比如:
consumer1:queue1,queue2
consumer2:queue3,queue4
这样同一个consumerGroup下不同的consumer消费各自的队列,就减少了重复拉取的危险

2.使用DefaultMqPullConsumer

Pull模式的Consumer,拉取完消息后的后续处理都需要业务方进行实现,
同时消费完了,也没有一个ACK去告诉Broker这些消息已经被消费了。
这是如果两个节点同时拉取就重复掉了。
这种情况比较少。生成环境中一般使用DefaultMqPushConsumer。因为DefaultMqPushConsumer编码难度小,是基于DefaultMqPullConsumer的一层封装。而且根据消费的结果返回一个ACK消息。自身的实现上不会消费已经消费过的消息

3.消费失败后返回RECONSUME_LATER进行容错

一般情况下如果出现异常后,对异常处理的结果是过段时间重新消费一次
比如

  defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
            int a=1;
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.println(msgs.size());
                try {
                    System.out.println(new String(msgs.get(0).getBody(),"UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        defaultMQPushConsumer.start();

异常捕获时返回的ACK为RECONSUME_LATER,则会在一段时间后进行重试。

4.Producer发送时,出现网络问题

如果producer发送了消息,此时broker已经同步刷盘或异步刷盘成功了。但是返回ACK时出现网络问题。此时producer会进行重发,这是broker上就会出现两条相同的消息

源码如下:
RocketMq什么时候会重复消费_第1张图片

5.Consumer节点重启

Consumer所在节点,消费完后还未来得及返回处理结果,此时服务宕机或重启。此时已经消费1次。
随后运维重新启动节点,会再次消费一次。总共出现两次消费重复。

6.Consumer消费时间超时

如果Consumer消费完后迟迟没有返回结果,此时会触发一次重新消费
经过测试,最多也只重新消费1次

总结:
生产环境下情况复杂,mq是无法避免消息重复的。通过业务上进行幂等性校验。比如通过关系型数据库的主键进行幂等性校验。或者短期业务使用redis实现的布隆过滤器,bitmap进行短期校验。

你可能感兴趣的:(rocketMq)