Springboot 集成RocketMQ4.4.0 遇到的問題 以及我的解決方法

RocketMQ4.4.0

最近在做一個小項目的過程中使用了MQ消息隊列。

選擇哪種MQ我也糾結了很久,最後選擇了阿里的開源項目RocketMQ,不過現在已經貢獻給Apache社區了。

但是在使用的過程中也是踩了很多坑的,下面我會把我遇到的一些問題羅列出來。

  1. No route info of this topic
  2. 本地連接服務器連接超時,連接失敗
  3. topic可以創建,可以發送消息,但是沒有被消費
  4. 一個consumer訂閱多個topic應該怎麼設置。

 

問題多多,但是都是環境的問題,代碼基本上都是一樣的,所以出了問題首先檢查的就是你的環境是否連接正確。

 

下面我把我的代碼環境配置羅列一下:

  • 消費者Producer

 

import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * rocketMq 生產者包裝
 *
 * @author zhengjf
 * @version 1.0
 * @date 2019/3/5
 */
@Service
@Slf4j
public class MqProducerService {

    @Value("${rocketmq.name-server}")
    private String namesrvAddr;

    @Value("${rocketmq.producer.group}")
    private String producerGroup;

    private DefaultMQProducer producer;

    /**
     * DefaultMQProducer 普通消息生產者對象創建
     *
     * @return void
     * @author zhengjf
     * @date 2019/3/5
     */
    @PostConstruct
    public void initProducer() {
        producer = new DefaultMQProducer(producerGroup);
        producer.setNamesrvAddr(namesrvAddr);
        producer.setRetryTimesWhenSendFailed(3);
        producer.setVipChannelEnabled(false);
        try {
            producer.start();
            log.info("[Producer 已啓動]");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 普通消息  同步發送消息,只要不拋異常就是成功
     *
     * @param topic, tags, msg
     * @return java.lang.String
     * @author zhengjf
     * @date 2019/3/5
     */
    public SendResult send(String topic, String tags, String msg) throws Exception {
        Message message = new Message(
                // Message所屬的Topic
                topic,
                // Message Tag,可理解爲mail中的標籤,對消息進行再歸類,方便Consumer指定過濾條件在MQ服務器過濾
                tags,
                // Message Body,任何二進制形式的數據,MQ不做任何干預,需要Producer與Consumer協商好一致的序列化和反序列化方式
                msg.getBytes(RemotingHelper.DEFAULT_CHARSET));

        SendResult result = producer.send(message);
        log.info("發送消息後返回:" + result.toString());
        return result;
    }

    /**
     * 延時發送
     * RocketMQ目前指定的延時時間間隔有DelayTimeLevel 1s,5s,10s,30s,1m,2m,3m,4m,5m,6m,7m,8m,9m,10m,20m,30m,1h,2h,用等級來表示時間間隔。
     *
     * @param topic, tags, msg, delayTimeLevel 時間等級(30分鐘是16)
     * @return org.apache.rocketmq.client.producer.SendResult
     * @author zhengjf
     * @date 2019/3/5
     */
    public SendResult sendDelayTime(String topic, String tags, String msg, int delayTimeLevel) throws Exception {
        Message message = new Message(
                // Message所屬的Topic
                topic,
                // Message Tag,可理解爲mail中的標籤,對消息進行再歸類,方便Consumer指定過濾條件在MQ服務器過濾
                tags,
                // Message Body,任何二進制形式的數據,MQ不做任何干預,需要Producer與Consumer協商好一致的序列化和反序列化方式
                msg.getBytes(RemotingHelper.DEFAULT_CHARSET));

        message.setDelayTimeLevel(delayTimeLevel);
        SendResult result = producer.send(message);
        log.info("發送消息後返回:" + result.toString());
        return result;
    }


    /**
     * 這裏用到了這個mq的異步處理,類似ajax,可以得到發送到mq的情況,並做相應的處理
     * 不過要注意的是這個是異步的
     *
     * @param topic, tags, msg
     * @return void
     * @author zhengjf
     * @date 2019/3/5
     */
    public String sendAsync(String topic, String tags, String msg) throws Exception {
        Message message = new Message(
                // Message所屬的Topic
                topic,
                // Message Tag,可理解爲Gmail中的標籤,對消息進行再歸類,方便Consumer指定過濾條件在MQ服務器過濾
                tags,
                // Message Body,任何二進制形式的數據,MQ不做任何干預,需要Producer與Consumer協商好一致的序列化和反序列化方式
                msg.getBytes(RemotingHelper.DEFAULT_CHARSET));
        producer.send(message, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                log.info("傳輸成功。" + sendResult.toString());
            }

            @Override
            public void onException(Throwable e) {
                log.error("傳輸失敗", e);
            }
        });
        // 在callback返回之前。
        log.info("send message async." + message.toString());
        return message.toString();
    }

