分布式事务笔记暂定

Posted by SFHJavaer on 2025-05-29
Estimated Reading Time 8 Minutes
Words 2.6k In Total
Viewed Times

在分布式环境下想实现“事务”的功能,就必须要分布式事务

比如下单和扣库存服务,既然是两个服务,两个JVM,两个上下文,两个事务管理器(事务传递机制不生效),所以事务边界当然不统一

有可能下单成功,但是最终的库存扣减失败,但调用方无权去回滚B的方法,因为这里的方法是RPC远调的

所以同样加入调用ABC三个服务,AB成功,C失败,那么AB的逻辑同样无法回滚,由此就产生了分布式事务的概念

所以即使在Mangos中,如果在CloudService同时调用了固收和限额服务,那么能做到的操作就是当限额(C)服务失败时,提示一个

创建订单失败,但限额服务异常

是没有分布式事务的控制手段的,这种微服务架构下,就必须将业务逻辑耦合在单个服务,或将微服务架构(舍弃)直接整合成一体化包

Rocket事务消息

1. 它保证了什么?—— 核心是“本地事务”与“消息发送”的原子性

  • 场景: 服务A(订单服务)需要执行一个本地数据库事务(包含您说的5个步骤:检查库存、扣库存、创建订单主记录、创建订单明细记录、更新积分)。这个本地事务完成后,需要 可靠地通知 服务B(物流服务)和服务C(通知服务)去做它们的事情。
  • 问题: 如何保证服务A的 本地事务成功执行通知消息成功发送 这两件事要么都发生,要么都不发生?
    • 灾难场景1: 服务A本地事务成功提交了,但消息没发出去(服务A在提交后、发消息前宕机)。结果:服务B和服务C不知道订单创建了,没发货也没通知。
    • 灾难场景2: 服务A本地事务失败了(比如扣库存时库存不足,事务回滚),但消息发出去了。结果:服务B和服务C收到了“订单创建成功”的消息,去执行发货和通知,但实际上订单不存在!这比场景1更严重。
  • RocketMQ 事务消息的解决: 它通过“半消息 + 本地事务执行 + Commit/Rollback + 回查”的机制,精确地保证了
    • 如果服务A的本地事务(那5个步骤)成功提交,那么代表“订单创建成功”的消息最终一定会被成功发送(Commit 成功或回查后 Commit)。
    • 如果服务A的本地事务(那5个步骤)失败回滚,那么代表“订单创建成功”的消息最终一定会被丢弃(Rollback 成功或回查后 Rollback)。
  • 因此,它保证了: 服务A的本地数据库事务(5个步骤)一条消息的可靠发送 之间的 最终一致性。它把两个原本独立(一个在DB,一个在MQ)的操作绑定成了一个“逻辑原子操作”。

2. 为什么说它是“分布式事务”的解决方案?

  • 分布式事务的本质: 协调多个独立的服务/资源(它们有自己的数据存储和控制逻辑)完成一个业务目标,并尽可能保证整体数据的一致性。强一致性(ACID)在分布式系统中极其困难且代价高昂(CAP定理),最终一致性是更常用、更实用的目标。
  • RocketMQ 事务消息解决的 分布式事务: 它解决了服务A(订单服务,操作DB)与服务B/C(物流/通知服务,通过MQ触发)之间的 可靠事件通知 问题。服务A完成了自己的事,如何 可靠地、一致性地 告诉服务B/C“我这边OK了,该你们了”?这就是分布式事务中最常见的 事件驱动 模式。
  • 它是“模式”和“组件”: 它提供了一种 标准化、高可靠、高性能 的机制来实现 本地事务与下游事件触发的解耦与一致性。这是构建最终一致性分布式事务的基石之一。没有这种机制,构建可靠的分布式事务会更加复杂和脆弱。

3. 关于“五个步骤在本地事务结束”和“物流原子性”

  • “五个步骤在本地事务结束”完全正确: 这5个步骤(库存检查、扣库存、创建订单主/明细、更新积分)必须在服务A的同一个本地数据库事务中完成。这个本地事务保证了这5个步骤的 强一致性(ACID)。RocketMQ 事务消息 完全不干涉 这个本地事务的执行和它内部的ACID保证。它只关心这个本地事务最终的结果(成功 or 失败)
  • “不能保证物流的原子性”也完全正确: RocketMQ 事务消息只负责把消息最终、可靠地送到物流服务的消费者那里。它不负责物流服务内部处理这个消息的业务逻辑是否成功(如创建发货单是否成功)。
    • 物流服务收到消息后,它需要自己去执行它的本地事务(比如扣减自己的库存位、创建发货单、调度快递员)。这个事务的成败完全在物流服务内部
    • 如果物流服务处理失败(比如创建发货单时自己数据库挂了),RocketMQ 事务消息机制本身对此无能为力。

