Rocketmq 应用重启后重复消费消息问题(集群模式与广播模式)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangsht/article/details/84776906

Rocketmq 应用重启后出现重复消费的情况,查询相关资料后发现当客户端版本和服务端版本不同时,会出现重复消费的情况,但实际测试后发现,在版本有差异的情况下(客户端3.5.8版本,服务端4.2.0版本),采用集群模式消费,未出现重复消费的情况,采用广播模式时,会出现重复消费的情况。

Rocketmq 消费者分 集群模式 和 广播模式 两种方式,在消费者实例初试化时进行设置

// 集群模式
//consumer.setMessageModel(MessageModel.CLUSTERING);
//广播模式
consumer.setMessageModel(MessageModel.BROADCASTING);

设置集群模式时,在版本有差异和无差异的情况下,均未出现重复消费的情况(此情况与网上一些资料描述的情况不同

设置广播模式时,在版本有差异和无差异的情况下,均出现了重复消费的情况。

补充设置消费者实例名称:

 
            //设置消费实例名,在广播消费模式下有效,若未设置,则重启会重复消费
            consumer.setInstanceName("instanceName");
             //设置此种格式的实例名无效
//            consumer.setInstanceName("10.0.75.1192.168.50.36:19876;192.168.50.37:29876");

经测试,在版本无差异的情况下,没有出现重复消费的情况下,在版本有差异的情况下则依旧会重复消费。

有趣的是,设置实例名为带 ip类型的格式时,也会出现重复消费的情况,具体原因,还需详细分析

如下是完整代码:


import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere;
import com.alibaba.rocketmq.common.message.MessageExt;
import com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel;
import com.google.gson.Gson;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;

/**
 *
 */
@Component("addressIndexDataMQConsumer")
public class AddressIndexDataMQConsumer implements MessageListenerConcurrently {

    public static final Logger log = LoggerFactory.getLogger(AddressIndexDataMQConsumer.class);


    @Value("${spring.rocketmq.namesrvAddr}")
    private String namesrvAddr;

    private Gson gson = new Gson();

    private final DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("addressIndexDataMQConsumer");

    /**
     * 初始化
     *
     * @throws
     */
    @PostConstruct
    public void start() {
        try {
            log.info("MQ:启动消费者");

            consumer.setNamesrvAddr(namesrvAddr);
            // 从消息队列头开始消费
            consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
            // 集群模式
            //consumer.setMessageModel(MessageModel.CLUSTERING);
            //广播模式
            consumer.setMessageModel(MessageModel.BROADCASTING);
            //设置消费实例名,在广播消费模式下有效,若未设置,则重启会重复消费
            consumer.setInstanceName("instanceName");
             //设置此种格式的实例名无效
//            consumer.setInstanceName("10.0.75.1192.168.50.36:19876;192.168.50.37:29876");
            //VipChannel阿里内部使用版本才用,开源版本没有,默认为true,占用10909端口,此时虚拟机需要开放10909端口,否则会报 :connect to <:10909> failed异常,可以直接设置为false
            consumer.setVipChannelEnabled(false);
            // 订阅主题
            consumer.subscribe("AddressIndexData", "AddressIndexData");
            // 注册消息监听器
            consumer.registerMessageListener(this);
            // 启动消费端
            consumer.start();
        } catch (MQClientException e) {
            log.error("MQ:启动消费者失败:{}-{}", e.getResponseCode(), e.getErrorMessage());
            throw new RuntimeException(e.getMessage(), e);
        }

    }

    /**
     * 消费消息
     * @param msgs
     * @param context
     * @return
     */
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        MessageExt msg = msgs.get(0);
        log.error("====addressindexdata==== " + new String(msg.getBody()));
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }

    @PreDestroy
    public void stop() {
        if (consumer != null) {
            consumer.shutdown();
            log.error("MQ:关闭消费者");
        }
    }

    /**
     * 获取消费者实例名,采用当前ip与mq服务ip组合的方式  **实测发现,此格式的实例名不生效
     * @param namesrvAddr
     * @return
     */
    private static String getInstanceName(String namesrvAddr) {
        return getHostAddress() + namesrvAddr;
    }

    private static String getHostAddress(){
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }


}

 

 

 

展开阅读全文

消费消息:推模式

05-25

