连载中 8/18

事务消息:RocketMQ 半消息与回查

2026-06-17 · 3821 阅读 · 0 评论 · 0 赞

把土办法下沉到 MQ

本地消息表方案讲给团队听,有人说:土是真的土——每个要发消息的业务都要建一张消息表、养一个扫描任务,十个业务十张表。RocketMQ 的回应是:「先存后投」的逻辑我替你做,搬进消息服务器内部,这就是事务消息(Transactional Message)。应用侧只剩「执行本地事务」一件事,消息表和扫描任务全部消失。

半消息:先锁事实,再干活

事务消息的核心概念是半消息(Half Message)——一条「暂扣」在 MQ 里、消费者看不见的消息。完整流程四步:

1 生产者 → MQ:发送半消息(消费者不可见)
2 MQ:半消息持久化,回复「收到」
3 生产者:执行本地事务(订单落库)
4 生产者 → MQ:commit(消息转正,开始投递)
              或 rollback(删除半消息)

对照本地消息表看透本质:半消息就是 MQ 帮你管理的那条「待发送」记录——第 2 步 MQ 确认落盘,相当于消息记录已提交;第 3、4 步的顺序保证了「要么消息和业务一起成立,要么半消息被删掉」。顺序题的两难被结构化解开了:先让消息「半」着,业务成了再转正。

回查:进程挂了的兜底

流程走到第 3 步,生产者本地事务提交成功,还没来得及发 commit 就崩了——半消息悬在 MQ 里,转正还是删除?MQ 不知道,但它会问:定时对悬而未决的半消息发起回查(Check Local Transaction),生产者收到回查后查自己的本地事务状态,回答 commit、rollback 或 unknown(unknown 则稍后继续查)。

关键在「查什么」:回查要能从业务数据本身判断事务做没做成——订单表里有没有这笔单、状态是什么。这要求业务记录可查、状态语义清晰(成功/失败不能都是同一个模糊态)。有团队偷懒在内存里记个标记应付回查,进程一重启标记蒸发,回查永远 unknown,半消息等满最大回查次数后默认 rollback——消息丢了。回查逻辑不是可选项,是这个方案的地基。

与本地消息表对比

维度本地消息表事务消息
消息暂存业务库里的消息表MQ 内部半消息
应用侧工作写消息表 + 扫描任务本地事务 + 回查实现
DB 开销每笔多一次消息表写入无额外写入
MQ 绑定任何 MQ 都行RocketMQ(或同类实现)
排查视角查自己的表,直白查 MQ 控制台 + 回查日志

别高估它的保真范围

两个常见误解纠正:一,事务消息只管发送端——保证「业务成功则消息必达」,消费端该重试重试、该幂等幂等,一样不能少;二,它不是 ACID 事务——MQ 和数据库之间没有统一提交点,靠的是「先半后全 + 回查」的收敛协议,中间存在短暂的双向不确定,最终一致而已。另外 Kafka 原生没有这套机制(它的事务是另一回事——流处理 exactly-once),Kafka 体系想要可靠消息,本地消息表仍是首选。

小结

事务消息一句话:半消息锁事实、本地事务定乾坤、回查兜进程挂——把本地消息表下沉进 MQ,省表省任务,代价是绑定 RocketMQ 与一份可靠的回查实现。发送端到 MQ 的链路闭环了,但有一类场景连 MQ 都嫌重:给用户发个到账短信,通知失败了总不能无限重试把 MQ 塞满——下一篇:最大努力通知,通知到为止的艺术。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#分布式事务#事务消息#RocketMQ#半消息#回查

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