跳转到内容

事务消息与回查

用途:把“本地事务 + 发消息”变成一个可靠动作

1 Producer 发送半消息(Half Message,对消费者不可见)
2 Broker 持久化半消息并返回成功
3 Producer 执行本地事务
4 Producer 根据结果提交(Commit → 消息可见)或回滚(Rollback → 删除半消息)
5 若第 4 步丢失(进程崩溃、网络断):Broker 定时回查 Producer
6 Producer 检查本地事务真实状态,返回 COMMIT / ROLLBACK / UNKNOWN

半消息存储:提交前写入事务主题(RMQTRANS-Half 类),提交时把消息真实写入目标队列,回滚则标记删除;回查频率与最大次数由配置控制。

回查必须基于持久化的本地事实判断,不能依赖内存:

本地事务状态 回查答复
业务表已有对应记录/状态已推进 COMMIT
明确失败或无记录且已过期 ROLLBACK
仍在执行中(无法判定) UNKNOWN(等待下次回查)

实现要点:为每个本地事务留下可查询痕迹(业务单据状态、事务状态表或幂等键表),回查时按消息里的业务键查询。

保证 不保证
本地事务提交 ⇒ 消息最终会可见(至少一次) 消费方一定成功处理(需消费重试 + 幂等)
本地事务回滚 ⇒ 消息不会被消费 端到端恰好一次
生产者崩溃后的悬置消息能被裁决 业务语义冲突(仍需对账)

与本地消息表(Outbox)的对比

「与本地消息表(Outbox)的对比」小节链接
维度 事务消息 Outbox
可靠性归属 Broker 自己的数据库
额外表与投递任务 不需要 需要
回查代码 必须正确实现 不需要
可审计/可重放 依赖消息轨迹 表内可查、可重放
换中间件的成本 语义依赖具体产品 与中间件解耦
多通道(HTTP 回调、多 MQ) 不适用 适用
  1. 本地事务里不能有远程调用:耗时会拉长回查窗口,且事务持锁。
  2. 业务表与事务状态必须同库,否则回查依据本身可能不一致。
  3. 回查次数上限要有告警:达到上限说明存在真实故障,需要人工介入而不是静默丢弃。
  4. 消费端幂等仍是必须:提交后消息仍会重复投递。
  5. 延迟消息、事务消息等特性在不同版本/发行版支持程度不同,需按所用版本确认。
误区 修正
回查里凭内存标志判断 查库或状态表
认为事务消息=不重复消费 至少一次,仍需幂等
用事务消息替代所有对账 一致性证据仍靠对账
半消息发送失败不处理 需要重试或降级为本地消息表
把“提交成功”当作“业务成功” 消费结果需要回执或查询确认
  • Apache RocketMQ 官方文档:Transactional Messages
  • 本地消息表与 Outbox 模式(见本站“本地消息表与 Outbox”)