RocketMQ核心内容

一、消息队列典型的应用场景

1、系统解耦

场景说明---当用户下单时,订单系统通知库存系统完成后续操作。

订单系统:用户下单后,订单系统完成内部处理流程,将消息投递至MQ,返回用户下单成功。

库存系统:订阅MQ的消息,进行库存扣减等操作。即使在用户下单时库存系统宕机,也不影响用户完成下单流程,实现订单系统与库存系统的解耦。

2、流量削峰

场景说明:秒杀活动,面对用户高并发同步请求,应用存在宕机风险,如图2所示。


秒杀业务系统收到用户请求后,首先将请求写入消息队列,然后根据自己的处理能力拉取消息进行处理。

二、RocketMQ整体架构

RocketMQ的整体架构主要包含服务发现、生产者、Broker集群和消费者,如图3所示。


Name Server:Broker向NameServer注册路由,NameServer为生产者、消费者提供最新的路由信息。
Broker:负责消息的持久化存储、消息的HA机制以及服务器端消息过滤等功能。一个Master Broker可以有多个Slave Broker,一个Slave Broker只能有一个Master Broker。Broker启动后将自己注册到Name Server,定期向Name Server上报Topic路由信息。
Producer:生产者与Name Server集群中的某个节点(随机)建立长连接,定期从Name Server读取Topic路由信息,并与提供Topic服务的Master Broker建立长连接,且定时向Master Broker发送心跳。
Consumer:消费者与Name Server集群中的某个节点(随机)建立长连接,定期从Name Server拉取Topic路由信息,并与提供Topic服务的Master Broker、Slave Broker建立长连接,且定时向Master Broker、Slave Broker发送心跳。Consumer既可以从Master Broker订阅消息,也可以从Slave Broker订阅消息。

三、RocketMQ消息发送与消费流程

消息发送与消费流程如下:首先生产者发送的消息被顺序写入CommitLog,如图4所示。此处在写CommitLog时使用PageCache会非常高效。

然后,CommitLog日志消息被异步转发到对应的逻辑队列(ConsumeQueue),如图5所示。


ConsumeQueue与Paratiton的概念相对应,并且转发至ConsumeQueue中的消息也是顺序写入的,消费者可以从ConsumeQueue中拉取消息进行消费,如图6所示。从旧到新顺序拉取消息,这里也可以使用PageCache。ConsumeQueue与消费者组中消费者数量的增多会显著提高消费速度。消费者直接和逻辑队列接触而不是commitlog。


ConsumeQueue消息结构包含三个部分:消息在CommitLog中的物理位置偏移量offset、消息实体内容的大小和Message Tag的hash值。我们可以根据offset定位消息在CommitLog文件中的具体位置,该过程是随机读,如图7所示。

虽然多个队列共享 CommitLog 导致回读是逻辑随机读,但只要写入与消费节奏相近,物理读取区域会高度集中,从而充分利用 PageCache,效果接近顺序读。

四、消息类型:顺序消息、延迟消息、事务消息 、死信消息

1、顺序消息

全局顺序消息

全局顺序消息如图9所示,对于一个指定的Topic,所有消息严格按照先入先出(FIFO)的顺序进行发布和消费,此时使用一个队列保证全局顺序会存在严重的性能瓶颈。

分区顺序消息

一般场景下,不要求消息的全局顺序,例如一个订单产生了3条消息,分别是订单创建、付款、完成,消费时同一个订单要按照这个顺序消费才有意义,但是不同订单之间是可以并行消费的。分区顺序消息如图10所示,对于一个指定的Topic,所有消息根据sharding key进行分区(比如按照订单id)。同一个分区内的消息严格按照FIFO顺序进行发布和消费(由于是根据订单id分区的,因此同一个订单的创建、付款、完成消息会出现在同一个队列里并保持顺序性)。图10中的sharding key是顺序消息中用来区分不同分区的关键字段。

为了保证消费端的顺序性,某条消息消费失败会阻塞后续消息的消费。

2、延迟消息

延迟消息是指生产者发送消息后,需要等待指定的时间才可以被消费。

延迟消息典型应用场景举例:用户下单后需要在30分钟内付款,到期前发送消息提醒用户支付。

RocketMQ延迟消息在Broker内部的处理流程如图11所示。


