一.概念

rocketMQ是一款典型的分布式架构下的中间件产品,使用异步通信方式和发布订阅的消息传输模型,具备异步通信的优势,系统拓扑简单,上下游耦合较弱,主要应用于异步解耦,流量削峰填谷等场景

二.服务端部署

部署声明

名称 版本 IP
Rocket 4.4.0 192.168.10.99

官方链接

名称 地址
官方文档 https://rocketmq.apache.org/docs/

安装namesrv

1. 拉取镜像

docker pull rocketmqinc/rocketmq

2. 创建挂载目录

mkdir -p  /docker/rocketmq/data/namesrv/logs   /docker/rocketmq/data/namesrv/store

3. 创建和启动容器

docker run -d \
--restart=always \
--name rmqnamesrv \
-p 9876:9876 \
-v /docker/rocketmq/data/namesrv/logs:/root/logs \
-v /docker/rocketmq/data/namesrv/store:/root/store \
-e "MAX_POSSIBLE_HEAP=100000000" \
rocketmqinc/rocketmq \
sh mqnamesrv

安装broker

1. 创建broker数据存储路径

mkdir -p  /docker/rocketmq/data/broker/logs   /docker/rocketmq/data/broker/store /docker/rocketmq/conf

2. 创建配置文件

vi /docker/rocketmq/conf/broker.conf
# 所属集群名称,如果节点较多可以配置多个
brokerClusterName = DefaultCluster
#broker名称,master和slave使用相同的名称,表明他们的主从关系
brokerName = broker-a
#0表示Master,大于0表示不同的slave
brokerId = 0
#表示几点做消息删除动作,默认是凌晨4点
deleteWhen = 04
#在磁盘上保留消息的时长,单位是小时
fileReservedTime = 48
#有三个值:SYNC_MASTER,ASYNC_MASTER,SLAVE;同步和异步表示Master和Slave之间同步数据的机制;
brokerRole = ASYNC_MASTER
#刷盘策略,取值为:ASYNC_FLUSH,SYNC_FLUSH表示同步刷盘和异步刷盘;SYNC_FLUSH消息写入磁盘后才返回成功状态,ASYNC_FLUSH不需要;
flushDiskType = ASYNC_FLUSH
# 设置broker节点所在服务器的ip地址
brokerIP1 = 192.168.10.99
# 磁盘使用达到95%之后,生产者再写入消息会报错 CODE: 14 DESC: service not available now, maybe disk full
diskMaxUsedSpaceRatio=95
#开启自动创建主题
autoCreateTopicEnable=true
#开启过滤消息
enablePropertyFilter=true

3. 构建broker容器

docker run -d  \
--restart=always \
--name rmqbroker \
--link rmqnamesrv:namesrv \
-p 10911:10911 \
-p 10909:10909 \
-v /docker/rocketmq/data/broker/logs:/root/logs \
-v /docker/rocketmq/data/broker/store:/root/store \
-v /docker/rocketmq/conf/broker.conf:/opt/rocketmq-4.4.0/conf/broker.conf \
-e "NAMESRV_ADDR=namesrv:9876" \
-e "MAX_POSSIBLE_HEAP=200000000" \
rocketmqinc/rocketmq \
sh mqbroker -c /opt/rocketmq-4.4.0/conf/broker.conf

安装控制台服务

1. 拉起镜像

docker pull pangliang/rocketmq-console-ng

2. 构建容器

docker run -d \
--restart=always \
--name rmqadmin \
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=192.168.10.99:9876 \
-Dcom.rocketmq.sendMessageWithVIPChannel=false \
-Duser.timezone='Asia/Shanghai'" \
-v /etc/localtime:/etc/localtime \
-p 9999:8080 \
pangliang/rocketmq-console-ng

控制台地址: http://192.168.10.99:9999

错误1

控制台报错 This date have’t data

构建容器时加入jvm 时区及系统时区文件

-v /etc/localtime:/etc/localtime

错误2

集成boot时 CODE: 1 DESC: The broker does not support consumer to filter message by SQL92

在broker.conf配置文件中 #开启过滤消息功能

enablePropertyFilter=true
docker run -d --restart=always --name rmqadmin -e "JAVA_OPTS=-Drocketmq.namesrv.addr=b.youlai.tech:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -Duser.timezone='Asia/Shanghai'" -v /etc/localtime:/etc/localtime -p 9999:8080 pangliang/rocketmq-console-ng

