面试专题

RocketMQ 都有哪些消息类型?使用场景是什么?

系统介绍 RocketMQ 5.x 的普通消息、顺序消息、定时与延时消息、事务消息,说明各自语义、适用场景、使用限制,并澄清批量消息、重试消息和死信消息是否属于消息类型。

难度:进阶更新:2026-07-26

RocketMQ 都有哪些消息类型?使用场景是什么?

面试回答

RocketMQ 5.x 按消息的传输语义正式分为四种类型:

  1. 普通消息 Normal:没有顺序、定时或事务等特殊语义,发送成功后即可被消费,适合微服务解耦、异步通知、日志和数据集成。
  2. 顺序消息 FIFO:同一 Message Group 内的消息按照发送、存储和投递顺序处理,适合同一订单的创建、支付、发货等状态流转,以及 Binlog 增量同步。
  3. 定时与延时消息 Delay:消息到指定时间后才对消费者可见,适合订单超时关闭、延迟检查、定时通知和任务调度。
  4. 事务消息 Transaction:通过半事务消息、本地事务确认和事务回查,保证本地事务与消息发送的最终一致性,适合下单后发放积分、扣款后发送通知等场景。

RocketMQ 5.x 可以为 Topic 声明消息类型,一个 Topic 只应承载一种消息类型。批量消息属于发送方式,重试消息和死信消息属于消费失败后的系统处理状态,Request-Reply 属于通信模式,它们都不属于上述四种正式 MessageType。

一句话总结:

无特殊要求用普通消息;同一业务实体需要按序处理用 FIFO;需要未来触发用 Delay;本地事务必须和消息发送保持最终一致用 Transaction。

一张图看懂

RocketMQ 四种消息类型、核心语义、典型场景及选择方法

详细讲解

一、先明确 RocketMQ 的正式分类

RocketMQ 5.x 定义了四种 MessageType:

消息类型核心语义典型场景
NORMAL发送后立即进入可消费状态异步解耦、事件通知、日志传输
FIFO同一 Message Group 内按顺序处理订单状态流转、Binlog 同步
DELAY到指定时间后才允许消费超时关闭、延迟检查、定时任务
TRANSACTION本地事务与消息发送最终一致交易完成后驱动下游业务

这四种类型不是按照消息内容划分,而是按照消息需要具备的传输和投递语义划分。

例如,同样是“订单创建”事件:

  • 创建后立即异步通知风控,可以使用普通消息;
  • 必须与后续支付、发货事件保持同一订单内的顺序,可以使用顺序消息;
  • 创建三十分钟后检查是否支付,可以使用延时消息;
  • 只有订单数据库事务成功后才能向下游投递,可以使用事务消息。

因此,消息类型的选择取决于业务语义,而不是消息中装了什么数据。

二、普通消息 Normal

1. 什么是普通消息

普通消息没有顺序、定时和事务等特殊语义。Broker 接收并保存消息后,消息进入 Ready 状态,Consumer 可以正常获取并处理。

Producer
   │ 发送
   ▼
Broker 持久化
   │ 立即可见
   ▼
Consumer 消费

“普通”不代表不可靠。普通消息同样可以使用发送确认、Broker 持久化、消费重试、死信队列和业务幂等机制。

它只表示:

消息之间没有需要 RocketMQ 额外维护的顺序、时间或事务关系。

2. 适用场景

普通消息适合绝大多数异步业务:

  • 微服务之间异步解耦;
  • 用户注册后异步发送欢迎短信;
  • 订单创建后异步更新搜索索引;
  • 操作日志、埋点和审计事件传输;
  • 缓存失效通知;
  • 数据采集和数据集成;
  • 不要求严格顺序的业务事件广播。

例如,订单创建后需要通知多个独立系统:

订单服务
   │
   └── OrderCreated 普通消息
           ├── 风控服务
           ├── 推荐服务
           └── 数据分析服务

这些下游之间不存在必须先后执行的关系,使用普通消息能够获得更好的并发能力。

3. 不适合的场景

以下要求不能只依赖普通消息:

  • 同一订单的支付必须在创建之后处理;
  • 消息必须在未来某个时间触发;
  • 本地数据库事务失败时消息绝对不能对下游可见。

这时应分别考虑 FIFO、Delay 或 Transaction。

三、顺序消息 FIFO

