type
status
date
slug
summary
tags
category
icon
password
URL
文章来源说明

分布式事物

在微服务架构中,完成某一个业务功能可能需要横跨多个服务,操作多个数据库。这就涉及到到了分布式事务,需要操作的资源位于多个资源服务器上,而应用需要保证对于多个资源服务器的数据操作,要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同资源服务器的数据一致性。

电商下单分布式事物的简单场景

  1. 用户下单锁库存
  1. 支付成功后修改订单状态和异步扣减真实库存

分布式事物常见解决方案

2pc
tcc
可靠消息
最大努力通知
一致性
强一致性
最终一致
最终一致
最终一致
吞吐量
实现复杂读
当前重点方案
  1. 2pc 基于seata at 实现
  1. mq可靠消息 基于rocketmq事物消息实现

基于seata实现用户下单锁库存

seata架构

  • TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。
 
在 Seata 中,一个分布式事务的生命周期如下:
1. TM 请求 TC 开启一个全局事务。TC 会生成一个 XID 作为该全局事务的编号。XID会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。 2. RM 请求 TC 将本地事务注册为全局事务的分支事务,通过全局事务的 XID 进行关联。 3. TM 请求 TC 告诉 XID 对应的全局事务是进行提交还是回滚。 4. TC 驱动 RM 们将 XID 对应的自己的本地事务进行提交还是回滚。
notion image
具体例子解释
  • 订单服务发起事务(TM)
    • 订单服务作为TM,向TC(事务协调器)发起一个全局事务请求,TC会创建一个全局事务ID,并跟踪这个事务。
  • 库存和支付服务参与事务(RM)
    • 订单服务调用库存和支付服务时,这两个服务会向TC注册自己,表明它们是这个全局事务的一部分。库存服务和支付服务的本地事务(如锁定库存和冻结资金)由各自的RM来管理。
  • TC协调全局事务
    • 在库存和支付服务执行完各自的本地事务后,它们的RM会向TC汇报本地事务的执行结果。如果TC收到所有分支事务执行成功的汇报,TC就会通知各RM提交本地事务,最终全局事务成功。
    • 如果任何一个服务的本地事务失败,TC会通知所有RM回滚事务,整个全局事务将被回滚。
 

seata整合

  1. 引入依赖
spring-cloud-starter-alibaba-seata内部集成了seata,并实现了xid传递
 
  1. tc服务搭建
说实话还是挺麻烦可以参考官网地址 新人文档 | Apache Seata
 
  1. 微服务对应数据库中添加undo_log表(仅AT模式)
  1. 微服务application.yml中添加seata配置
注意:请确保client与server的注册中心和配置中心namespace和group一致
  1. 由于分库分表 导致 不能简单用注解
@GlobalTransactional //此处不能使用@GlobalTransactional
  1. ShardingSphere整合Seata
    1. 引入依赖
    2. b.配置seata.conf
      包含 Seata 柔性事务的应用启动时,用户配置的数据源会根据 seata.conf 的配置,适配为 Seata 事务所需的 DataSourceProxy,并且注册至 RM 中。
      c. 开启全局事物
 

可靠消息最终一致性方案

可靠消息最终一致性方案是指当事务发起执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。
  1. 本地消息表 略
  1. rockemq事物消息实现
RocketMQ事务消息设计则主要是为了解决Producer端的消息发送与本地事务执行的原子性问题,RocketMQ的设计中broker与producer端的双向通信能力,使得broker天生可以作为一个事务协调者存在;而RocketMQ本身提供的存储机制为事务消息提供了持久化能力;RocketMQ的高可用机制以及可靠消息设计则为事务消息在系统发生异常时依然能够保证达成事务的最终一致性。
 
notion image
 
执行流程如下 : 为方便理解我们以注册送优惠券的例子来描述整个流程。 Producer即MQ发送方,本例中是用户服务,负责新增用户。MQ订阅方即消息消费方,本例中是优惠券服务,负责新增优惠券。
1)Producer发送事务消息
Producer(MQ发送方)发送事务消息至MQ Server,MQ Server将消息状态标记为Prepared(预览状态),注意此时这条消息消费者(MQ订阅方)是无法消费到的。
2)MQ Server回应消息发送成功
MQ Server接收到Producer发送给的消息则回应发送成功表示MQ已接收到消息。
3)Producer执行本地事务
Producer端执行业务代码逻辑,通过本地数据库事务控制。
本例中,Producer执行添加用户操作。
4)消息投递
若Producer本地事务执行成功则自动向MQ Server发送commit消息,MQ Server接收到commit消息后将“增加优惠券消息”状态标记为可消费,此时MQ订阅方(优惠券服务)即正常消费消息;
若Producer 本地事务执行失败则自动向MQ Server发送rollback消息,MQ Server接收到rollback消息后将删除“增加优惠券消息”。
MQ订阅方(优惠券服务)消费消息,消费成功则向MQ回应ack,否则将重复接收消息。这里ack默认自动回应,即程序执行正常则自动回应ack。
5)事务回查
如果执行Producer端本地事务过程中,执行端挂掉,或者超时,MQ Server将会不停的询问同组的其他Producer来获取事务执行状态,这个过程叫事务回查。MQ Server会根据事务回查结果来决定是否投递消息。
以上主干流程已由RocketMQ实现,对用户则来说,用户需要分别实现本地事务执行以及本地事务回查方法,因此只需关注本地事务的执行状态即可。
致谢:
💡
有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
 
 
订单系统的设计消息中心架构设计
Loading...