SpringBoot进阶(七)整合RocketMQ

·  阅读 391

RocketMQ是阿里出的一个纯java的消息队列框架,其它的还有Kafka,Rabbitmq等,网上也有很多他们的对比,优缺点一目了然,国内可能RocketMQ使用居多,因为它抗住了全球最大的流量洪峰双十一,而且运行稳定!

GitHub:github.com/baiyuliang/…

下图为引用网上关于三者的对比情况图:

在这里插入图片描述

关于MQ的作用这里也不再讲了,自行Baidu,你会了解更多!如果你是安卓开发同学,那你就把他理解成EventBus吧,哈哈!

使用Docker安装RocketMQ:

你可以不使用docker,直接安装到linux服务器:Linux部署RocketMq,当然,这会相对麻烦一点!

首先,打开Xftp 6软件连接Linux服务器,在usr/local或者其它文件夹下,创建mq文件夹,再在mq文件夹下创建conf和data两个文件夹:

在这里插入图片描述

在conf文件夹下新建broker.conf文件,并编辑内容一下内容后保存:

brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
brokerIP1 = 39.xxx.x.xx
复制代码

brokerIP1为你本机的外网地址!

准备就绪后,开始安装: 1.下载: docker pull rocketmqinc/rocketmq 2.启动rocketmq: docker run -d -p 9876:9876 -v /usr/local/mq/data/namesrv/logs:/root/logs -v /usr/local/mq/data/namesrv/store:/root/store --name rmqnamesrv -e "MAX_POSSIBLE_HEAP=100000000" rocketmqinc/rocketmq sh mqnamesrv 3.启动broker: docker run -d -p 10911:10911 -p 10909:10909 -v /usr/local/mq/data/broker/logs:/root/logs -v /usr/local/mq/data/broker/store:/root/store -v /usr/local/mq/conf/broker.conf:/opt/rocketmq/conf/broker.conf --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker autoCreateTopicEnable=true -c /opt/rocketmq/conf/broker.conf 4.安装控制台: docker pull styletang/rocketmq-console-ng 7.启动控制台: docker run -e "JAVA_OPTS=-Drocketmq.config.namesrvAddr=39.xxx.x.xx:9876 -Drocketmq.config.isVIPChannel=false" -p 8082:8080 -t styletang/rocketmq-console-ng

注意自己的外网ip地址不要写错,如果你更改了默认的端口映射,那么要注意你的端口保持一致!

浏览器打开:39.xxx.x.xx/8082

在这里插入图片描述

你可以在右侧选择中文语言,但到这里并不算成功,点击Cluster/集群:

在这里插入图片描述

出现broker-a,即你在broker.conf文件内声明的brokerName时,表明你的RockerMQ完全安装成功了!

整合进项目测试:

pom.xml引入:

<!--消息框架rocketmq-->
 <dependency>
     <groupId>org.apache.rocketmq</groupId>
     <artifactId>rocketmq-client</artifactId>
     <version>4.7.1</version>
 </dependency>
复制代码

application.propertites中配置:

spring.application.name=springboottest
#配置项目根路径
server.servlet.context-path=/byl
spring.thymeleaf.cache=false
####RocketMQ相关配置
###producer
#该应用是否启用生产者
rocketmq.producer.isOnOff=on
#发送同一类消息的设置为同一个group
rocketmq.producer.groupName=${spring.application.name}
#mq的nameserver地址
rocketmq.producer.namesrvAddr=39.xxx.x.xx:9876
#主题
rocketmq.producer.topics=MyTopic;
#消息最大长度 默认1024*128(128M)
rocketmq.producer.maxMessageSize=131027
#发送消息超时时间,默认10000
rocketmq.producer.sendMsgTimeout=10000
#发送消息失败重试次数,默认2
rocketmq.producer.retryTimesWhenSendFailed=2
###consumer
##该应用是否启用消费者
rocketmq.consumer.isOnOff=on
rocketmq.consumer.groupName=${spring.application.name}
#mq的nameserver地址
rocketmq.consumer.namesrvAddr=39.xxx.x.xx:9876
#该消费者订阅的主题
rocketmq.consumer.topics=MyTopic;
rocketmq.consumer.consumeThreadMin=20
rocketmq.consumer.consumeThreadMax=64
#设置一次消费消息的条数,默认为1条
rocketmq.consumer.consumeMessageBatchMaxSize=1
复制代码

rocketmq的三大件:Producer,Consumer,MessageListener,分别进行配置:

在这里插入图片描述

MQProducerConfig:

package com.byl.springboottest.rocket;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 消息生产者配置
 */
@Configuration
public class MQProducerConfig {