三 客户端部署

1.Maven依赖

        <dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>

2.客户端配置

rocketmq:
name-server: http://192.168.10.99:9876
producer:
group: defaultGroup

四. RocketMQ实战

普通消息

生产者

同步发送

    public boolean sync(String message) {
boolean flag = true;
String text1 = "发送消息:" + message;
log.info(text1);
SendResult sendResult1 = rocketMQTemplate.syncSend("base_topic", text1);
log.info("同步响应:"+sendResult1.getSendStatus().toString());
if(!SendStatus.SEND_OK.equals(sendResult1.getSendStatus())){
flag = false;
}
return flag;
}

异步发送

    /**
* 异步消息
*/
public boolean async(String message) {
String text1 = "发送消息:" + message;
log.info(text1);
rocketMQTemplate.asyncSend("base_topic", text1 , new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("异步消息响应成功");
}
@Override
public void onException(Throwable throwable) {
log.info("异步消息响应发送失败");
}
});
return true;
}

单向发送

    /**
* 单向消息,不关心返回结果
*/
public boolean oneWay(String message) {
String text1 = "发送消息:" + message;
log.info(text1);
rocketMQTemplate.sendOneWay("base_topic", text1);
log.info("单向发送-已发送...");
return true;
}

消费者

@Component
@RocketMQMessageListener( topic = "base_topic",consumerGroup = "defaultGroup", messageModel = MessageModel.BROADCASTING, consumeMode= ConsumeMode.CONCURRENTLY)
@Slf4j
public class BaseConsumer implements RocketMQListener<String> { @Override
public void onMessage(String message) {
log.info("普通信息-接受到消息:" + message);
}
}

测试

顺序消息

生产者

