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

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 "";
    }


}

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值