    @PreDestroy
    public void shutDownProducer() {
        if (producer != null) {
            producer.shutdown();
        }
    }
}

 

  • 消費者監聽
import com.mjs.common.common.OrderStatusEnum;
import com.mjs.mojisishop.entity.OrderInfo;
import com.mjs.mojisishop.mapper.OrderInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 監聽MQ的主題消息,進行消費。可以監聽多個
 *
 * @author zhengjf
 * @version 1.0
 * @date 2019/3/5
 */
@Component
@Slf4j
public class ConsumerListener {

    @Value("${rocketmq.name-server}")
    private String namesrvAddr;

    @Value("${rocketmq.consumer.group}")
    private String consumerGroup;

    @Autowired
    OrderInfoMapper orderInfoMapper;

    @PostConstruct
    public void defaultMQPushConsumer() throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
        consumer.setNamesrvAddr(namesrvAddr);
        consumer.subscribe("order", "pay");

        // 如果是第一次啓動,從隊列頭部開始消費
        // 如果不是第一次啓動,從上次消費的位置繼續消費
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        // 開啓內部類實現監聽
        consumer.registerMessageListener((MessageListenerConcurrently) (list, context) -> {
            try {
                for (MessageExt messageExt : list) {
                    String messageBody = new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET);
                    log.info("消費者受到消息:[Consumer] msgID(" + messageExt.getMsgId() + ") msgBody : " + messageBody);
                 
                }
            } catch (Exception e) {
                e.printStackTrace();
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });


        consumer.subscribe("test222", "pay");
        consumer.registerMessageListener((MessageListenerConcurrently) (list, context) -> {
            try {
                for (MessageExt messageExt : list) {
                    String messageBody = new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET);
                    log.info("消費者受到消息:[Consumer] msgID(" + messageExt.getMsgId() + ") msgBody : " + messageBody);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });


        consumer.start();
        log.info("[Consumer 已啓動]");
    }
}

 

就是這麼簡單的兩個文件就可以了。

  • pom

my   mq.version 4.4.0

        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-client</artifactId>
            <version>${mq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-common</artifactId>
            <version>${mq.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-remoting</artifactId>
            <version>${mq.version}</version>
        </dependency>

 

代碼說完了就說以下我的環境配置。

首先我的mq放在阿里雲服務器上

cd  /home/tools/rocketmq-all-4.4.0-bin-release

關閉namesrv服務:

sh bin/mqshutdown namesrv


關閉broker服務 :

sh bin/mqshutdown broker


啓動namesrv服務:

nohup sh bin/mqnamesrv & 

啓動broker服務:公網ip
nohup sh bin/mqbroker -c conf/broker.conf & 

我的broker.conf  內容有修改,所以上面啓動的時候沒有指定nameserver地址

在默認的配置下面添加兩項

公網ip啊。要不然本地的服務就連接不上mq服務器,沒辦法發送消費消息

#nameServer地址,分號分割
namesrvAddr = 57.111.156.132:9876
brokerIP1 = 57.111.156.132

還有一個要注意的就是如果你本地連接雲服務器的mq,要把本地的防火牆還有云服務的防火牆關了。

 

如果要查看mq的日誌,一般都放在/root/logs/rocketmqlogs中,這是我的日誌路徑,也可能不同用戶不同地址

有broker.log、namesrv.log。。。。。。。

有問題也可以找我交流一下

[email protected]

471639492

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章