RocketMQ事务消息通过两阶段提交(半消息+本地事务)与回查机制解决“本地业务操作”和“消息发送”的最终一致性:第一阶段发半消息至RMQ_SYS_TRANS_HALF_TOPIC并标记PREPARED;第二阶段生产者执行本地事务后返回COMMIT/ROLLBACK,Broker据此投递或丢弃;若超时未响应,Broker按默认6秒起、60秒间隔、最多15次触发checkLocalTransaction回查,生产者须幂等实现并返回明确状态。

RocketMQ 生产者事务消息处理机制,核心是解决“本地业务操作”和“消息发送”之间的原子性问题。它不依赖数据库XA或强一致2PC,而是用轻量、异步、可回查的方式达成最终一致性。
事务消息的两阶段流程
整个过程分为明确的两个阶段,中间无阻塞等待:
-
第一阶段:发半消息(Half Message)——生产者调用
sendMessageInTransaction(),Broker 接收后不投递给消费者,而是将消息存入系统主题RMQ_SYS_TRANS_HALF_TOPIC,状态标记为PREPARED; -
第二阶段:执行并上报结果——生产者同步执行本地事务(如扣库存、写订单),通过
LocalTransactionExecuter返回COMMIT_MESSAGE或ROLLBACK_MESSAGE;Broker 根据该结果决定将消息转投目标 Topic 或直接丢弃。
事务状态回查(Check)机制
回查不是可选补充,而是保障高可用的兜底手段。当生产者因宕机、网络中断等原因未及时返回结果时,Broker 会主动发起校验:
- 默认在半消息写入后 6秒(
transactionTimeout=6000)开始首次扫描; - 按固定间隔(
transactionCheckInterval=60000)重复检查,最多尝试 15次(transactionCheckMax=15); - 每次回查会触发生产者实现的
checkLocalTransaction()方法,需根据事务ID或消息Key查询本地数据库/日志,真实还原事务终态。
生产者端关键实践要点
要让事务消息真正可靠,光走通流程远远不够,以下几点必须落实:
- 使用
TransactionMQProducer实例,而非普通DefaultMQProducer; - 本地事务逻辑必须是幂等且可重入的,避免回查时重复执行造成数据错乱;
- 半消息的
transactionId应与业务主键(如订单号)绑定,并写入本地事务日志,便于回查准确定位; - 回查接口中禁止抛异常,必须返回明确的
COMMIT、ROLLBACK或UNKNOW;返回UNKNOW会让 Broker 继续重试,直到达到最大次数后强制回滚。
典型失败场景与应对
实际运行中最容易出问题的几个点:
- 本地事务成功但未返回 COMMIT → 半消息长期滞留,触发回查;若回查逻辑没查到记录,可能误判为 ROLLBACK,导致下游漏消费;
- 回查时数据库不可用 → 必须降级为缓存查日志、或从消息体解析业务标识做轻量判断,不能直接 throw Exception;
- 事务监听器未正确注册或启动失败 → 消息发出去就卡在 PREPARED 状态,所有后续操作失效;上线前务必验证监听器是否被加载。

