    @Value("${rocketmq.producer.groupName}")
    private String groupName;
    @Value("${rocketmq.producer.namesrvAddr}")
    private String namesrvAddr;
    @Value("${rocketmq.producer.maxMessageSize}")
    private Integer maxMessageSize;
    @Value("${rocketmq.producer.sendMsgTimeout}")
    private Integer sendMsgTimeout;
    @Value("${rocketmq.producer.retryTimesWhenSendFailed}")
    private Integer retryTimesWhenSendFailed;

    @Bean
    public DefaultMQProducer defaultMQProducer() {
        DefaultMQProducer producer = new DefaultMQProducer(this.groupName);
        producer.setNamesrvAddr(this.namesrvAddr);
        producer.setMaxMessageSize(this.maxMessageSize);
        producer.setSendMsgTimeout(this.sendMsgTimeout);
        producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
        try {
            producer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
        return producer;
    }
}

复制代码

MQConsumerConfig:

package com.byl.springboottest.rocket;


import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;


/**
 * 消费者配置
 */
@Configuration
public class MQConsumerConfig {
    @Value("${rocketmq.consumer.namesrvAddr}")
    private String namesrvAddr;
    @Value("${rocketmq.consumer.groupName}")
    private String groupName;
    @Value("${rocketmq.consumer.consumeThreadMin}")
    private int consumeThreadMin;
    @Value("${rocketmq.consumer.consumeThreadMax}")
    private int consumeThreadMax;
    @Value("${rocketmq.consumer.topics}")
    private String topics;
    @Value("${rocketmq.consumer.consumeMessageBatchMaxSize}")
    private int consumeMessageBatchMaxSize;

    @Resource
    private MQMsgListener mqMsgListener;

    @Bean
    public DefaultMQPushConsumer defaultMQPushConsumer() {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
        consumer.setNamesrvAddr(namesrvAddr);
        consumer.setConsumeThreadMin(consumeThreadMin);
        consumer.setConsumeThreadMax(consumeThreadMax);
        consumer.registerMessageListener(mqMsgListener);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        // consumer.setMessageModel(MessageModel.CLUSTERING);
        consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
        try {
            consumer.subscribe(topics, "MyTag");
            consumer.start();
        } catch (MQClientException e) {
        }
        return consumer;
    }
}
复制代码

MQMsgListener:

package com.byl.springboottest.rocket;

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.common.message.MessageExt;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 消息接收监听
 */
@Component
public class MQMsgListener implements MessageListenerConcurrently {

    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        if (msgs == null || msgs.size() == 0) {
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        MessageExt messageExt = msgs.get(0);
        System.out.println("接受到的消息为:" + messageExt.toString());
        if (messageExt.getTopic().equals("你的Topic")) {
            if (messageExt.getTags().equals("你的Tag")) {
                //判断该消息是否重复消费(RocketMQ不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重)
                //获取该消息重试次数
                int reconsume = messageExt.getReconsumeTimes();
                if (reconsume == 3) {//消息已经重试了3次,如果不需要再次消费,则返回成功
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
                //处理对应的业务逻辑

            }
        }
        // 如果没有return success ,consumer会重新消费该消息,直到return success
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }

}
复制代码

打开SpringboottestApplicationTests测试:

    @Resource
    DefaultMQProducer defaultMQProducer;

    @Test
    void testSendRocketMq() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        String msg = "rocketmq发送查询消息:查询成功";
        Message sendMsg = new Message("MyTopic", "MyTag", msg.getBytes());
        //默认3秒超时
        SendResult sendResult = defaultMQProducer.send(sendMsg);
        SendStatus sendStatus = sendResult.getSendStatus();
        System.out.println("消息发送响应信息状态:" + sendStatus);
        System.out.println("消息发送响应信息:" + sendResult.toString());
    }
复制代码

运行testSendRocketMq方法:

在这里插入图片描述

具体返回内容:

SendResult [sendStatus=SEND_OK, msgId=C0A801184D2818B4AAC27A4996310000, offsetMsgId=2769096000002A9F0000000000000347, messageQueue=MessageQueue [topic=ConsumerTopic, brokerName=broker-a, queueId=2], queueOffset=0]
复制代码

打开rocketmq控制台:

在这里插入图片描述

在这里插入图片描述

注意,经测试,在消费者订阅主题时:

subscribe(String topic, String subExpression)
复制代码

第二个参数,也就是发送消息时设置的Tag,必须指定,如:

consumer.subscribe("MyTopic", "MyTag");
复制代码

consumer.subscribe("MyTopic", "MyTag||MyTag2");
复制代码

如果设为consumer.subscribe("MyTopic", "*")会导致无法收到消息!

分类:
后端
标签:
分类:
后端
标签: