news 2026/8/28 0:42:50

分布式事务弃用 Seata?记一次基于 RocketMQ 最终一致性的落地实战,复杂场景下的“弃笨从简”之道

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分布式事务弃用 Seata?记一次基于 RocketMQ 最终一致性的落地实战,复杂场景下的“弃笨从简”之道

💣 开篇:为什么我们决定“弃用” Seata?

在上一阶段的项目复盘中,我们发现订单中心的数据库 CPU 飙升,且大量事务处于 Lock Wait 状态。
排查发现,罪魁祸首竟然是不仅被视为“银弹”,也被广泛使用的Seata AT 模式

Seata AT 的痛点(高并发场景):

  1. 全局锁(Global Lock):二阶段提交(2PC)为了保证隔离性,持锁时间 = RPC 调用时间 + 业务执行时间。长链路下,这就是性能毒药。
  2. 吞吐量瓶颈:TC(事务协调者)集群在高并发下容易成为单点瓶颈。
  3. 死锁风险:复杂链路下的全局锁与本地锁极易死锁。

架构哲学的反思:
在微服务架构中,99% 的业务场景(如下单、支付、积分)其实不需要强一致性(CP),只需要最终一致性(AP)
于是,我们决定**“弃重从轻”**,全面切换到基于RocketMQ 事务消息的最终一致性方案。


🏗️ 架构演进:从“同步等待”到“异步确保”

我们的目标业务场景:用户下单 -> 扣减库存 -> 发放积分

1. 核心方案:RocketMQ 事务消息机制

RocketMQ 的“事务消息”是解决分布式事务的神器。它将消息发送拆分为两个阶段,确保本地事务执行消息发送的原子性。

交互时序图 (Sequence Diagram):

订单服务(Producer)RocketMQ积分服务(Consumer)阶段一:半消息机制1. 发送 Half 消息 (对消费者不可见)2. 发送成功 (ACK)3. 执行本地事务 (创建订单)4. Commit (提交消息)5. 投递消息 (消费者可见)6. 增加积分 (本地事务)4. Rollback (回滚消息/删除)alt[本地事务成功][本地事务失败]异常兜底:回查机制7. 回查本地事务状态 (Check)8. 再次 Commit/Rollbackopt[如果 Commit/Rollback 丢失]订单服务(Producer)RocketMQ积分服务(Consumer)

💻 落地实战:代码里的魔鬼细节

不要以为有了 RocketMQ 就万事大吉,“最终一致性”的难点在于 Consumer 端

Step 1: 生产者端 (Producer) - 保证“发”与“做”的原子性

我们需要实现RocketMQLocalTransactionListener接口。