@Service
@Slf4j
public class OrderProducer {
@Resource
RocketMQTemplate rocketMQTemplate; private String topic = "order_topic";
public boolean order(String create, String pay, String deliver) {
boolean flag = true;
try {
TimeUnit.MILLISECONDS.sleep(50); String text1 = "发送顺序消息1:" + create;
log.info(text1);
SendResult sendResult1 = rocketMQTemplate.syncSendOrderly(topic, text1,"order");
if(!SendStatus.SEND_OK.equals(sendResult1.getSendStatus())){
flag = false;
} TimeUnit.MILLISECONDS.sleep(50);
String text2 = "发送顺序消息2:" + pay;
log.info(text2);
SendResult sendResult2 = rocketMQTemplate.syncSendOrderly(topic, text2,"order");
if(!SendStatus.SEND_OK.equals(sendResult2.getSendStatus())){
flag = false;
}
TimeUnit.MILLISECONDS.sleep(50);
String text3 = "发送顺序消息3:" + deliver;
log.info(text3);
SendResult sendResult3 = rocketMQTemplate.syncSendOrderly(topic, text3,"order");
if(!SendStatus.SEND_OK.equals(sendResult3.getSendStatus())){
flag = false;
}
return flag;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

消费者

@Component
@RocketMQMessageListener( consumeMode= ConsumeMode.ORDERLY, topic = "order_topic", consumerGroup = "order_group")
@Slf4j
public class OrderConsumer implements RocketMQListener<String> { @Override
public void onMessage(String message) {
log.info("顺序消息-接收到消息:" + message);
}
}

测试

延迟消息

生产者

@Service
@Slf4j
public class ScheduledProducer {
@Resource
RocketMQTemplate rocketMQTemplate; public void scheduled(Integer delayLevel,String body) {
String text = "延时"+delayLevel+"消息:"+ body;
log.info(text);
// 设置延时等级2,这个消息将在5s之后发送
// 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
Message<String> message = MessageBuilder.withPayload(body).build();
SendResult sendResult = rocketMQTemplate.syncSend("scheduled_topic", message, 1000, delayLevel);
log.info("延时消息发送:"+sendResult.getSendStatus().toString());
}
}

消费者

@Component
@RocketMQMessageListener(topic = "scheduled_topic", consumerGroup = "scheduled_group", messageModel = MessageModel.BROADCASTING, consumeMode= ConsumeMode.CONCURRENTLY)
@Slf4j
public class ScheduleConsumer implements RocketMQListener<String> { @Override
public void onMessage(String message) {
log.info("延时消息-接受到消息:" + message);
}
}

测试

批量消息

生产者

@Service
@Slf4j
public class BatchProducer {
@Resource
RocketMQTemplate rocketMQTemplate; public void batch(String message1,String message2,String message3,String message4,String message5) {
List<Message> messageList = new ArrayList<>();
messageList.add(MessageBuilder.withPayload(message1).build());
messageList.add(MessageBuilder.withPayload(message2).build());
messageList.add(MessageBuilder.withPayload(message3).build());
messageList.add(MessageBuilder.withPayload(message4).build());
messageList.add(MessageBuilder.withPayload(message5).build());
log.info("开始发送...");
SendResult result = rocketMQTemplate.syncSend("batch_topic", messageList);
log.info("已发送...");
}
}

消费者

@Component
@RocketMQMessageListener(topic = "batch_topic", consumerGroup = "batch_group", messageModel = MessageModel.BROADCASTING, consumeMode= ConsumeMode.CONCURRENTLY)
@Slf4j
public class BatchConsumer implements RocketMQListener<String> { @Override
public void onMessage(String message) {
log.info("批量消息-接受到消息:" + message);
}
}

测试

事务消息

生产者

@Service
@Slf4j
@RequiredArgsConstructor
public class TxProducer {
@Resource
RocketMQTemplate rocketMQTemplate; public void tx(Boolean isOpenTx) {
Message<Long> message = MessageBuilder.withPayload(Long.valueOf(RandomUtil.randomInt(1,1000)))
// 设置事务Id
.setHeader(RocketMQHeaders.TRANSACTION_ID,RandomUtil.randomInt(1,1000))
.build();
rocketMQTemplate.sendMessageInTransaction("tx:tx_expression", message, isOpenTx);
log.info("发送事务消息");
}
}

消费者

@Slf4j
@RocketMQTransactionListener
@RequiredArgsConstructor
public class TxProducerListener implements RocketMQLocalTransactionListener { /**
* 记录各个事务Id的状态:1-正在执行,2-执行成功,3-执行失败
*/
private ConcurrentHashMap<String, Integer> transMap = new ConcurrentHashMap<>(); /**
* 执行本地事务
*
* @param msg
* @param arg
* @return
*/
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Boolean isOpenTx = (Boolean) arg;
if(isOpenTx){
log.info("提交事务");
return RocketMQLocalTransactionState.COMMIT;
}else{
log.info("回滚事务");
return RocketMQLocalTransactionState.ROLLBACK;
}
} /**
* 事务超时,回查方法
* 检查本地事务,如果RocketMQ长时间(1分钟左右)没有收到本地事务的返回结果,则会定时主动执行改方法,查询本地事务执行情况。
*
* @param msg
* @return
*/
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
log.info("检查事务");
return RocketMQLocalTransactionState.UNKNOWN;
}
}

测试

踩坑1

消费者接收不到消息

@RocketMQMessageListener(  topic = "base_topic",consumerGroup = "defaultGroup", messageModel = MessageModel.BROADCASTING, consumeMode= ConsumeMode.CONCURRENTLY)

消费者默认为集群消费模式,需要修改为广播模式

  • 集群消费模式:当使用集群消费模式时,RocketMQ 认为任意一条消息只需要被消费组内的任意一个消费者处理即可。
  • 广播消费模式:当使用广播消费模式时,RocketMQ 会将每条消息推送给消费组所有的消费者,保证消息至少被每个消费者消费一次。

踩坑2

springboot版本大于2.6时会和knife4j冲突

解决方法

spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher

五.总结

本文只是简单写了一下rocketmq的基本使用,主要需要理解的是rocketmq里面生产者和消费者,消息类型,了解清楚概念就没什么问题了

所有代码地址:https://gitee.com/youlaiorg/youlai-learning.git

SpringBoot整合RocketMQ案例实战的更多相关文章

  1. SpringBoot(17)---SpringBoot整合RocketMQ

    SpringBoot整合RocketMQ 上篇博客讲解了服务器集群部署RocketMQ 博客地址:RocketMQ(2)---Docker部署RocketMQ集群 这篇在上篇搭建好的基础上,将Spri ...

  2. springBoot 整合 mybatis 项目实战

    二.springBoot 整合 mybatis 项目实战   前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用 ...

