RocketMQ入门篇-------整合Springboot

写在前面

从安装到测试成功,花了好几天的时间。在网上也查了很多的资料。但是很多时候都是徒劳的。第一次学习MQ,想把这些天学到的东西总结一下。也很欢迎各位大神、大牛来评论。
首先,我们花点时间介绍一下RocketMQ的性能及一些角色。个人觉得这是很有必要的。其实,不管是什么MQ,他们都是MQ,只要是MQ,他都具有一下特点:

  • 削峰填谷(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题)
  • 系统解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死)
  • 提升性能(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统)
  • 蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测)
    而RocketMQ独有的特性有:
  • 支持结合rocketmq的多个系统之间数据最终一致性(多方事务,二方事务是前提)
  • 支持18个级别的延迟消息(rabbitmq和kafka不支持)
  • 支持指定次数和时间间隔的失败消息重发(kafka不支持,rabbitmq需要手动确认)
  • 支持consumer端tag过滤,减少不必要的网络传输(rabbitmq和kafka不支持)
  • 支持重复消费(rabbitmq不支持,kafka支持)

RocketMQ整体结构及特色

RocketMQ入门篇-------整合Springboot_第1张图片
如上图所示,整体可以分成4个角色,分别是:Producer,Consumer,Broker以及NameServer;

角色如下:

NameServer

可以理解为是消息队列的协调者,Broker向它注册路由信息,同时Client向其获取路由信息,如果使用过Zookeeper,就比较容易理解了,但是功能比Zookeeper弱;
NameServer本身是没有状态的,并且多个NameServer直接并没有通信,可以横向扩展多台,Broker会和每一台NameServer建立长连接;

Broker

Broker是RocketMQ的核心,提供了消息的接收,存储,拉取等功能,一般都需要保证Broker的高可用,所以会配置Broker Slave,当Master挂掉之后,Consumer然后可以消费Slave;
Broker分为Master和Slave,一个Master可以对应多个Slave,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave;

Producer

息队列的生产者,需要与NameServer建立连接,从NameServer获取Topic路由信息,并向提供Topic服务的Broker Master建立连接;Producer无状态.

Consumer

消息队列的消费者,同样与NameServer建立连接,从NameServer获取Topic路由信息,并向提供Topic服务的Broker Master,Slave建立连接;

Topic 和 Message Queue

在介绍完以上4个角色以后,还需要重点介绍一下上面提到的Topic和Message Queue;字面意思就是主题,用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息,为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个Message Queue,有点类似kafka的分区(Partition),这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个Message Queue读取消息;

跟其他的MQ相比,可能角色多了点,但是没有关系。这里我说明一点。前面两种角色不需要我们自己创建,开发者只需要自己创建后三者角色。
在申明一点:我们一定要提前搭建好RocketMQ的基本环境,如果你还不会搭建的,请点击这里;如果你搭建好了,先启动NameServer服务器,在启动Broker服务器,在运行相应的jar包。详细步骤上一篇文章都有。

整合RocketMQ基本上算是有两种方法

第一种 springboot提供了依赖

我们先看怎么整合的问题,至于问题,后面再说

Pom文件



    4.0.0
    com.tff
    springboot_rocketmq
    pom
    1.0-SNAPSHOT
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.2.RELEASE
        
    
    

        
        
            org.apache.rocketmq
            rocketmq-spring-boot-starter
            2.0.3
        

        
            org.springframework.boot
            spring-boot-starter-web
        
    

生产者角:

package com.tff.springbootrocketmq;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Producer{
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    
    public void sendMessage(){
        //参数1:topic  参数2:要发送的消息
        rocketMQTemplate.convertAndSend("hoppy","i love code");
        System.out.println("消息发送完成");
    }
}

消费者角色:

package com.tff.springbootrocketmq;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

#这个注解相当重要  参数1 topic  参数2  消息的组
@RocketMQMessageListener(topic = "hoppy",consumerGroup = "${rocketmq.producer.group}")
@Component
public class Consumer implements RocketMQListener {
    @Override
    public void onMessage(String s) {
        System.out.println("接收的消息:"+s);
    }
}

controller层

package com.tff.web;

import com.tff.springbootrocketmq.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.UnsupportedEncodingException;