(1)消息发送时修改Topic名称和队列信息。消息一旦由CommitLog转发到ConsumeQueue就会被立即消费,为了避免延迟消息被立即消费,发送消息时将主题的名称修改为特定Topic (SCHEDULE_TOPIC_XXXX),并根据延迟级别确定投递的队列。同时消息相关属性里保存了要投递的目标Topic和队列信息。

(2)转发消息到延迟主题的CosumeQueue中。消息写入CommitLog后会转发到CosumeQueue,计算延迟消息投递时间,投递时间=消息存储时间+延迟级别对应的时间,将它作为消息Tag的哈希值存储到CosumeQueue中。

(3)延迟服务消费SCHEDULE_TOPIC_XXXX消息。ScheduleMessageService消费SCHEDULE_TOPIC_XXXX中的消息,并投递到目标Topic中。ScheduleMessageService根据延迟级别的个数启动对应数量的TimerTask,每个TimerTask负责一个延迟级别的消息消费与投递,根据Tag值判断对应队列的第一个消息是否到期,若到期则进行投递,并继续检查之后的消息,若当前消息未到期则不再检查后续消息。

(4)到期消息重新写入CommitLog。消息到期后,需要投递到目标Topic,由于第一步记录了目标Topic和队列信息,因此重新设置后直接消息存储到CommitLog即可。

(5)CommitLog消息转发至目标Topic下的CosumeQueue,被消费者消费。消息的Topic被重置后写入CommitLog,转发至CosumeQueue后会被消费者直接消费。

3、事务消息

1、MQServer将消息持久化后返回发送方ACK,确认消息发送成功,此时消息为半消息。

2、发送方执行本地事务。

3、发送方根据本地事务执行结果向MQ Server提交Commit或Rollback,若MQ Server 收到Commit则将半消息标记为可投递,订阅方可消费到该消息;若MQServer收到Rollback则删除半消息,订阅方将不会消费该消息。

4、在网络中断、服务重启等特殊情况下,步骤04提交的Commit或Rollback未能到达MQServer,经过固定时间后MQServer将对该消息发起回查。

5、发送方收到消息回查后,检查对应消息的本地事务执行的最终结果。发送方根据本地事务执行的最终结果再次Commit或Rollback,MQServer仍按照步骤04对半消息进行处理。

4、死信消息

一条消息在达到最大重试次数后仍然消费失败,就会进入死信队列(DLQ)。死信队列里的消息默认不会再被自动消费,需要人工干预。

五、消费者、消费者组、队列之间的关系

当使用集群消费模式时,RocketMQ的一条消息只被集群内的任意一个消费者处理。

规则如下-----
1、一个队列同一时间只允许被消费者组下的某一个消费者消费。
2、消费者组下的某个消费者,可以同时消费同一个Topic下不同队列的消息。

3、不同消费者组下的消费者,可以同时消费同一个Topic下相同队列的消息。

相关推荐
摇滚侠1 天前
RocketMQ 教程丨深度掌握 MQ 消息中间件,笔记 39-44
笔记·rocketmq
心雨⁢⁢⁣1 天前
RocketMq(Apache RocketMQ 5.2.1-SNAPSHOT)消息消费流程
apache·rocketmq·java-rocketmq
予枫的编程笔记4 天前
【Kafka基础篇】RabbitMQ、RocketMQ、Kafka怎么选?3种主流MQ核心差异实测解析
kafka·rabbitmq·rocketmq·分布式流处理·发布订阅模型·消息队列(mq)·点对点模型
qq_297815276 天前
Docker Compose 部署 RocketMQ 5.4.0 完整指南(Windows Docker Desktop 专属)
windows·docker·rocketmq
愿你天黑有灯下雨有伞14 天前
高效异步处理:基于RocketMQ的延迟消费系统架构全解析
系统架构·rocketmq
堕落年代15 天前
RocketMQ 5.x + Spring Boot 发送消息失败全解析
spring boot·rocketmq·java-rocketmq
三水不滴15 天前
深度分析RocketMQ 消息重试(重读)机制
rocketmq
三水不滴15 天前
深度分析 RocketMQ 幂等性设计与生产级实现方案
后端·rocketmq·设计
三水不滴15 天前
深度分析:RocketMQ 如何保证消息不丢失 —— 全链路防丢机制与生产实践
rocketmq