最新 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

    扫描二维码关注公众号,回复: 11065248 查看本文章

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的整体理解与问题的定位,对适用场景的技术选型才更有把握。限于笔者的才疏学浅,对本文内容可能还有理解不到位的地方,如有阐述不合理之处还望留言一起探讨!

发布了70 篇原创文章 · 获赞 114 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43330884/article/details/105139017