@Component@RocketMQTransactionListenerpublicclassOrderTransactionListenerimplementsRocketMQLocalTransactionListener{@AutowiredprivateOrderServiceorderService;/** * 执行本地事务:插入订单数据 */@OverridepublicRocketMQLocalTransactionStateexecuteLocalTransaction(Messagemsg,Objectarg){try{// 解析消息中的订单信息OrderDTOorder=JSON.parseObject(newString((byte[])msg.getPayload()),OrderDTO.class);// 1. 核心业务:创建订单 (数据库操作)orderService.createOrder(order);// 2. 成功,通知 MQ 提交消息returnRocketMQLocalTransactionState.COMMIT;}catch(Exceptione){log.error("创建订单失败",e);// 3. 失败,通知 MQ 回滚 (Consumer 永远收不到这条消息)returnRocketMQLocalTransactionState.ROLLBACK;}}/** * 事务回查:防止网络丢包导致 MQ 不知道你是成功还是失败 */@OverridepublicRocketMQLocalTransactionStatecheckLocalTransaction(Messagemsg){OrderDTOorder=JSON.parseObject(newString((byte[])msg.getPayload()),OrderDTO.class);// 查询数据库,看订单到底有没有创建成功booleanexists=orderService.checkOrderExists(order.getOrderId());returnexists?RocketMQLocalTransactionState.COMMIT:RocketMQLocalTransactionState.ROLLBACK;}}
Step 2: 消费者端 (Consumer) - 幂等性是生命线

这是最关键的一步!
MQ 保证消息至少投递一次,意味着网络抖动时 Consumer 可能收到重复消息。如果积分加了两次,就是资损!

幂等性设计流程图:

graph TD Start(收到 MQ 消息) --> CheckRedis{1. 查询 Redis/去重表} CheckRedis -- "Key 已存在" --> Ignore[直接丢弃/返回成功] CheckRedis -- "Key 不存在" --> DoBiz[2. 执行业务: 加积分] DoBiz --> DBTx{3. 数据库事务提交?} DBTx -- "成功" --> SaveKey[4. 写入去重 Key (Redis/DB)] DBTx -- "失败" --> Retry[抛出异常/等待重试] SaveKey --> End(消费完成 ACK)

消费者代码示例:

@Service@RocketMQMessageListener(topic="order-topic",consumerGroup="point-group")publicclassPointConsumerimplementsRocketMQListener<String>{@AutowiredprivatePointServicepointService;@OverridepublicvoidonMessage(Stringmessage){OrderDTOorder=JSON.parseObject(message,OrderDTO.class);StringbizKey="POINT_ADD_"+order.getOrderId();// 1. 幂等性检查 (这里演示简单版,生产环境建议用去重表)if(redisTemplate.hasKey(bizKey)){log.info("重复消息,忽略: {}",bizKey);return;}// 2. 执行业务 (加积分)try{pointService.addPoints(order.getUserId(),order.getAmount());// 3. 标记为已处理redisTemplate.opsForValue().set(bizKey,"1",24,TimeUnit.HOURS);}catch(Exceptione){// 4. 抛出异常,利用 RocketMQ 的重试机制thrownewRuntimeException("消费失败,等待重试");}}}

🛡️ 异常兜底:最终一致性的“最终”有多远?

如果 Consumer 一直失败怎么办?(例如积分服务挂了,或者代码有 Bug)。

  1. 重试机制:RocketMQ 默认重试 16 次(从 1s 到 2h 不等)。绝大多数网络抖动都能在重试中恢复。
  2. 死信队列 (DLQ):如果 16 次重试后依然失败,消息进入死信队列。
  3. 人工/定时任务干预
  • 我们需要开发一个监控服务,订阅 DLQ。
  • 一旦发现死信,发送告警(钉钉/邮件)。
  • 人工排查 Bug,或通过脚本重新投递消息。

💡 架构总结:何时用 Seata,何时用 MQ?

没有最好的架构,只有最合适的架构。

对比维度Seata (AT 模式)RocketMQ 事务消息
一致性强弱强一致性(刚性事务)最终一致性(柔性事务)
并发性能低 (受限于全局锁)极高(异步解耦)
代码侵入性极低 (注解即可)高 (需写 Listener 和 幂等逻辑)
适用场景后台管理系统、配置变动、对一致性要求极高的资金转账电商下单、秒杀、支付回调、日志记录

博主建议:
在核心的高并发链路中,请大胆地**“弃笨从简”。虽然 MQ 方案写起来麻烦(要处理幂等、回查、死信),但它换来的是系统的高可用性无限的扩展能力**。这笔交易,绝对划算。


Next Step:
您是否想了解 Consumer 端**“基于本地消息表”的 100% 可靠幂等方案(比 Redis 更稳)?或者需要一份死信队列告警**的 Python 脚本?
在评论区回复“幂等”“脚本”,我为您安排下一期干货!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 13:02:24

你还在手动搭配衣服?Open-AutoGLM已实现全自动个性化推荐

第一章&#xff1a;Open-AutoGLM 穿衣搭配推荐Open-AutoGLM 是一个基于开源大语言模型的智能穿搭推荐系统&#xff0c;结合视觉识别与用户偏好分析&#xff0c;为用户提供个性化、场景化的穿衣建议。该系统能够理解自然语言输入的穿搭需求&#xff0c;如“适合面试的春季穿搭”…

作者头像 李华
网站建设 2026/8/28 0:37:26

Excalidraw支持导入/导出JSON实现数据迁移

Excalidraw 支持导入/导出 JSON 实现数据迁移 在远程协作日益成为常态的今天&#xff0c;团队对可视化工具的需求早已超越了“画图”本身。工程师、产品经理和设计师们需要一种既能快速表达想法&#xff0c;又能将这些想法持久化、版本化并嵌入工作流的工具。Excalidraw 正是在…

作者头像 李华
网站建设 2026/8/27 12:53:08

Excalidraw入门指南:快速上手手绘风格白板工具

Excalidraw入门指南&#xff1a;快速上手手绘风格白板工具 在一场远程产品评审会上&#xff0c;团队成员正围绕一个复杂的微服务架构展开讨论。有人提议&#xff1a;“我们能不能画出来看看&#xff1f;”——这句话几乎每天都在无数技术会议中响起。但真正的问题是&#xff1a…

作者头像 李华
网站建设 2026/8/27 9:41:05

还在愁节日送什么?Open-AutoGLM生态好物推荐,99%的人都没想到

第一章&#xff1a;Open-AutoGLM生态礼物推荐的全新视角在人工智能与个性化服务深度融合的今天&#xff0c;Open-AutoGLM 作为开源自动语言生成模型&#xff0c;正逐步改变用户与数字生态之间的互动方式。其核心能力不仅体现在自然语言理解与生成上&#xff0c;更在于能够基于上…

作者头像 李华
网站建设 2026/8/28 6:58:28

从实验室到落地:Open-AutoGLM手势控制适配面临的6大挑战与应对策略

第一章&#xff1a;从实验室到落地的跨越在人工智能与软件工程快速融合的今天&#xff0c;许多创新模型和算法在实验室环境中表现出色&#xff0c;但真正实现商业价值的关键在于能否顺利落地。从原型验证到生产部署&#xff0c;技术团队面临性能、稳定性、可维护性等多重挑战。…

作者头像 李华
网站建设 2026/8/27 18:02:00

Open-AutoGLM深度解析:OCR、NLP与知识图谱的完美融合(稀缺技术内幕)

第一章&#xff1a;Open-AutoGLM文档扫描归档概述Open-AutoGLM 是一个基于大语言模型的自动化文档处理框架&#xff0c;专注于将纸质或非结构化电子文档通过扫描、识别与语义解析&#xff0c;转化为可检索、可管理的结构化归档数据。该系统融合了OCR技术、自然语言理解与元数据…

作者头像 李华