RocketMQ 内部是怎么实现半消息的 Published on Apr 22, 2026 in 随笔 with 0 comment 极简版(30秒) “RocketMQ 实现半消息的关键是:发送时把 Topic 临时换成系统 RMQ_SYS_TRANS_HALF_TOPIC,让消息对消费者不可见;通过二次确认写入 Op 消息来标记最终状态;如果二次确认丢失,后台定时任务会回查生产者,根据本地事务结果决定提交还是回滚。这样就实现了分布式事务的最终一致性。” 加分项(如果有时间) “另外,RocketMQ 的这个设计相比其他方案有几个优势: 不依赖外部存储(比如数据库),完全基于自身的 CommitLog,性能好 高可用:半消息同样支持同步复制,主从切换不会丢 回查机制:避免了生产者宕机导致的消息悬空” 建议你把这个回答背熟,面试时先讲“三个关键点”,如果面试官感兴趣再展开细节。 追问 你的回答 半消息存储在哪个文件里? 和其他普通消息一样,都是顺序写入 CommitLog 文件。只是它的 Topic 被改成了 RMQ_SYS_TRANS_HALF_TOPIC。 Op 消息有什么用?为什么不直接删掉半消息? Op 消息是用来标记状态的。因为半消息存在 CommitLog 里,物理删除很麻烦,用 Op 消息做一个“标记删除”,回查时只需要检查有没有 Op 消息就知道是否已处理过。 回查时生产者的 checkLocalTransaction 方法里要做什么? 根据消息中的业务 ID(比如 orderId)去数据库查询本地事务是否成功,然后返回 COMMIT 或 ROLLBACK。这个方法必须幂等,因为可能被多次调用。 如果生产者一直不回查怎么办? RocketMQ 默认回查 15 次,总时长约 12 小时。超过后消息会被自动回滚(丢弃)。 半消息会不会导致磁盘占用无限增长? 不会。一旦确定了最终状态(commit 或 rollback),RocketMQ 会定期清理这些已经完成事务的半消息。 RocketMQ 半消息的实现,关键在于它基于两阶段提交(2PC)思想,并巧妙地复用了自身架构,用三个核心组件配合,解决了分布式事务的难题: 存储与隔离:使用特殊 Topic 和 Op 消息存储半消息与状态变更。 状态追踪:通过 Op 消息记录最终状态,解决“悬空”消息问题。 最终一致性:依靠 Broker 主动回查机制,确保事务状态最终确定。 sequenceDiagram participant P as Producer participant B as Broker participant C as Consumer Note over P,C: 阶段一:发送半消息 P->>B: 1. sendMessage (TRAN_MSG) B-->>P: 2. 返回ACK Note over B: 3. 消息写入RMQ_SYS_TRANS_HALF_TOPIC(替换原Topic/Queue) Note over P,C: 阶段二:执行本地事务 P->>P: 4. executeLocalTransaction alt 本地事务成功 P->>B: 5. commit (END_TRANSACTION) else 本地事务失败 P->>B: 5. rollback (END_TRANSACTION) else 本地事务未知 P->>B: 5. unknown (END_TRANSACTION) end Note over P,C: 阶段三:Broker处理二次确认 alt 收到commit Note over B: 6. 写入Op消息至RMQ_SYS_TRANS_OP_HALF_TOPIC7. 恢复原Topic/Queue B-->>C: 8. 消息投递 else 收到rollback Note over B: 6. 写入Op消息7. 标记忽略 else 未知或超时 Note over B: 6. 定时任务回查(TransactionalMessageCheckService) B->>P: 7. checkLocalTransaction P-->>B: 8. commit/rollback Note over B: 9. 更新Op消息并处理消息 end 本文由 admin 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。