最新 RocketMQ 入門教程

一. RocketMQ簡介

1.1 功能作用優點

  • RocketMQ作爲一款純java 分佈式 隊列模型的開源消息中間件,支持事務消息 順序消息 批量消息 定時消息 消息回溯等功能

  • 支持發佈/訂閱(Pub/Sub)和點對點(P2P)消息模型

  • 在一個隊列中可靠的先進先出(FIFO)和嚴格的順序傳遞 (RocketMQ可以保證嚴格的消息順序,而ActiveMQ無法保證)

  • 支持拉(pull)和推(push)兩種消息模式 (Push好理解,比如在消費者端設置Listener回調;而Pull,控制權在於應用,即應用需要主動的調用拉消息方法從Broker獲取消息,這裏面存在一個消費位置記錄的問題(如果不記錄,會導致消息重複消費) )

  • 單一隊列百萬消息的堆積能力 (RocketMQ提供億級消息的堆積能力,這不是重點,重點是堆積了億級的消息後,依然保持寫入低延遲)

  • 支持多種消息協議,如JMS,MQTT等

  • 分佈式高可用的部署架構,滿足至少一次消息傳遞語義(RocketMQ原生就是支持分佈式的,而ActiveMQ原生存在單點性)

  • 提供docker鏡像用於隔離測試和雲集羣部署

  • 提供配置、指標和監控等功能豐富的Dashboard

1.2 圖示

在這裏插入圖片描述

1.3 基本概念

  • Producer:消息生產者
  • Producer Group:消息生產者組,發送同類消息的一個消息生產組
  • Consumer:消費者
  • Consumer Group:消費同個消息的多個實例
  • Tag:標籤,子主題(二級分類),用於區分同一個主題下的不同業務的消息
  • Topic:主題
  • Message:消息
  • Broker:MQ程序,接收生產的消息,提供給消費者消費的程序
  • Name Server:給生產和消費者提供路由信息,提供輕量級的服務發現和路由

二. 下載安裝與配置

環境:

  • Windows 10
  • Java :jdk1.8.0_191
  • Apache Maven 3.6.1

1. 下載安裝

2. RocketMQ 配置

2.1 配置環境變量

點擊新建
這裏給出變量名:ROCKETMQ_HOME
在這裏插入圖片描述

2.2 本地部署

2.2.1 啓動RocketMQ
  1. 進入RocketMQ 的bin目錄–啓動mq–如下圖 啓動命令是: start mqnamesrv.cmd
    在這裏插入圖片描述
    執行上面命令後如果報錯:找不到或無法加載主類,有兩種情況:
    • rocketmq解壓路徑有空格,放入非中文沒有空格的路徑
    • Java 的環境變量有空格,把jdk的地址複製放入非中文沒有空格的路徑並且修改環境變量
      注意jdk的版本最好是JDK 8 或者 JDK 9;版本太高會報錯
  2. 出現這個說明啓動成功,注意不要關閉窗口
    在這裏插入圖片描述
2.2.2 啓動Broker程序
  1. 和上面方法一樣:cmd創建進入mq的bin目錄–執行命令:
    start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true
    如果報錯:
    在這裏插入圖片描述
  2. 解決辦法:打開runbroker.cmd,然後將 %CLASSPATH% 加上英文雙引號 保存並重新執行start語句
    在這裏插入圖片描述
  3. 啓動成功標誌
    這個窗口不要關閉
    在這裏插入圖片描述
2.2.3 部署RocketMQ插件
  1. 下載地址

  2. 文件配置
    下載完畢解壓後進入路徑:D:\RocketMQ-Externals\rocketmq-console\src\main\resources 配置application.properties文件
    在這裏插入圖片描述

  3. 執行打包操作
    進入 D:\RocketMQ-Externals\rocketmq-console 路徑,在地址欄直接 cmd 回車執行:
    mvn clean package -Dmaven.test.skip=true
    完成打包操作,此過程會聯網下載資源

  4. 啓動
    打包完成後會生成 target 文件夾
    cmd 進入 target:D:\RocketMQ-Externals\rocketmq-console\target
    執行:java -jar rocketmq-console-ng-1.0.1.jar

  5. 測試運行
    localhost:8088
    在這裏插入圖片描述

三. springboot整合RocketMQ

3.1 創建spring boot項目

詳細見博客:https://blog.csdn.net/weixin_43330884/article/details/104942624

