SpringBoot整合RocketMQ案例实战
一.概念
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案例实战的更多相关文章
- SpringBoot(17)---SpringBoot整合RocketMQ
SpringBoot整合RocketMQ 上篇博客讲解了服务器集群部署RocketMQ 博客地址:RocketMQ(2)---Docker部署RocketMQ集群 这篇在上篇搭建好的基础上,将Spri ...
- springBoot 整合 mybatis 项目实战
二.springBoot 整合 mybatis 项目实战 前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用 ...
- SpringBoot整合Mybatis案例
SpringBoot整合Mybatis案例 2019/7/15以实习生身份入职公司前端做Angular ,但是感觉前途迷茫,于是乎学习一下Java的框架——SpringBooot. 参照大神博客:ht ...
- SpringBoot整合Swagger2案例,以及报错:java.lang.NumberFormatException: For input string: ""原因和解决办法
原文链接:https://blog.csdn.net/weixin_43724369/article/details/89341949 SpringBoot整合Swagger2案例 先说SpringB ...
- Springboot整合RocketMQ解决分布式事务
直接上代码: 代码结构如下: 依次贴出相关类: DataSource1Config: package com.example.demo.config;import org.apache.ibatis. ...
- 二、springBoot 整合 mybatis 项目实战
前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用的是jdbcTemplate.项目中肯定不会这样使用,上篇文章 ...
- 史上最全SpringBoot整合Mybatis案例
摘要:如果小编说,SpringBoot是目前为止最好的框架,应该没有人会反驳吧?它的出现使得我们很容易就能搭建一个新应用.那么,SpringBoot与其他第三方框架的整合必定是我们需要关注的重点. 开 ...
- SpringBoot 整合缓存Cacheable实战详细使用
前言 我知道在接口api项目中,频繁的调用接口获取数据,查询数据库是非常耗费资源的,于是就有了缓存技术,可以把一些不常更新,或者经常使用的数据,缓存起来,然后下次再请求时候,就直接从缓存中获取,不需要 ...
- SpringBoot整合RocketMQ
1.RocketMQ的下载与配置 到官网选择想要的版本下载即可,https://rocketmq.apache.org/release_notes/ 下载速度会比较慢,这里提供目前最新版本4.9.3的 ...
- spring-boot整合Mybatis案例
1.运行环境 开发工具:intellij idea JDK版本:1.8 项目管理工具:Maven 3.2.5 2.Maven Plugin管理 <?xml version="1.0&q ...
随机推荐
- Qt中资源文件qrc中的路径访问
首先先看一下我们的qrc文件目录结构: 在文件系统中的目录结构是这样的: 请务必注意这边的前缀(按照网友推荐,大部分项目前缀都是只写一个"/"): 接下来进入正题,我们来分 ...
- Mysql存储的设备推送数据如何利用GroupBy筛选所有设备的最新数据
首先介绍GroupBy关键字的用法原理: 先来看下表1,表名为test: 表1 执行如下SQL语句: SELECTnameFROMtestGROUPBYname 你应该很容易知道运行的结果,没错, ...
- spring的作用
Spring能有效地组织你的中间层对象,无论你是否选择使用了EJB.如果你仅仅使用了Struts或其他的包含了J2EE特有API的framework,你会发现Spring关注了遗留下的问题.Sprin ...
- Linux日常指令
Linux: https://man.linuxde.net/ Linux命令大全 基础指令 终端输入: #shutdown -h now : 立即关机 #ls: 显示路径下所有的文件: ...
- JDK的安装及卸载
JDK安装及卸载 卸载JDK 删除JAVA安装目录 删除java_home 删除path下关于Java的目录 java-version 查看是否仍能查看 安装JDK 百度搜索JDK8(性能稳定)找到下 ...
- php对接java接口
1.php curl 传参形式 public function send($url,$postData){ $ch = curl_init(); $headers = array("Cont ...
- jmeter dubbo测试
一.环境准备 1.安装jmeter 2.安装dubbo插件,下载地址jmeter-plugins-dubbo, 将jar包放入${JMETER_HOME}\lib\ext路径下,重启即可 二.添加一个 ...
- C# NAudio 检测声音
using NAudio.Wave;using System;using System.Collections.Generic; namespace WinFromBaidu{ class NAudi ...
- 12.8 linux学习第十五天
今天老刘讲了第11章和第12章,感觉讲的速度很快,一气呵成,水都没怎么喝. 11.1 文件传输协议 一般来讲,人们将计算机联网的首要目的就是获取资料,而文件传输是一种非常重要的获取资料的方式.今天的互 ...
- Hyper-V 直连主机USB设备
因为授权问题不让用 Vmware 了.所以换成微软自带的 Hyper V 但是碰到一个很头痛的问题,就是外部设备没法像 Vmware 那样直接连接到虚拟机里面,很多第三方设备没法调试了. 找了很久终于 ...