事务消息——分布式事务的终极解法(四)
在之前的文章里我们把 RocketMQ 的存储、发送、消费全链路都拆解了一遍。但有一个重量级特性我们一直没聊——事务消息Transactional Message。为什么把事务消息放在这里才讲因为理解事务消息需要两个前提一是你要知道消息是怎么存储的CommitLog ConsumeQueue二是你要知道消息是怎么发送的同步/异步/单向。有了这些基础我们才能深入理解事务消息的精妙之处。说实话事务消息是 RocketMQ 最复杂、也最令人惊叹的特性之一。它解决的是一道难题——在分布式系统中如何保证“发送消息”和“执行本地事务”要么一起成功要么一起失败今天这篇文章我们就来彻底搞懂事务消息。我会从它要解决的问题开始一步步深入到半消息、事务回查、状态机等核心机制。老规矩配合流程图一步一图。八、事务消息事务消息诞生的背景与要解决的问题我们先来看一个经典的分布式事务困境。你在电商系统里做一个“下单扣库存”的业务。订单服务和库存服务是两个独立的服务通过消息来解耦分布式事务困境订单服务创建订单发送扣库存消息消息发送成功但订单插入失败⚠️ 消息已经发出去了库存被扣了但订单不存在→ 数据不一致订单插入成功但消息发送失败⚠️ 订单创建了但库存没扣→ 超卖风险问题可以归结为一句话本地数据库操作订单插入和消息发送扣库存通知这两个操作不在同一个事务里。它们要么都成功要么都失败——但在分布式环境下这很难做到。常见的解决方案及其局限方案 怎么做 问题先发消息再执行本地事务 消息发出去后再插入订单 消息发成功但订单插入失败 → 库存被误扣先执行本地事务再发消息 插入订单后再发消息 订单插入成功但消息发送失败 → 超卖本地事务 本地消息表 在同一个数据库里存消息表定时扫描发送 依赖数据库轮询效率低有延迟RocketMQ 事务消息的解法RocketMQ 事务消息的核心思想是让消息的发送和本地事务的执行通过“半消息 事务回查”机制达成最终一致性。它不依赖本地消息表不需要轮询不需要额外的存储全部在 Broker 和 Producer 之间协调完成。事务消息的核心流程半消息Half Message什么是半消息Half Message半消息是事务消息的核心概念。它是一种暂不可见的消息——Producer 发送了这条消息但 Consumer 暂时还消费不到。半消息✅ 消息已写入 CommitLog有存储❌ 消息在 ConsumeQueue 中被标记为不可见⏳ 等待本地事务执行结果半消息 消息已存储但不可消费像个“待确认”的订单半消息的设计意图半消息的存在解决了“消息发送成功了但本地事务还没执行”这个中间状态的问题。如果半消息直接可见Consumer 就能消费到——但此时本地事务可能还没执行完数据状态不确定如果半消息不可见Consumer 就消费不到——等本地事务执行完再决定是提交还是回滚这样消息的可见性和本地事务的执行结果绑定在了一起。本地事务与半消息的协调机制事务消息的完整流程核心就是一个两阶段协调的过程成功失败COMMITROLLBACK业务发起事务消息阶段一发送半消息Producer 发送半消息到 BrokerBroker 存储半消息标记为不可消费Broker 返回半消息发送成功阶段二执行本地事务Producer 执行本地业务逻辑如插入订单本地事务结果阶段三提交/回滚Producer 向 Broker发送事务状态状态Broker 将半消息标记为可见Consumer 可以消费到消息Broker 删除半消息标记删除消息被丢弃不消费关键点半消息是第一步先发半消息再执行本地事务。如果半消息发送失败直接结束不用执行本地事务。本地事务决定最终状态本地事务成功 → COMMIT本地事务失败 → ROLLBACK。Broker 最终执行COMMIT 使消息可见ROLLBACK 使消息被丢弃。事务回查Check机制的实现原理上面我们讨论的是正常情况——本地事务执行完Producer 能正常告诉 Broker 是 COMMIT 还是 ROLLBACK。但如果本地事务执行完后Producer 宕机了或者网络断了呢Broker 怎么知道这条半消息最终应该被提交还是回滚答案就是事务回查Transaction Check机制。否是否是否是Broker 扫描半消息半消息状态是否为 UNKNOWN跳过Broker 向 Producer发起事务回查请求Producer 是否能正常响应标记为需要再次回查等待下一轮回查次数是否超限默认回滚防止消息堆积Producer 执行事务状态检查逻辑返回事务状态COMMIT / ROLLBACK / UNKNOWNBroker 根据状态执行提交或回滚回查机制的核心设计Broker 主动发起Broker 会定期扫描处于 UNKNOWN 状态的半消息默认每 60 秒一次Producer 被动响应Producer 需要实现 TransactionListener 的 checkLocalTransaction() 方法根据业务状态返回最终决定可配置重试回查失败会重试但如果超过配置的重试次数默认 15 次Broker 会默认回滚为什么需要回查回查解决了分布式系统中的不确定性问题——当 Producer 不可达时Broker 不能无限等待必须有最终决策。回查机制确保了半消息不会永远处于“悬而未决”的状态。事务消息的状态COMMIT、ROLLBACK、UNKNOWNRocketMQ 事务消息有三种状态由 Producer 的 TransactionListener 返回状态 含义 Broker 操作 Consumer 是否可见COMMIT 本地事务成功提交消息 将半消息标记为可见 ✅ 可见可消费ROLLBACK 本地事务失败回滚消息 删除半消息 ❌ 不可见被丢弃UNKNOWN 本地事务状态未知 暂不操作等待回查 ❌ 暂不可见等待决策public class OrderTransactionListener implements TransactionListener {Override public LocalTransactionState executeLocalTransaction(Message msg, Object arg) { try { // 执行本地事务插入订单 orderService.createOrder(arg); return LocalTransactionState.COMMIT_MESSAGE; } catch (Exception e) { return LocalTransactionState.ROLLBACK_MESSAGE; } } Override public LocalTransactionState checkLocalTransaction(MessageExt msg) { // 回查时根据业务数据判断事务是否成功 String orderId msg.getProperty(orderId); if (orderService.orderExists(orderId)) { return LocalTransactionState.COMMIT_MESSAGE; } return LocalTransactionState.ROLLBACK_MESSAGE; }}UNKNOWN 的使用场景本地事务执行过程中发生了异常无法确定是否成功本地事务执行时间很长需要异步确认依赖外部系统的状态需要等待外部回调UNKNOWN 状态触发的回查机制给了系统足够的容错空间。事务消息的完整时序图与执行流程把前面所有的内容串起来我们来看一张完整的时序图本地数据库ConsumerBrokerProducer业务应用本地数据库ConsumerBrokerProducer业务应用消息不可见不被消费此时不向 Broker 发送最终决定alt[多次回查仍返回UNKNOWN]loop[事务回查默认每 60 秒]alt[本地事务成功][本地事务失败][本地事务执行异常/超时]发送事务消息发送半消息状态PREPARED存储半消息不可消费记录事务状态半消息发送成功回调执行本地事务执行本地事务插入订单等7a. 事务提交成功8a. 返回 COMMIT9a. 提交事务消息10a. 标记消息可见11a. Consumer 消费到消息7b. 事务回滚8b. 返回 ROLLBACK9b. 回滚事务消息10b. 删除半消息8c. 返回 UNKNOWN9c. 发起回查请求10c. 检查本地事务状态11c. 查询业务数据12c. 返回查询结果13c. 返回 COMMIT/ROLLBACK/UNKNOWN14c. 提交最终事务状态15c. 超过回查次数限制默认回滚流程概括发送半消息 → 2. 执行本地事务 → 3. 根据结果决定状态 → 4. COMMIT/ROLLBACK/UNKNOWN → 5. UNKNOWN 触发回查 → 6. 最终确定状态。这个流程保证了要么本地事务成功且消息被消费要么本地事务失败且消息被丢弃。

相关新闻

设备发烫降频?导热硅胶片选这款真的稳[特殊字符]

设备发烫降频?导热硅胶片选这款真的稳[特殊字符]

做电子研发、新能源、工控的小伙伴应该都懂😭 设备最怕的不是性能不够,是散热拉胯 芯片过热降频、电源高温异响、长期温循老化失效、PCB渗油污染… 很多问题根源,其实都是导热硅胶片没选对! 给行业同行安利一款真实参数、不虚标的…

2026/7/19 5:05:39阅读更多 →
AI法规分析系统:从NLP到知识图谱的政府治理技术实践

AI法规分析系统:从NLP到知识图谱的政府治理技术实践

当纽约州长凯西霍楚宣布要用AI分析州内"每一条法规"时,很多人第一反应可能是"又一个政客在蹭AI热点"。但如果你仔细想想政府法规的现状——成千上万条相互引用、年代久远、甚至自相矛盾的法律条文,就会意识到这可能是AI在公共治理领…

2026/7/19 5:03:39阅读更多 →
C++内存泄漏检测与修复实战指南:从原理到工具全面解析

C++内存泄漏检测与修复实战指南:从原理到工具全面解析

1. 项目概述:为什么C程序员必须直面内存泄漏?在C的世界里,内存管理是开发者手中的双刃剑。它赋予了我们无与伦比的性能控制力,但也埋下了无数隐患的种子,其中最臭名昭著、也最难以根除的,就是内存泄漏。这不…

2026/7/19 5:03:39阅读更多 →
STM32 LoRaWAN节点通信优化与低功耗设计

STM32 LoRaWAN节点通信优化与低功耗设计

1. STM32 LoRaWAN Ping-Pong节点方案概述在物联网应用中,节点间的双向通信验证是确保链路可靠性的基础需求。这个基于STM32和LoRaWAN的Ping-Pong方案,本质上构建了一个可测量无线链路质量的测试框架。Ping-Pong机制源于网络诊断中的基础概念,…

2026/7/19 9:00:04阅读更多 →
FPGA串口通信实现与UART协议详解

FPGA串口通信实现与UART协议详解

1. 串口通信基础与FPGA实现概述在嵌入式系统和数字电路设计中,串口通信是最基础也最常用的外设接口之一。相比并行通信,串行通信虽然传输速率较低,但具有线路简单、占用引脚资源少的优势,特别适合FPGA与上位机或其他设备之间的数据…

2026/7/19 9:00:04阅读更多 →
服务器电源设计:PFC、LLC谐振与同步整流控制技术详解

服务器电源设计:PFC、LLC谐振与同步整流控制技术详解

在实际服务器电源设计中,电源转换效率、功率密度和稳定性是三个核心指标。服务器电源需要将交流电转换为服务器主板、CPU、内存等组件所需的直流电,这个过程中涉及多级转换和复杂控制策略。常见的服务器电源架构包含功率因数校正(PFC&#xf…

2026/7/19 9:00:04阅读更多 →
User-Agent解析与应用指南

User-Agent解析与应用指南

1. User-Agent基础解析与核心价值 User-Agent(用户代理)是HTTP协议中最古老且持续演进的请求头之一,它的核心作用就像快递包裹上的发货单。当你的浏览器访问网站时,会自动在请求头中附带这样一段字符串:"Mozilla/…

2026/7/19 9:00:04阅读更多 →
Handler嵌套模式在多线程与异步编程中的应用

Handler嵌套模式在多线程与异步编程中的应用

1. Handler嵌套的概念与背景 在软件开发领域,Handler嵌套是一个常见但容易被忽视的设计模式。我第一次接触这个概念是在开发一个复杂的Android应用时,当时需要处理多个异步任务之间的协调问题。简单来说,Handler嵌套指的是在一个Handler的处理…

2026/7/19 9:00:04阅读更多 →
靠谱的手机租赁苹果锁哪个好

靠谱的手机租赁苹果锁哪个好

手机租赁行业近年增长迅猛,据行业报告显示,国内租赁市场规模年复合增长率超30%,苹果设备因保值率高、用户需求稳定,成为租赁主力。但租赁过程中,苹果锁(即设备监管锁)的可靠性直接影响风控效果&…

2026/7/19 8:58:03阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/18 22:49:46阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/18 14:49:24阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/18 18:49:35阅读更多 →