1. 顺序消息保证什么

RocketMQ 5.x 使用 Message Group 标识需要保持顺序的一组消息。同一个 Message Group 中的消息按照先进先出顺序处理。

例如以订单号作为 Message Group:

Message Group = order-1001

创建订单 → 支付成功 → 仓库出库 → 物流发货

另一个订单可以使用不同的 Message Group:

order-1001:创建 → 支付 → 发货
order-1002:创建 → 取消

两个订单之间不要求顺序,可以并发处理;同一订单内部保持顺序。这通常称为局部顺序分组顺序

2. 为什么不追求整个 Topic 的全局顺序

如果一个 Topic 的全部消息都要求全局顺序,就只能把所有消息串行发送、存储和消费,并发能力会受到严重限制。

按订单号、用户 ID、账户 ID 等业务键划分 Message Group,可以做到:

组内有序
+
组间并行

这更符合大多数业务的真实要求。

3. 保证顺序需要满足哪些条件

完整的顺序需要覆盖三个阶段。

发送顺序

同一 Message Group 的消息需要由生产端按业务顺序串行发送。如果多个线程或多个生产者同时发送,即使 Message Group 相同,RocketMQ 也无法推断业务上谁应该在前。

存储顺序

RocketMQ 将同一 Message Group 的消息存入同一个队列,并保持接收顺序。

消费顺序

Consumer 必须遵循“接收、处理、确认”的顺序。不能收到消息后随意提交给异步线程并立即确认,否则业务实际完成顺序仍可能被打乱。

发送有序
   ↓
存储有序
   ↓
投递有序
   ↓
业务处理有序

4. 适用场景

  • 同一订单的创建、支付、取消和发货;
  • 同一账户的充值、扣款和退款;
  • 同一用户的状态变更;
  • 数据库 Binlog 增量同步;
  • 工作流节点推进;
  • 交易撮合等要求按到达顺序处理的场景。

5. 使用代价与风险

顺序消息会牺牲部分并发能力,并且前面的消息处理失败时,后续消息可能等待。

需要重点关注:

  • Message Group 是否过热;
  • 单条消息是否持续重试并阻塞后续消息;
  • 消费逻辑是否包含慢 SQL、慢 RPC;
  • 是否错误地在消费端进行异步并发处理;
  • 是否真的需要顺序,还是使用状态机和幂等就能解决。

不要把所有消息都设置为同一个 Message Group,否则会把系统退化成串行消费。

四、定时与延时消息 Delay

1. 定时消息和延时消息有什么区别

业务表达方式不同,但在 RocketMQ 5.x 中本质相同:都是设置一个未来的投递时间戳。

延时消息:10 分钟后投递
定时消息:2026-07-26 18:00:00 投递

延时消息也需要先计算出最终投递时间:

long deliveryTimestamp =
        System.currentTimeMillis() + Duration.ofMinutes(10).toMillis();

2. 消息生命周期

Producer 发送
      ↓
Timing:Broker 按时间暂存
      ↓ 到达投递时间
Ready:转入普通存储并对 Consumer 可见
      ↓
Consumer 消费并确认

消息到达 Broker 并不代表 Consumer 立即可见。只有达到投递时间,消息才进入可以消费的状态。

3. 适用场景

  • 订单创建三十分钟后检查是否支付;
  • 支付处理中,五分钟后查询渠道结果;
  • 优惠券到期提醒;
  • 用户预约通知;
  • 延迟重试;
  • 定时清理任务;
  • 分布式定时调度。

例如订单超时关闭:

创建订单
   │
   ├── 写入订单数据
   └── 发送 30 分钟后投递的 Delay 消息
                         ↓
                 Consumer 查询订单状态
                    ├── 未支付:关闭订单
                    └── 已支付:忽略消息

Consumer 收到延时消息后仍然必须重新检查业务状态。消息表达的是“现在应该检查”,不是“订单一定未支付”。

4. 延时消息不是精确定时器

设置的时间表示消息不应早于该时间被消费,但以下因素可能使实际处理晚于目标时间:

  • Broker 当前负载较高;
  • 大量消息设置了相同投递时间;
  • 消费端发生积压;
  • Consumer 执行较慢或暂时不可用;
  • 存储系统故障或重启。

因此,对秒级严格准点有强要求的业务不能只依赖消息到达时间,还要监控投递延迟并准备补偿扫描。