3.2 配置pom.xml文件

		<properties>
        	<java.version>1.8</java.version>
        	<rocketmq.version>4.7.0</rocketmq.version>
    	</properties>
		
		<!--rocketMQ的jar包依賴-->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-client</artifactId>
            <version>${rocketmq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-common</artifactId>
            <version>${rocketmq.version}</version>
        </dependency>

3.3 配置 application.properties


# 消費者的組名
apache.rocketmq.consumer.PushConsumer=orderConsumer
# 生產者的組名
apache.rocketmq.producer.producerGroup=Producer
# NameServer地址
apache.rocketmq.namesrvAddr=127.0.0.1:9876

3.4 創建生產者和消費者

1.生產者:ProducerMsg.java

package cn.hp.springboot_day08_01.jms;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 生產者 --- 用戶產生消息
 * @author hp
 * @date 2020/03/27
 */
@Component
public class ProducerMsg {
    /**
     * 生成者組
     */
    @Value("${apache.rocketmq.producer.producerGroup}")
    private String  producerGroup;

    /**
     * 從配置文件讀取 nameserver
     */
    @Value("${apache.rocketmq.namesrvAddr}")
    private String namesrvAddr;


    /**
     * 默認生產者
     */
    private DefaultMQProducer producer;

    /**
     * 提供get方法,讓外部調用
     * @return
     */
    public DefaultMQProducer getProducer() {
        return producer;
    }

    /**
     * @PostConstruct
     * 會在servlet初始化時執行,只執行1次
     * 作用:讓當前方法在構造函數 之後,在init方法之前執行
     */
    @PostConstruct
    public  void defaultMQProducer(){
        //1. 創建一個默認的生產者對象--- 作用用於生成消息
        producer = new DefaultMQProducer(producerGroup);
        //2. 綁定生產者和 nameserver ,就是建立 和broker程序的關係
        producer.setNamesrvAddr(namesrvAddr);
        //3. 發送消息
        try {
            producer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }
}

2.消費者:ConsumerMsg.java

package cn.hp.springboot_day08_01.jms;

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.client.exception.MQClientException;
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.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 消息的 消費者
 * @author hp
 * @date 2020/03/27
 */
@Component
public class ConsumerMsg {

    /**
     * 讀取配置文件的 消費者
     */
    @Value("${apache.rocketmq.consumer.PushConsumer}")
    private String consumerGroup;

    /**
     * 從配置文件讀取 nameserver
     */
    @Value("${apache.rocketmq.namesrvAddr}")
    private String namesrvAddr;

    /**
     * 提供一個空的構造器
     */
    public ConsumerMsg() {
    }

    /**
     * 提供默認的消費者
     */
    @PostConstruct
    public  void defaultMqConsumer() throws MQClientException {
        //1.指定消費者 所消費的主題(隊列)和tag(2及標籤,用於過濾消息)
        //從消費者組拿到1個消費者
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
        //說明:如果要消費所有 tag,用通配符*代替所有tag
        consumer.subscribe("orderTopic","*");
        //2.指定消費的策略 (從所有的消息開頭位置執行,還是從消息尾部執行)指定消費的順序
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        //TODO ....
        //註冊消息監聽器,用的lambda
        consumer.registerMessageListener((MessageListenerConcurrently) (list, context) -> {
            try {
                for (MessageExt messageExt : list) {
                    System.out.println("messageExt: " + messageExt);//輸出消息內容
                    String messageBody = new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET);//讀取遠程配置的編碼爲utf-8
                    System.out.println("消費響應:msgId : " + messageExt.getMsgId() + ",  msgBody : " + messageBody);//輸出消息內容
                }
            } catch (Exception e) {
                e.printStackTrace();
                return ConsumeConcurrentlyStatus.RECONSUME_LATER; //稍後再試
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; //消費成功
        });

        //3. 開啓監聽 消費消息
        consumer.start();
    }
}

3.4 創建controller運行測試

OrderController.java

package cn.hp.springboot_day08_01.controller;

import cn.hp.springboot_day08_01.jms.ProducerMsg;
import cn.hp.springboot_day08_01.utils.JsonData;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author hp
 * @date 2020/03/27
 */

@RestController
@RequestMapping("/api")
public class OrderController {

    @Autowired
    private ProducerMsg producerMsg;

    /**
     * @param msg   發送的消息
     * @param tag   二級標籤
     * @return
     */
    @RequestMapping("/order")
    public Object order(String msg,String tag) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        //1.創建消息載體對象 Massage
        Message message = new Message("orderTopic",tag,msg.getBytes());
        //2.通過注入的 消息提供者對象發送消息
        SendResult send = producerMsg.getProducer().send(message);
        System.out.println("消息ID:"+send.getMsgId()+"  消息發送狀態:"+send.getSendStatus());
        return JsonData.buildSuccess();
    }
}

小工具JsonData.java:https://blog.csdn.net/weixin_43330884/article/details/105142483
測試:http://localhost:8080/api/order?msg=支付成功&tag=pay
在這裏插入圖片描述
在這裏插入圖片描述

四. Closing

一個簡單的案例應用,對於RocketMQ的學習不止於應用,更應於底層原理的探索。底層原理的探索也有助於提高對RocketMQ的整體理解與問題的定位,對適用場景的技術選型才更有把握。限於筆者的才疏學淺,對本文內容可能還有理解不到位的地方,如有闡述不合理之處還望留言一起探討!

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