RocketMq | 概念 - [消息 & 类型]

消息:message

消息类型:messageType

rocketMq 支持 4 种消息类型:

  • 普通
  • 顺序
  • 延时(4.x)/定时(5.x)
  • 事务

4.x 下,消息队列与消息类型并不是强校验关系,队列中可以存在不同类型的消息
5.x 开始,消息队列与消息类型开始进行强校验(默认如此,也可以配置关闭以兼容 4.x)

普通消息:Normal

普通消息的全称是 普通顺序消息,Normal Ordered Message

顺序消息:FIFO

强调 消费顺序 的消息类型,全称 严格顺序消息,Strictly Ordered Message
rocketMq 的顺序消费最终是依靠消息队列的存储有序性实现的

  • 4.x 下,消息通过 ShardingKey,但实际上是通过 MessageQueueSelector.select 的返回指定消息队列
  • 5.x 下,消息通过 MessageGroup 间接指定消息队列

实际上就是将希望顺序消费的消息,顺序的存储在某个消息队列下,然后因一个队列只能被一个消费者消费自动被顺序消费

  • 4.x 下,一个消息队列只能被一个消费者消费
  • 5.x 下,对消费者负载均衡策略进行了区分
    • 队列粒度负载均衡:即 5.x 之前的模式,一个消息队列只能被一个消费者消费
    • 消息粒度负载均衡:一个消息队列可以被多个消费者消费
      • 但是,顺序消息下,会严格按照先后顺序锁定消息状态
      • 即,队列 A 中消息 1 由消费者 1 消费,消息 2 由消费者 2 消费,但只要消息 1 的消费没有提交,消息 2 就不会被消费
      • 即,此场景下多个消费者实际上没有并发度,这些消费者逻辑上等同于一个消费者

重头梳理完整的思路(在 rocketMq 其他设计不变的情况下)

  • 整体的过程是:顺序投递(按序交给mq)、顺序存储、顺序消费(按序开始)、串行消费(按序完成)
  • 如果我们想要按照顺序消费消费一组消息,必须满足两个条件
    • 串行消费:消费的时候没有并发度,消费了已经拿到的消息才能去消息下一个
    • 顺序消费:按顺序拿到需要消费的消息
  • rocketMq 通过消费者负载均衡策略实现串行消费(更具体信息见上文)
    • 队列粒度下,一个消息队列只能被一个消费者消费(不考虑消费时自开多线程的智熄操作)
    • 信息粒度下,虽然一个消息队列可以被多个消费者消费,但受消息状态锁定,等同于只能被一个> 消费者消费
  • rocketMq 通过顺序存储实现顺序消费
    • 只要消息按正确的顺序存储在单个消息队列中,消费者自然会按顺序开始消费(这里说的是开始消费,不等于按顺序消费完)
  • rocketMq 依赖顺序投递实现顺序存储
    • 生产者投递时,通过指定 ShardingKey/MessageGroup 保证将需要顺序的消费放入同一个消息队列
    • rocketMq 本身就支持顺序存储,但是是按接收到消息的顺序进行顺序存储,因此需要依赖投递的顺序
  • rocketMq 的顺序投递只能通过 client 实现
    • 需要按顺序生产消息,并通过唯一的 producer 单线程发送

定时/延时消息:Delay

强调延后投递时机的消息类型
Delay 消息在 4.x/5.x 中有明显的差异

  • 4.x 下,Delay 是延时消息,消费发送时根据 18 个延时级别决定实际投递时机
  • 5.x 下,Delay 是定时消息,消息发送时直接指定投递时间,rocketMq 会按此时间进行实际投递
    • 可以通过将投递时间指定为延时后时间,来实现原延时消息的功能
      识别消息类型
  • 4.x 下,基于 DELAY 属性
  • 5.x 下,基于 __STARTDELIVERTIME 属性

延时原理(4.x)
延时消息是通过将消息暂存,并在延时结束后二次投递到真实 topic 实现的
rocketmq 为延时消息专门准备了一个固定的 topic:SCHEDULE_TOPIC_XXXX
[图片]
broker 接收到消息后,会判断延时级别,如果级别 > 0,就先把消息放到这个 topic,原消息放入 > properties
相关代码见 org.apache.rocketmq.store.CommitLog#asyncPutMessage
if (msg.getDelayTimeLevel() > 0) {
//...其他逻辑略
topic = TopicValidator.RMQ_SYS_SCHEDULE_TOPIC;
//...
}
这样,真实 topic 下就不会实际存储这条消息,消费者也就不会消费
SCHEDULE_TOPIC_XXXX 具有 18 个消息队列,对应 18 个延时级别,相当于 18 个独立的定时桶
每个桶独立计算延时,当延时结束时,消息会从 SCHEDULE_TOPIC_XXXX 二次投递到真正的 topic,此时消费者可以消费,完成延时

定时原理(5.x)
https://juejin.cn/post/7265183486418927674
rocketmq 5.x 的定时消息与 4.x 的延时消息差别极大,
rocketmq 5.x 启用了独立于 commitlog 之外的文件存储定时消息,即 timerlog
依然使用了一个 rmq_sys_wheel_timer 队列进行二次投递,设置了 3 个队列配合时间轮服务于这个过程

整体流程如下图所示
[图片]

事务消息:Transaction

强调按本地事务状态决定投递时机的消息类型
相当于把本地消息表集成到mq
单独课题,后面再说

posted @ 2025-06-27 16:59  问仙长何方蓬莱  阅读(33)  评论(0)    收藏  举报