5. RocketMQ 4.x 与 5.x 的区别

RocketMQ 4.x 常见实现使用固定的延迟级别,例如:

1 秒、5 秒、10 秒、30 秒、1 分钟……

生产者通过 delayTimeLevel 选择预设级别。

RocketMQ 5.x 的正式 Delay 消息使用毫秒级 Unix 时间戳表示投递时间,不再局限于旧版固定延迟级别。面试时需要先说明讨论的是哪个版本,避免把 4.x 的十八个延迟级别直接当作 5.x 的唯一实现。

五、事务消息 Transaction

1. 事务消息解决什么问题

事务消息解决的是:

本地事务与消息发送之间的最终一致性。

例如订单服务需要同时完成:

  1. 在本地数据库创建订单;
  2. 向 RocketMQ 发送订单创建消息。

如果先提交数据库再发送消息,数据库成功后消息可能发送失败;如果先发送消息再写数据库,消息可能已被消费,但数据库事务最终失败。

数据库事务成功,消息失败  → 下游永远不知道订单已创建
消息发送成功,数据库失败  → 下游处理了一笔不存在的订单

2. 核心流程

Producer 发送 Half Message
           ↓
Broker 保存消息,但暂不向 Consumer 投递
           ↓
Producer 执行本地事务
       ┌───┴────────┐
       │            │
    Commit       Rollback
       │            │
消息可见并投递    消息回滚

如果 Broker 长时间没有收到明确结果,会回查 Producer:

Broker 发起事务回查
          ↓
Producer 查询本地事务记录
     ┌────┼─────┐
  Commit Unknown Rollback

Producer 的事务回查不能只依赖内存变量,需要根据订单表、事务日志或本地 Outbox 等持久化数据判断。

3. 适用场景

  • 订单创建成功后通知库存、积分系统;
  • 扣款成功后发送账务事件;
  • 账户入账成功后通知下游;
  • 数据库状态变化后更新搜索索引;
  • 本地事务成功后驱动跨服务异步流程。

4. 事务消息不保证什么

事务消息保证的是本地事务与消息是否投递之间的最终一致性,不等于整个分布式业务已经成功。

例如:

订单本地事务成功
       ↓
事务消息 Commit
       ↓
积分服务消费失败

RocketMQ 可以重试投递,但积分服务仍需实现:

  • 消费幂等;
  • 失败重试;
  • 死信处理;
  • 对账与补偿;
  • 业务状态机。

事务消息也不是跨多个数据库的强一致分布式事务。它更适合能够接受异步执行和最终一致性的业务。

六、四种消息类型如何选择

可以按照下面的顺序判断:

本地事务是否必须与消息发送保持最终一致?
    ├── 是 → Transaction
    └── 否
         ↓
消息是否需要到未来某个时间才可消费?
    ├── 是 → Delay
    └── 否
         ↓
同一业务实体的事件是否必须按顺序处理?
    ├── 是 → FIFO
    └── 否 → Normal

对应关系:

业务要求推荐类型关键设计点
只需要可靠异步传输Normal重试、幂等、监控
同一订单内有先后关系FIFOMessage Group、串行处理
未来某个时间触发Delay投递时间、状态复查、延迟监控
本地事务成功后才能投递TransactionHalf Message、事务回查、持久化事务状态

不要因为高级消息类型“功能更多”就默认使用。每种特殊语义都会增加约束、运维成本或吞吐损耗;没有特殊要求时,普通消息通常是更简单的选择。

七、这些算不算消息类型

1. 批量消息

批量消息不是独立 MessageType,而是一种发送或消费方式。

单条发送:一次请求发送一条消息
批量发送:一次请求携带多条消息

批量能够减少网络往返和请求开销,适合日志采集、数据同步等吞吐优先的场景,但需要注意:

  • 控制整个批次的大小;
  • 批次失败后的重试粒度;
  • 顺序消息不应随意并行批处理;
  • 批量消费部分成功时的幂等和重试问题。

2. 重试消息

重试消息是普通消息、FIFO 消息等消费失败后,RocketMQ 根据消费重试策略重新投递形成的系统处理过程,不是业务创建 Topic 时选择的正式 MessageType。

第一次消费失败后,消息可能经历:

Ready → Inflight → WaitingRetry → Ready

Consumer 必须按消息可能重复投递来设计幂等。

3. 死信消息

消息超过最大消费重试次数后,可能进入死信队列。死信消息代表消息进入异常隔离状态,也不是四种正式业务 MessageType 之一。

死信队列需要配套:

  • 告警;
  • 失败原因记录;
  • 人工检查;
  • 修复后的重投;
  • 对账和业务补偿。

4. Request-Reply 消息

Request-Reply 是一种通信模式:

请求方发送消息
      ↓
处理方消费并返回响应
      ↓
请求方等待响应

它描述生产者和消费者如何交互,不属于 NORMALFIFODELAYTRANSACTION 之外的第五种正式 MessageType。

5. 同步、异步和单向消息

同步发送、异步发送和单向发送描述的是 Producer 调用发送接口的方式,也不是消息类型。

同步发送:等待 Broker 返回结果
异步发送:通过回调接收结果
单向发送:发送后不等待结果

不要把“发送方式”和“消息传输语义”混为一谈。

八、RocketMQ 5.x 为什么要求 Topic 类型一致

RocketMQ 5.x 支持在 Topic 上声明消息类型:

mqadmin updateTopic \
  -n <nameserver_address> \
  -t <topic_name> \
  -c <cluster_name> \
  -a +message.type=<NORMAL|FIFO|DELAY|TRANSACTION>

启用类型校验后,一个 Topic 只允许发送与其类型一致的消息。例如:

  • FIFO 消息不能发送到 NORMAL Topic;
  • TRANSACTION 消息不能发送到 DELAY Topic;
  • 同一个 Topic 不应同时承载普通消息和顺序消息。

这样做的价值是:

  • 让 Topic 的行为语义清晰;
  • 避免客户端误用高级消息能力;
  • 便于 Broker 按消息类型管理;
  • 降低运维和故障排查复杂度。

为了兼容旧客户端,5.x 的强制类型校验能力需要结合服务端配置判断。面试中可以说“5.x 支持并推荐一个 Topic 对应一种消息类型”,不要绝对化为所有兼容部署都默认强制拒绝。

九、常见追问

1. 普通消息一定无序吗

普通消息在某个物理队列中自然存在存储先后,但业务没有建立端到端 FIFO 约束。多队列发送、并发消费、失败重试都可能使业务完成顺序变化,因此不能依赖普通消息保证业务顺序。

2. 顺序消息能否保证整个 Topic 全局有序

实际通常保证同一 Message Group 内有序。理论上把所有消息放入一个组可以接近全局串行,但会形成热点并严重限制吞吐,不建议这样设计。

3. 延时消息到点后一定立即执行吗

不一定。到点表示消息可以进入可消费状态,Broker 调度延迟、消息积压和 Consumer 处理能力都会影响最终业务执行时间。

4. 事务消息消费成功是否与本地事务强一致

不是。事务消息只保证本地事务结果与消息是否投递之间的最终一致性。Consumer 的业务处理仍然是独立的异步过程,需要重试、幂等和补偿。

5. FIFO 和 Transaction 能否同时使用

从 RocketMQ 5.x 的 Topic 类型模型看,一个 Topic 只对应一种正式消息类型,不能把同一条消息同时声明为 FIFO 和 Transaction。业务同时需要“事务一致性”和“顺序处理”时,需要重新审视领域流程,常见做法是用事务消息可靠发布业务事件,再由下游状态机、版本号、业务序号或独立 FIFO 流程处理顺序要求。

十、容易答错的地方

错误一:RocketMQ 有五种消息,包含批量消息

批量是发送方式,不是 RocketMQ 5.x 的正式 MessageType。正式类型是 Normal、FIFO、Delay、Transaction。

错误二:顺序消息保证整个 Topic 全局有序

通常保证同一 Message Group 内的局部顺序,不同组之间允许并发。

错误三:延时消息到了时间就保证业务已经执行

到达投递时间只表示消息对 Consumer 可见,实际业务完成还受积压、消费能力和重试影响。

错误四:事务消息保证上下游所有业务一起提交

事务消息保证本地事务与消息投递最终一致,下游消费结果仍然需要独立保障。

错误五:普通消息可靠性低

普通消息只是没有高级传输语义,不代表不持久化、不重试或不可靠。

参考资料

DISCUSSION

评论与讨论

留下你的想法