Rocket小结

MQ介绍

为什么要用mq?

mq是一种先进先出数据结构,主要应用包括一下三方面:

  1. 流量削峰
  2. 应用解耦
  3. 异步调用

MQ优缺点

优点:流量削峰、异步调用、应用解耦

缺点:

  • 系统可用性降低

    一旦发生MQ宕机,就会对业务造成影响,如何保证MQ高可用?

  • 系统复杂度提高

    以前系统是同步调用,现在是通过MQ进行异步系统调用,

    如何保证消息没有被重复消费?如何处理消息丢失?如何保证消息传递顺序性?

  • 一致性问题

    A处理业务,通过MQ给BCD,BC处理成功,但D处理失败,如何保证消息一致性?

MQ快速入门

安装

  1. 解压程序包
  2. 进入安装目录

目录介绍:

  • bin:启动脚本,包括shell脚本和cmd脚本
  • conf:实例配置文件,包括broker配置文件、logback配置文件
  • lib:依赖jar包,包括Netty,commons-log、FastJson等

启动RocketMQ:

  1. 启动nameserver

    nohup sh bin/mqnamesrv &
    
    #查看启动日志
    tail -f ~/logs/rocketmqlogs/namesrv.log
    
  2. 启动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确定。

集群模式

  1. 单master模式:

    • 这种模式风险较大,一旦mq宕机,会导致整个服务不可用,不建议线上环境使用,可以用于本地测试。
  2. 多master模式:

    • 一个集群无salve,全是master。

      优点:配置简单,单个master宕机对整体影响不大。

      缺点:单台MQ宕机期间,这台机器上未被消费的消息将在机器恢复之前不会被订阅。

  3. 多master与多salve异步

    每个master配置多个salve,多对master-salve,HA采用异步复制,

    优点:即使磁盘损坏,消息丢失非常少,且实时性不会受影响,同时master宕机后,可以从salve消费,性能几乎和多master模式一样。

    缺点:master宕机,导致消息少量丢失。

  4. 多master与多salve同步

    HA采用同步双写,只有主从双节点都写入成功才可以返回,

    优点:master宕机情况下,无消息丢失

    缺点:性能比异步低,

双主双从集群搭建

集群搭建流程

  1. 启动nameserver,Nameserver起来后监控端口,等待broker,producer,consumer连上来,相当于一个路由中心。
  2. broker启动后,跟所有nameserver保持长连接,定时发送心跳包。心跳包包含当前Broker信息(ip+端口等)以及存储所有topic信息。注册成功后,nameserver集群中就有topic跟broker的映射关系。
  3. 收发消息前,先创建Topic,创建topic时候需要指定topci要存储在哪些broker上,也可以在发送消息时自动创建topic。
  4. producer发送消息,启动时先和nameservr建立长连接,并从nameserverhz中获取当前发送的topic存在哪些broker上,轮询从列表队列中选择一个列,然后与队列所在的broker建立长连接从而向broker发送消息。
  5. consumer跟producer类似,跟其中一台nameserver建立连接,获取topic信息在哪些broker上,然后和broker建立连接,开始消费消息。

服务器环境:

序号IP角色架构模式
1192.168.25.135nameserver、brokerserverMaster1、Slave2
2192.168.25.138nameserver、brokerserverMaster2、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 &

消息发送

事务消息

流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lWnmYq6Z-1676276154211)(D:\MarkDownP\image-20230213083256696.png)]

事务消息大致大致方案,两个流程:正常事务消息的发送和提交,事务消息的补偿流程。

  1. 事务消息发送和提交

    • 发送消息
    • 服务端相应消息写入结果。
    • 根据发送结果,执行本地事务(如果写入失败,则本条half消息对外不可见,本地逻辑不执行。)
    • 根据本地事务状态执行commit或者rollback(commit操作生成消息索引,消息对消费者可见)
  2. 事务补偿

    • 对没有commit/rollback的事务消息,从服务端发起一次回查
    • producer收到回查消息,检查回查消息对应的本地事务状态。
    • 根据本地事务状态,重新commit或者rollback

    其中补偿阶段用于解决消息commit或者rollback发生超时或者失败的情况。

  3. 事务消息状态

    事务消息共有三种状态,提交状态,回滚状态,中间状态

    • TransactionStatus.CommitTransaction:提交事务,它允许消费者消费此消息。
    • TransactionStatus.RollbackTransaction:回滚事务,他代表消息即将被删除,不允许被消费
    • TransactionStatus.Unknown:中间状态,他代表需要检查消息队列来确定状态。

使用事务分两个步骤:

  1. 创建事务监听器,后续正常流程(创建消息生成者,设置mq地址,启动生产者,创建消息体,在消息体中写入消息,topic,tag等)
  2. 写一个TransactionListener的实现类,重写其方法完成事务的处理。
  3. 事务处理就是对其状态进行检查,如果为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处理消息流程:

  1. 消息生成者发送消息
  2. MQ收到消息,对消息进行持久化,在存储中新增一条记录
  3. 返回ack给生产者
  4. MQ push消息给对应消费者,然后等待消费者返回ack
  5. 如果消费者在指定时间内没有返回ack,那么MQ则认为消息没有消费成功,在存储中删除消息,即执行第六步;如果MQ在指定时间内没有收到ack,则认为消息消费失败,会尝试重新push消息,重复执行4、5、6步骤
  6. MQ删除消息

存储介质

  • 关系型数据库DB

    由于普通关系型数据库在单表数据量达到千万级别的情况下,其IO读写性能往往会出现瓶颈。在可靠性方面,该种方案非常依赖 DB,如果一旦DB出现故障,则MQ的消息就无法落盘存储导致线上故障。

  • 文件系统

    目前业界较为常用的几款产品(RocketMQ/Kafka/RabbitMQ)均采用的是消息刷盘至所部署虚拟机/物理机的文件系统来做持久化

性能对比:文件系统>关系型数据库

消息存储结构:

RocketMQ消息存储是由ConsumeQueue和CommitLog配合完成的,消息真正的物理存储文件时CommitLog,ConsumerQueue是消息的逻辑队列,类似数据库的索引文件,存储的是指向物理存储的地址。每个Topic下的每个Message Queue都有一个对应的ConsumeQueue文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QIRayThw-1676276154212)(D:\MarkDownP\image-20230213105145909.png)]

  • 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不会立刻将消息丢弃,而是将消息发送到消费者对应的特殊队列中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值