  3. SpringBoot整合Mybatis案例

    SpringBoot整合Mybatis案例 2019/7/15以实习生身份入职公司前端做Angular ,但是感觉前途迷茫,于是乎学习一下Java的框架——SpringBooot. 参照大神博客:ht ...

  4. SpringBoot整合Swagger2案例,以及报错:java.lang.NumberFormatException: For input string: ""原因和解决办法

    原文链接:https://blog.csdn.net/weixin_43724369/article/details/89341949 SpringBoot整合Swagger2案例 先说SpringB ...

  5. Springboot整合RocketMQ解决分布式事务

    直接上代码: 代码结构如下: 依次贴出相关类: DataSource1Config: package com.example.demo.config;import org.apache.ibatis. ...

  6. 二、springBoot 整合 mybatis 项目实战

    前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用的是jdbcTemplate.项目中肯定不会这样使用,上篇文章 ...

  7. 史上最全SpringBoot整合Mybatis案例

    摘要:如果小编说,SpringBoot是目前为止最好的框架,应该没有人会反驳吧?它的出现使得我们很容易就能搭建一个新应用.那么,SpringBoot与其他第三方框架的整合必定是我们需要关注的重点. 开 ...

  8. SpringBoot 整合缓存Cacheable实战详细使用

    前言 我知道在接口api项目中,频繁的调用接口获取数据,查询数据库是非常耗费资源的,于是就有了缓存技术,可以把一些不常更新,或者经常使用的数据,缓存起来,然后下次再请求时候,就直接从缓存中获取,不需要 ...

  9. SpringBoot整合RocketMQ

    1.RocketMQ的下载与配置 到官网选择想要的版本下载即可,https://rocketmq.apache.org/release_notes/ 下载速度会比较慢,这里提供目前最新版本4.9.3的 ...

  10. spring-boot整合Mybatis案例

    1.运行环境 开发工具:intellij idea JDK版本:1.8 项目管理工具:Maven 3.2.5 2.Maven Plugin管理 <?xml version="1.0&q ...

随机推荐

  1. linux离线安装gcc 和g++

    1.先到有网的机器上下载依赖包 sudo yum install --downloadonly --downloaddir=/home/mjb/soft/gcc gcc sudo yum instal ...

  2. java websocket详细

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...

  3. noi 1.1 4 保留三位的浮点数

    描述 输入一个单精度浮点数,保留3位小数输出这个浮点数. 输入 只有一行,一个单精度浮点数. 输出 也只有一行,输入的单精度浮点数. 样例输入 12.34521 样例输出 12.345 题意 就是输入 ...

  4. 二叉树系列之二叉搜索树BST

    特征: 1.每个元素有唯一键值 2.任意一个结点键值,比它左子树的所有结点的键值大,比它右子树的所有结点的键值小 数据的基本操作: 1>建树和插入.逐个插入其他所有数据.新插入的数据于一个最底层 ...

  5. redis存储类型-数字和带双引号的数字

    这个是不一样的值,出现了转换异常

  6. Liunx mosquitto卸载

    1.查询文件: whereis mosquitto whereis mosquitto_sub 2.删除查询到的文件,命令: rm -rf /etc/mosquitto rm -f /usr/loca ...

  7. Jmeter五、jmeter中的逻辑控制器

    1.simple controller 提供一个块的结构和控制.更方便,更清晰. 嵌套其他的controller 2.loop controller 循环控制器 控制循环次数 可以使用变量 ${__t ...

  8. LeetCode 刷题感想之动态规划

    在 LeetCode/剑指Offer 上刷了500题左右了,应该写一篇文章总结一下自己的感想.因为我自己是测试,所以从测试角度来写感受吧. 先说动态规划. 什么是动态规划?是经典算法思想之一,是自底向 ...

  9. ext表单合并行

    在js里加入方法 /*** 合并Grid的数据列* @param grid {Ext.Grid.Panel} 需要合并的Grid* @param colIndexArray {Array} 需要合并列 ...

  10. SpringBoot - Lombok使用详解1(基本介绍、安装配置、var和val)

    我们创建 POJO 类时,经常需要先写属性,然后手写或者自动生成 get 和 set 方法,然后还要重写 toString 方法....一系列操作下来,这个 POJO 类便会产生太多的样板式代码. 这 ...