MQ介绍
为什么要用mq?
mq是一种先进先出数据结构,主要应用包括一下三方面:
- 流量削峰
- 应用解耦
- 异步调用
MQ优缺点
优点:流量削峰、异步调用、应用解耦
缺点:
-
系统可用性降低
一旦发生MQ宕机,就会对业务造成影响,如何保证MQ高可用?
-
系统复杂度提高
以前系统是同步调用,现在是通过MQ进行异步系统调用,
如何保证消息没有被重复消费?如何处理消息丢失?如何保证消息传递顺序性?
-
一致性问题
A处理业务,通过MQ给BCD,BC处理成功,但D处理失败,如何保证消息一致性?
MQ快速入门
安装
- 解压程序包
- 进入安装目录
目录介绍:
- bin:启动脚本,包括shell脚本和cmd脚本
- conf:实例配置文件,包括broker配置文件、logback配置文件
- lib:依赖jar包,包括Netty,commons-log、FastJson等
启动RocketMQ:
-
启动nameserver
nohup sh bin/mqnamesrv & #查看启动日志 tail -f ~/logs/rocketmqlogs/namesrv.log
-
启动broker
nohop sh bin/mqbroker -n localhost:6897 & #查看启动日志 tail -f ~/logs/rocketmqlogs/broker.log
出现问题
- RocketMQ默认虚拟机内存较大,如果broker启动失败,需要调整RocketMQ配置文件,修改jvm内存大小
vi runbroker.sh vi runserve.sh
参考配置
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
ROcketMQ集群搭建
各个角色介绍
- producer:消息发送者,寄信人
- consumer:消息接收者,收信人
- broker:暂存和传送消息,邮局
- NameServer:管理broker,邮局管理机构
- Topic:区分消息种类,一个生产者可以发送消息给一个或多个Topic,一个消费者可以订阅一个或多个Topci
- Message Queue:相当于Topci的分区,用于并行发送消息和接收消息。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AXxG9Ur1-1676276154209)(D:\MarkDownP\image-20230210084511469.png)]
集群搭建方式:
集群特点:
- NameServer是一个几乎无节点状态,可集群部署,节点之间无信息同步
- Broker:部署相对复杂,Broker分为master和salve,一个Master可对应多个salve,但一个salve只能对应一个master,Master与salve之间对应通过BrokerName里不同的BrokerId来定义。BrokerId为0表示为master节点,非0表示Slave。Master也可以部署多个。每个Broker与NameServer集群中所有节点建立长连接,定时注册topic到nameserver中。
- Producer与NameServer集群中一个节点建立长连接,定期从NameServer中的Topic中获取路由信息,并向提供Topic服务的Master建立长连接,且定时向master发送心跳。Producer完全无状态,可集群部署。
- Consumer与NameServer集群中一个节点建立长连接,定期从NameServer取Topic路由信息,并向提供Topic服务的Master、salve建立长连接,且定时向Master、salve发送心跳。Consumer既可以向Master订阅消息,也可以从Salve订阅消息,订阅规则有broker确定。
集群模式
-
单master模式:
- 这种模式风险较大,一旦mq宕机,会导致整个服务不可用,不建议线上环境使用,可以用于本地测试。
-
多master模式:
-
一个集群无salve,全是master。
优点:配置简单,单个master宕机对整体影响不大。
缺点:单台MQ宕机期间,这台机器上未被消费的消息将在机器恢复之前不会被订阅。
-
-
多master与多salve异步
每个master配置多个salve,多对master-salve,HA采用异步复制,
优点:即使磁盘损坏,消息丢失非常少,且实时性不会受影响,同时master宕机后,可以从salve消费,性能几乎和多master模式一样。
缺点:master宕机,导致消息少量丢失。
-
多master与多salve同步
HA采用同步双写,只有主从双节点都写入成功才可以返回,
优点:master宕机情况下,无消息丢失
缺点:性能比异步低,
双主双从集群搭建
集群搭建流程
- 启动nameserver,Nameserver起来后监控端口,等待broker,producer,consumer连上来,相当于一个路由中心。
- broker启动后,跟所有nameserver保持长连接,定时发送心跳包。心跳包包含当前Broker信息(ip+端口等)以及存储所有topic信息。注册成功后,nameserver集群中就有topic跟broker的映射关系。
- 收发消息前,先创建Topic,创建topic时候需要指定topci要存储在哪些broker上,也可以在发送消息时自动创建topic。
- producer发送消息,启动时先和nameservr建立长连接,并从nameserverhz中获取当前发送的topic存在哪些broker上,轮询从列表队列中选择一个列,然后与队列所在的broker建立长连接从而向broker发送消息。
- consumer跟producer类似,跟其中一台nameserver建立连接,获取topic信息在哪些broker上,然后和broker建立连接,开始消费消息。
服务器环境:
序号 | IP | 角色 | 架构模式 |
---|---|---|---|
1 | 192.168.25.135 | nameserver、brokerserver | Master1、Slave2 |
2 | 192.168.25.138 | nameserver、brokerserver | Master2、Slave1 |
host添加信息
vim /etc/hosts
配置如下:
#nameserver
192.168.25.135 rocketmq-nameserver1
192.168.25.138 rocketmq-nameserver2
#broker
192.168.25.135 rocketmq-master1
192.168.25.135 rocketmq-salve1
192.168.25.138 rocketmq-master2
192.168.25.138 rocketmq-salve2
配置完成重启网卡
systemctl restart network
宿主机需要远程访问虚拟机的rocketmq服务和web服务,需要开放相关的端口号,简单粗暴的方式是直接关闭防火墙
# 关闭防火墙
systemctl stop firewalld.service
# 查看防火墙的状态
firewall-cmd --state
# 禁止firewall开机启动
systemctl disable firewalld.service
环境变量配置
vim /etc/profile
在profile文件末尾加入如下命令
#set rocketmq
ROCKETMQ_HOME=/usr/local/rocketmq/rocketmq-all-4.4.0-bin-release
PATH=$PATH:$ROCKETMQ_HOME/bin
export ROCKET_HOME PATH
输入:wq!保存退出,并使配置生效
source /etc/profile
创建消息存储路径
mkdir /usr/local/rocketmq/store
mkdir /usr/local/rocketmq/store/commitlog
mkdir /usr/local/rocketmq/store/consumequeue
mkdir /usr/local/rocketmq/store/index
修改master配置文件四个
master1
服务器:192.168.25.135
vi /usr/soft/rocketmq/conf/2m-2s-sync/broker-a.properties
修改配置如下:
#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示 Master,>0 表示 Slave
brokerId=0
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SYNC_MASTER
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
slave2
服务器:192.168.25.135
vi /usr/soft/rocketmq/conf/2m-2s-sync/broker-b-s.properties
修改配置如下:
#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
#0 表示 Master,>0 表示 Slave
brokerId=1
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=11011
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SLAVE
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
master2
服务器:192.168.25.138
vi /usr/soft/rocketmq/conf/2m-2s-sync/broker-b.properties
修改配置如下:
#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
#0 表示 Master,>0 表示 Slave
brokerId=0
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SYNC_MASTER
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
slave1
服务器:192.168.25.138
vi /usr/soft/rocketmq/conf/2m-2s-sync/broker-a-s.properties
修改配置如下:
#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示 Master,>0 表示 Slave
brokerId=1
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=11011
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SLAVE
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
修改脚本启动文件,
runbroker.sh
vi /usr/local/rocketmq/bin/runbroker.sh
需要根据内存大小进行适当的对JVM参数进行调整:
#===================================================
# 开发环境配置 JVM Configuration
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m"
runserver.sh
vim /usr/local/rocketmq/bin/runserver.sh
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
启动NameServe集群
分别在192.168.25.135和192.168.25.138启动NameServer
cd /usr/local/rocketmq/bin
nohup sh mqnamesrv &
启动Broker集群
- 在192.168.25.135上启动master1和slave2
master1:
cd /usr/local/rocketmq/bin
nohup sh mqbroker -c /usr/local/rocketmq/conf/2m-2s-syncbroker-a.properties &
slave2:
cd /usr/local/rocketmq/bin
nohup sh mqbroker -c /usr/local/rocketmq/conf/2m-2s-sync/broker-b-s.properties &
- 在192.168.25.138上启动master2和slave2
master2
cd /usr/local/rocketmq/bin
nohup sh mqbroker -c /usr/local/rocketmq/conf/2m-2s-sync/broker-b.properties &
slave1
cd /usr/local/rocketmq/bin
nohup sh mqbroker -c /usr/local/rocketmq/conf/2m-2s-sync/broker-a-s.properties &
消息发送
事务消息
流程
事务消息大致大致方案,两个流程:正常事务消息的发送和提交,事务消息的补偿流程。
-
事务消息发送和提交
- 发送消息
- 服务端相应消息写入结果。
- 根据发送结果,执行本地事务(如果写入失败,则本条half消息对外不可见,本地逻辑不执行。)
- 根据本地事务状态执行commit或者rollback(commit操作生成消息索引,消息对消费者可见)
-
事务补偿
- 对没有commit/rollback的事务消息,从服务端发起一次回查
- producer收到回查消息,检查回查消息对应的本地事务状态。
- 根据本地事务状态,重新commit或者rollback
其中补偿阶段用于解决消息commit或者rollback发生超时或者失败的情况。
-
事务消息状态
事务消息共有三种状态,提交状态,回滚状态,中间状态
- TransactionStatus.CommitTransaction:提交事务,它允许消费者消费此消息。
- TransactionStatus.RollbackTransaction:回滚事务,他代表消息即将被删除,不允许被消费
- TransactionStatus.Unknown:中间状态,他代表需要检查消息队列来确定状态。
使用事务分两个步骤:
- 创建事务监听器,后续正常流程(创建消息生成者,设置mq地址,启动生产者,创建消息体,在消息体中写入消息,topic,tag等)
- 写一个TransactionListener的实现类,重写其方法完成事务的处理。
- 事务处理就是对其状态进行检查,如果为unknown则执行另一个重写方法,
创建事务性生产者
使用 TransactionMQProducer
类创建生产者,并指定唯一的 ProducerGroup
,就可以设置自定义线程池来处理这些检查请求。执行本地事务后、需要根据执行结果对消息队列进行回复。回传的事务状态在请参考前一节。
public class Producer {
public static void main(String[] args) throws MQClientException, InterruptedException {
//创建事务监听器
TransactionListener transactionListener = new TransactionListenerImpl();
//创建消息生产者
TransactionMQProducer producer = new TransactionMQProducer("group6");
producer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");
//生产者这是监听器
producer.setTransactionListener(transactionListener);
//启动消息生产者
producer.start();
String[] tags = new String[]{"TagA", "TagB", "TagC"};
for (int i = 0; i < 3; i++) {
try {
Message msg = new Message("TransactionTopic", tags[i % tags.length], "KEY" + i,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.sendMessageInTransaction(msg, null);
System.out.printf("%s%n", sendResult);
TimeUnit.SECONDS.sleep(1);
} catch (MQClientException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//producer.shutdown();
}
}
实现事务的监听接口
当发送半消息成功时,我们使用 executeLocalTransaction
方法来执行本地事务。它返回前一节中提到的三个事务状态之一。checkLocalTranscation
方法用于检查本地事务状态,并回应消息队列的检查请求。它也是返回前一节中提到的三个事务状态之一。
public class TransactionListenerImpl implements TransactionListener {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
System.out.println("执行本地事务");
if (StringUtils.equals("TagA", msg.getTags())) {
return LocalTransactionState.COMMIT_MESSAGE;
} else if (StringUtils.equals("TagB", msg.getTags())) {
return LocalTransactionState.ROLLBACK_MESSAGE;
} else {
return LocalTransactionState.UNKNOW;
}
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
System.out.println("MQ检查消息Tag【"+msg.getTags()+"】的本地事务执行结果");
return LocalTransactionState.COMMIT_MESSAGE;
}
}
消息存储
MQ处理消息流程:
- 消息生成者发送消息
- MQ收到消息,对消息进行持久化,在存储中新增一条记录
- 返回ack给生产者
- MQ push消息给对应消费者,然后等待消费者返回ack
- 如果消费者在指定时间内没有返回ack,那么MQ则认为消息没有消费成功,在存储中删除消息,即执行第六步;如果MQ在指定时间内没有收到ack,则认为消息消费失败,会尝试重新push消息,重复执行4、5、6步骤
- MQ删除消息
存储介质
-
关系型数据库DB
由于普通关系型数据库在单表数据量达到千万级别的情况下,其IO读写性能往往会出现瓶颈。在可靠性方面,该种方案非常依赖 DB,如果一旦DB出现故障,则MQ的消息就无法落盘存储导致线上故障。
-
文件系统
目前业界较为常用的几款产品(RocketMQ/Kafka/RabbitMQ)均采用的是消息刷盘至所部署虚拟机/物理机的文件系统来做持久化
性能对比:文件系统>关系型数据库
消息存储结构:
RocketMQ消息存储是由ConsumeQueue和CommitLog配合完成的,消息真正的物理存储文件时CommitLog,ConsumerQueue是消息的逻辑队列,类似数据库的索引文件,存储的是指向物理存储的地址。每个Topic下的每个Message Queue都有一个对应的ConsumeQueue文件。
- CommitLog:存储消息的元数据
- COnsumerQueue:存储消息在CommitLog的索引
- IndexFile:为了消息查询提供了一种通过key或时间区间来查询消息的方法,这种通过indexFile来查找消息的方法不影响发送与消费消息的主流程
刷盘机制
RocketMQ的消息是存储到磁盘上的,这样技能保证断电后恢复,又可以让存储的消息量超出内存限制。RocketMQ为了提高性能,会尽可能保证磁盘顺序写。消息在通过Producer写入RocketMQ的时候,有两种写磁盘方式,分布式同步刷盘和异步刷盘。
同步刷盘
在返回写成功状态时,消息已被写入磁盘。具体流程是,消息写入内存的PAGECACHE后,立刻通知刷盘线程刷盘,然后等待刷盘完成后,刷盘线程执行完成后唤醒等待线程,返回消息写成功状态。
异步刷盘
在返回写成功状态时,消息可能只是被写入了内存的PAGECACHE,写操作的返回快,吞吐量大;当内存里的消息量积累到一定程度时,统一出发写磁盘动作,快速写入。
配置
同步刷盘还是异步刷盘,都是通过Broker配置文件里的flushDiskType参数设置的,这个参数被配置成SYNC_FLUSH、ASYNC_FLUSH中的一个。
消息重试
顺序消息重试
对于顺序消息,当消费者消费消息失败后,消息队列RocketMQ会自动不断进行消息重试,这事,应用会出现消息消费被阻塞情况。因此,在是由顺序消息是,务必保证应用能够即使监控并处理消费失败的情况,避免阻塞现象发生。
无序消息重试
对于无序消息(普通、定时、延时、事务消息),当消费者消费小时失败时,可以通过设置返回状态达到消息重试结果。
无序消息的重试只针对集群消费方式生效;广播方式不提供失败重试特性,即消费失败后,失败消息不再重试,继续消费新的消息。
配置方式
消费失败后,重试配置方式
集群消费方式下,消息消费失败后,期望消息重试,需要在消息监听接口的实现中进行配置
- 返回Action.ReconsumerLater
- 返回null
- 抛出异常
public class MessageListenerImpl implements MessageListener {
@Override
public Action consume(Message message, ConsumeContext context) {
//处理消息
doConsumeMessage(message);
//方式1:返回 Action.ReconsumeLater,消息将重试
return Action.ReconsumeLater;
//方式2:返回 null,消息将重试
return null;
//方式3:直接抛出异常, 消息将重试
throw new RuntimeException("Consumer Message exceotion");
}
}
消费失败后,不重试配置方式
集群消费方式下,消息失败后,期望消息不重试,需要捕获消费逻辑中可能抛出的异常,最终返回Action.CommitMessage,此后这条消息不再被重试。
public class MessageListenerImpl implements MessageListener {
@Override
public Action consume(Message message, ConsumeContext context) {
try {
doConsumeMessage(message);
} catch (Throwable e) {
//捕获消费逻辑中的所有异常,并返回 Action.CommitMessage;
return Action.CommitMessage;
}
//消息处理正常,直接返回 Action.CommitMessage;
return Action.CommitMessage;
}
}
死信队列
当一条消息初次失败后,消息队列MQ会自动进行消息重试;达到最大重试次数后,若消费依然失败,则表明消费者在正常情况下无法正确的消费该消息,此时,消息队列MQ不会立刻将消息丢弃,而是将消息发送到消费者对应的特殊队列中。