<div>n <span style="font-size:16px;"><span><span style="font-size:20px;color:#FF0000;"><strong><span>课程亮点:</span></strong></span></span></span> n</div>n<div style="font-size:16px;">n <span style="color:#424242;"><span style="background-color:#FFFAA5;">课程培训详细的笔记以及实例代码,让学员开始掌握RabbitMQ知识点</span></span> n</div>n<p style="font-size:16px;">n <span style="font-size:14px;"><span><span style="background-color:#FFFFFF;"><span style="color:#424242;"><br /></span></span></span></span> n</p>n<div>n <div>n <span style="font-size:16px;"><span><strong><span style="background-color:#FFFFFF;">课程内容:</span></strong></span></span> n </div>n <div>n  n <ol><li>n <span style="font-size:16px;color:#E53333;"><strong>第1章:RabbitMQ简介:消息中间件概念、RabbitMQ的安装、Java实现RabbitMq客户端调用</strong></span>n </li>n <li>n <span style="font-size:16px;color:#E53333;"><strong>第2章:RabbitMQ几个概念:生产者、消费者、Broken、交换器、路由键、绑定键、交换器类型</strong></span>n </li>n <li>n <span style="font-size:16px;color:#E53333;"><strong>第3章:RabbitMQ的几个API:连接、信道、交换器、队列、发送消息、消费消息</strong></span>n </li>n </ol></div>n</div>n<div style="font-size:16px;">n <span style="color:#FF0000;"><strong><span style="font-size:18px;">课程特色:</span></strong></span> n</div>n<div>n <ol><li>n 笔记RabbitMQ中间件 :用200多条笔记串连所有知识点,让学员从一点一滴积累,学习过程无压力n </li>n <li>n 笔记标题采用关键字标识法,帮助学员更加容易记住知识点n </li>n <li>n 笔记以超链接形式让知识点关联起来,形式知识体系n </li>n <li>n 采用先概念后实例再应用方式,知识点深入浅出n </li>n <li>n <strong>提供授课内容笔记作为课后复习以及工作备查工具</strong> n </li>n </ol></div>n<p>n <span style="font-size:16px;"><span><span style="color:#00B050;"><strong><strong><span style="font-size:18px;">部分图表(电脑PC端查看):</span></strong></strong></span></span></span> n</p>n<p>n <span style="font-size:16px;"><span><span style="color:#00B050;"><strong><strong><span style="font-size:18px;"><br /></span></strong></strong></span></span></span> n</p>

消费消息:拉模式

05-25

<div>n <span style="font-size:16px;"><span><span style="font-size:20px;color:#FF0000;"><strong><span>课程亮点:</span></strong></span></span></span> n</div>n<div style="font-size:16px;">n <span style="color:#424242;"><span style="background-color:#FFFAA5;">课程培训详细的笔记以及实例代码,让学员开始掌握RabbitMQ知识点</span></span> n</div>n<p style="font-size:16px;">n <span style="font-size:14px;"><span><span style="background-color:#FFFFFF;"><span style="color:#424242;"><br /></span></span></span></span> n</p>n<div>n <div>n <span style="font-size:16px;"><span><strong><span style="background-color:#FFFFFF;">课程内容:</span></strong></span></span> n </div>n <div>n  n <ol><li>n <span style="font-size:16px;color:#E53333;"><strong>第1章:RabbitMQ简介:消息中间件概念、RabbitMQ的安装、Java实现RabbitMq客户端调用</strong></span>n </li>n <li>n <span style="font-size:16px;color:#E53333;"><strong>第2章:RabbitMQ几个概念:生产者、消费者、Broken、交换器、路由键、绑定键、交换器类型</strong></span>n </li>n <li>n <span style="font-size:16px;color:#E53333;"><strong>第3章:RabbitMQ的几个API:连接、信道、交换器、队列、发送消息、消费消息</strong></span>n </li>n </ol></div>n</div>n<div style="font-size:16px;">n <span style="color:#FF0000;"><strong><span style="font-size:18px;">课程特色:</span></strong></span> n</div>n<div>n <ol><li>n 笔记RabbitMQ中间件 :用200多条笔记串连所有知识点,让学员从一点一滴积累,学习过程无压力n </li>n <li>n 笔记标题采用关键字标识法,帮助学员更加容易记住知识点n </li>n <li>n 笔记以超链接形式让知识点关联起来,形式知识体系n </li>n <li>n 采用先概念后实例再应用方式,知识点深入浅出n </li>n <li>n <strong>提供授课内容笔记作为课后复习以及工作备查工具</strong> n </li>n </ol></div>n<p>n <span style="font-size:16px;"><span><span style="color:#00B050;"><strong><strong><span style="font-size:18px;">部分图表(电脑PC端查看):</span></strong></strong></span></span></span> n</p>n<p>n <span style="font-size:16px;"><span><span style="color:#00B050;"><strong><strong><span style="font-size:18px;"><br /></span></strong></strong></span></span></span> n</p>

没有更多推荐了,返回首页