@RestController
public class RocketMQController {

    @Autowired
    private Producer producer;  //采用springboot模板集成方式来整合

    @RequestMapping("/push")
    public String pushMsg() throws UnsupportedEncodingException {
        producer.sendMessage();
        return "ERROR";
    }
}

大家可以不写这一层,直接利用springboot的测试单元也可以
配置文件

# 安装RocketMQ的主机IP地址和端口
rocketmq.name-server=127.0.0.1:9876 
#发送消息的组
rocketmq.producer.group=group1

测试:
浏览器地址栏输入:http://localhost:8080/push
RocketMQ入门篇-------整合Springboot_第2张图片
我们可以看到,消息消费端已经接受到消息了。

打开RocketMQ的图形用户界面
RocketMQ入门篇-------整合Springboot_第3张图片
我们看到,已经可以看到我们的生产者了。
我们在来看一下“消息”菜单
RocketMQ入门篇-------整合Springboot_第4张图片
这些都是我们刚才发送的消息

这种方式有一定的局限性,Springboot在这方面做的不是很好。所以,我们在开发过程中经常使用第二种方式,开发者自己进行封装。

原始的API开发方式

Pom文件



    4.0.0

    com.tff
    rocketmq_test_demo
    1.0-SNAPSHOT
    
        
            org.apache.rocketmq
            rocketmq-client
            4.3.1
        
    

生产者:

import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.io.UnsupportedEncodingException;
public class Producer1 {
    public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException, UnsupportedEncodingException {
        //创建默认 DefaultMQProducer
        DefaultMQProducer producer = new DefaultMQProducer("demo1");
        //设置nameServer地址
        producer.setNamesrvAddr("127.0.0.1:9876");
        //开启 DefaultMQProducer
        producer.start();
        //创建消息
        Message message = new Message("Hello_World","jsj","二叉树、平衡二叉树、图、有向图、无向图、线性结构等".getBytes(RemotingHelper.DEFAULT_CHARSET));
        //发送消息
        SendResult result = producer.send(message);
        System.out.println(result);
        //关闭
        producer.shutdown();
    }
}

消息消费者

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
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.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;

import java.io.UnsupportedEncodingException;
import java.util.List;

public class Consumer1 {
    public static void main(String[] args) throws MQClientException {

        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("demo1");
        consumer.setNamesrvAddr("127.0.0.1:9876");
        //从那个主题中获取  第二个参数是怎么过滤,*代表所有,也可以是tag
        consumer.subscribe("Hello_World","*");
        //创建消息监听器
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            public ConsumeConcurrentlyStatus consumeMessage(List list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                //迭代消息
                for(MessageExt msg : list){
                    try {
                        //获取主题
                        String topic = msg.getTopic();
                        //获取tag
                        String tag = msg.getTags();
                        //获取消息
                        byte[] mes = msg.getBody();
                        String message = new String(mes,RemotingHelper.DEFAULT_CHARSET);
                        System.out.println("接收到消息==: 消息主题:"+topic+", tag: "+tag+", 内容:"+message);
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        //消息接收失败,重试机制
                        return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                    }
                }
                //消息接收成功,返回状态
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        //开启consumer
        consumer.start();
    }

}

这里就不具体解释代码的含义了,都有注释
这里只需要补充一点;也是特别重要的一点。
就是我们下载的RocketMQ的版本要是我们导入的依赖版本一致,否则,会出现bug
RocketMQ入门篇-------整合Springboot_第5张图片例如,我这个是4.3.1版本
那么,我的maven依赖也因该是这个版本

测试:
先启动生产者:
RocketMQ入门篇-------整合Springboot_第6张图片
已经发送成功

再启动消费者:
RocketMQ入门篇-------整合Springboot_第7张图片
基本上就是这两种方式了,一般开发过程中,选用后者的比较多。大家在开发过程中,可以自己封住,这里只是为了测试,我没有进行封装。

另外,附一下RocketMQ的官网地址;很有用的,因为是阿里开发的,所以中国人看起来还是挺可以的。
官网地址:http://rocketmq.apache.org/docs/simple-example/

欢迎大家批评指正!如果你喜欢的话,请留下您宝贵的建议……

你可能感兴趣的:(MQ)