4. 既然不能保证物流的原子性,那“分布式事务”体现在哪里?

分布式事务的“事务”在这里体现为 一个跨越多个服务、需要保证最终一致性的业务过程。RocketMQ 事务消息解决了这个过程中的 第一个关键链路

  1. 订单服务本地事务成功 (ACID by DB)
  2. => 消息可靠投递到物流服务 (最终一致性 by RocketMQ Transactional Message)

它保证了 步骤1的成功必然导致步骤2的发生。这是整个分布式流程启动下游的关键一步。

完整的“订单创建->发货”分布式事务流程:

  1. 订单服务:
    • 开始本地事务。
    • 执行5个步骤(库存检查、扣库存、创建订单主/明细、更新积分)。
    • 同时: 发送 RocketMQ 半消息 (对物流服务不可见)。
    • 提交本地事务 (5个步骤ACID完成)。
    • 根据提交结果,向MQ发送 Commit (成功) 或 Rollback (失败) 指令。
    • (如果宕机未发送指令,MQ会回查订单服务确认状态)。
  2. RocketMQ:
    • 收到 Commit 后,将半消息转为 正式消息,投递给物流服务。
    • 收到 Rollback 或回查结果为失败,则 丢弃 该半消息。
  3. 物流服务:
    • 消费者 收到正式消息。
    • 执行自己的本地事务:
      • 解析消息(获取订单ID、收货地址等)。
      • 执行自己的业务逻辑(如校验地址、分配仓库、扣减本地库存位、创建发货单、调度快递员)。这些操作也需要在一个本地事务中保证ACID!
      • 处理成功:向MQ发送 ACK
      • 处理失败/异常:返回 失败,触发MQ的重试机制。
    • (关键点) 物流服务 必须 实现消息处理的幂等性! 因为MQ可能重试投递(网络问题、物流服务短暂故障)。
    • 如果多次重试后仍然失败,消息进入 死信队列 (DLQ)。需要人工介入或专门的补偿服务处理(如通知客服、尝试其他物流方式、或触发订单取消流程)。
  4. (可选) 通知服务: 流程类似物流服务,处理通知逻辑(发短信、邮件等),同样需要幂等性和错误处理。
  5. (兜底) 对账系统: 定期扫描订单状态和物流状态/通知记录。发现“已支付未发货”且无有效失败记录的订单,触发告警或自动补偿流程。

为什么说 RocketMQ 事务消息是分布式事务解决方案?

  • 它解决了分布式事务中最常见的“可靠事件通知”问题: 这是实现最终一致性的核心模式之一。
  • 它保证了“事务发起方”动作与“触发下游”动作的一致性: 这是跨服务协作的关键环节。
  • 它与下游服务的幂等性、重试、补偿机制共同构成了完整的最终一致性方案: 没有它的“可靠触发”,下游的幂等和补偿就失去了基础。没有下游的幂等和补偿,它的可靠触发就可能引发错误(如重复执行)。

总结:

  1. RocketMQ 事务消息保证的是: 本地业务事务 (如订单创建的5步) 的提交一条代表该事务成功的消息的可靠投递 之间的 最终一致性。它解决了服务A到服务B/C的 可靠事件通知 问题。
  2. 保证: 下游服务(物流、通知)自身内部事务执行的原子性或成功。这是下游服务自身的责任,需要通过 幂等性设计、可靠消费、重试机制、死信处理、业务补偿/对账 来解决。
  3. 它是“分布式事务解决方案”: 因为它提供了一种标准化的、高可用的、高性能的机制,解决了分布式事务流程中 事件驱动 模式的核心痛点(本地事务与事件触发的原子性),是构建最终一致性分布式系统的 关键基础设施。完整的分布式事务需要 组合 多种模式(事务消息、TCC、Saga、补偿、幂等、对账),而 RocketMQ 事务消息是其中针对“可靠事件通知”场景最常用且高效的方案之一。它保证了“起点”的正确性,为后续的“最终一致”奠定了基础。

明确保证一致性,想想一致性是什么,转账不能A没少,B就多了50块,Rocket保证的就是有延迟的最终一致性,只要保证每个环节具有了一致性,那么总体一致性就不会被破坏


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !