面试知识库
进阶

RocketMQ事务消息#

一句话答案#

RocketMQ 事务消息通过半消息(Half Message)机制保证本地事务和消息发送的原子性:先发半消息 → 执行本地事务 → 成功 Commit / 失败 Rollback → Producer 宕机时 Broker 主动回查。

核心要点

流程#

1. Producer 发送半消息(Half Message)→ Broker 暂存,Consumer 不可见
2. Broker 返回发送成功
3. Producer 执行本地事务
   ├── 成功 → 发送 Commit → Broker 投递给 Consumer
   └── 失败 → 发送 Rollback → Broker 丢弃半消息
4. 如果 Producer 没发 Commit/Rollback(宕机/网络异常)
   → Broker 定时回查 Producer 的本地事务状态(最多 15 次)
   → 根据查询结果 Commit 或 Rollback
plaintext

半消息为什么消费不到(可见性机制,易讲偏)#

关键:半消息照常写入 CommitLog(和普通消息存在同一个物理文件里),消费不到不是因为没落盘,而是因为没有建到目标 Topic 的消费索引

  • 发半消息时,RocketMQ 会备份原始 Topic/QueueId,然后把消息的 Topic 替换成内部 Topic RMQ_SYS_TRANS_HALF_TOPIC,再写入 CommitLog。
  • ConsumeQueue(消费索引)是按 Topic 建的。半消息只建了 RMQ_SYS_TRANS_HALF_TOPIC 的 ConsumeQueue,没有建目标 Topic 的 ConsumeQueue 索引 → 消费者订阅的是目标 Topic,扫不到这条记录,所以「不可见」。
  • Commit 时才真正投递:Broker 从半消息恢复出原始 Topic/QueueId,把消息重新写一条到 CommitLog 并建目标 Topic 的 ConsumeQueue 索引,消费者这时才能拉到。
  • Op 消息记状态:commit/rollback 都会向另一个内部 Topic RMQ_SYS_TRANS_OP_HALF_TOPIC 写一条 Op 消息,标记「这条半消息已处理(已决)」。Rollback 本质就是只写 Op 标记、不投递到目标 Topic。
  • 回查靠对比:定时任务遍历 Half Topic 里的半消息,逐条到 Op Topic 里查是否已有对应的「已决」标记;没有 Op 标记的就是未决半消息,对它们发起回查 checkLocalTransaction

回查机制#

  • Broker 对未决事务消息定时回查(默认 60 秒一次)
  • Producer 需实现 TransactionListener.checkLocalTransaction() 接口
  • 返回 COMMIT / ROLLBACK / UNKNOWN
  • UNKNOWN → 继续下次回查,最多回查 15 次,超过默认回滚

与本地消息表对比#

维度事务消息本地消息表
额外表不需要需要 message 表
轮询Broker 自动回查需要定时任务轮询
侵入性低(实现 Listener)中(维护表 + 定时任务)
依赖依赖 RocketMQ任意 MQ 都可
面试回答(2分钟版)

RocketMQ 事务消息通过半消息机制解决了本地事务和消息发送的原子性问题。流程分三步:第一步 Producer 发送半消息到 Broker,这条消息对 Consumer 不可见,暂存在内部 Topic RMQ_SYS_TRANS_HALF_TOPIC;第二步 Producer 执行本地事务,成功则发送 Commit 让 Broker 把消息投递给 Consumer,失败则发送 Rollback 让 Broker 丢弃。关键的安全网是回查机制:如果 Producer 宕机或网络异常导致既没 Commit 也没 Rollback,Broker 会定时回查 Producer 的本地事务状态,默认 60 秒一次最多回查 15 次,超过仍未决则默认回滚。Producer 需要实现 TransactionListener 接口的 checkLocalTransaction 方法来支持回查。和本地消息表方案相比,事务消息不需要额外维护消息表和定时轮询任务,侵入性更低,但依赖 RocketMQ 的支持。需要注意的是事务消息只保证最终一致性不是强一致性,Consumer 端仍然可能重复消费,必须做好幂等处理。

追问与易错

追问方向:

  • “回查失败怎么办?”→ 最多 15 次,超过默认回滚 + 告警
  • “Kafka 有类似机制吗?”→ Kafka 事务面向流处理(Exactly-Once),不直接支持半消息回查

易错点:

  • ❌ “事务消息保证强一致”——只保证最终一致
  • ❌ “不需要幂等”——Consumer 仍可能重复消费,必须幂等