分布式事务

分布式事务框架 Seata


Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。它提供了AT、TCC、Saga和XA事务模式,为开发者提供了一站式的分布式事务解决方案。其中TCC 和XA我们前面分析过,AT 和Saga这两种事务模式是什么呢?下面先来简单介绍一下这两种事务模式。

AT模式


AT 模式是Seata最主推的分布式事务解决方案,它是基于XA演进而来的一种分布式事务模式,所以它同样分为三大模块,分别是TM、RM和TC,其中TM和RM作为Seata的客户端与业务系统集成,TC作为Seata的服务器独立部署。TM表示事务管理器(Transaction Manager),它负责向TC注册一个全局事务,并生成一个全局唯一的XID。在AT模式下,每个数据库资源被当作一个RM(Resource Manager),在业务层面通过JDBC标准的接口访问RM时,Seata会对所有请求进行拦截。每个本地事务进行提交时,RM都会向TC(Transaction Coordinator,事务协调器)注册一个分支事务。Seata的AT 事务模式如图所示。
 

分布式事务_第1张图片

具体执行流程如下:

  • TM向TC注册全局事务,并生成全局唯一的XID.
  • RM向TC注册分支事务,并将其纳入该XID对应的全局事务范围。
  • RM向TC汇报资源的准备状态。
  • TC汇总所有事务参与者的执行状态,决定分布式事务是全部回滚还是提交。
  • TC通知所有RM提交/回滚事务。

AT模式和XA一样,也是一个两阶提交事务模型,不过和XA相比,做了很多优化,会在后续的章节中重点分析AT模式的实现原理。


Saga 模式


Saga模式又称为长事务解决方案,它是由普林斯顿大学的Hector Garcia-Molina和Kenneth Salem 提出的,主要描述的是在没有两阶段提交的情况下如何解决分布式事务问题。其核心思想是:把一个业务流程中的长事务拆分为多个本地短事务,业务流程中的每个参与者都提交真实的提交给该本地短事务,当其中一个参与者事务执行失败,则通过补偿机制补偿前面已经成功的参与者。
如图所示,Saga由一系列sub-transaction Ti组成,每个Ti都有对应的补偿动作Ci,补偿动作用于销Ti造成的数据变更结果。它和TCC相比,少了Try这个预留动作,每一个Ti操作都真实地影响到数据库。

分布式事务_第2张图片

按照Saga的工作模式,有两种执行方式:

  • T1,T2,T3,...,Ti:这种方式表示所有事务都正常执行。
  • T1, T2, ..., Tj,Cj,...,C2,C1(其中0

另外,Saga提供了以下两种补偿恢复方式。

  • ·向后恢复,也就是上面提到的第二种工作模式,如果任一子事务执行失败,则把之前执行的结果逐一撤销。
  • ·向前恢复,也就是不进行补偿,而是对失败的事务进行重试,这种方式比较适合于事务必须要执行成功的场景。

不管是向后恢复还是向前恢复,都可能出现失败的情况,在最坏的情况下只能人工干预处理。

Saga 的优劣势

和XA或者 TCC相比,它的优势包括:一阶段直接提交本地事务;没有锁等待,性能较高;在事件驱动的模式下,短事务可以异步执行;补偿机制的实现比较简单。
缺点是 Saga并不提供原子性和隔离性支持,隔离性的影响是比较大的,比如用户购买一个商品后系统赠送一张优惠券,如果用户已经把优惠券使用了,那么事务如果出现异常要回滚时就会出现问题。


Saga的实现方式


在一个电商平台的下单场景中,一般会涉及订单的创建、商品库存的扣减、钱包支付、积分赠送等操作,整体的时序图如图8-12所示。
电商平台下单的流程是一个典型的长事务场景,根据Saga模式的定义,先将长事务拆分成多个本地短事务,每个服务的本地事务按照执行顺序逐一提交,一旦其中一个服务的事务出现异常,则采用补偿的方式逐一撤回。这一过程的实现会涉及Saga的协调模式,它有两种常用的协调
模式。

  • 事件/编排式:把Saga的决策和执行顺序逻辑分布在Saga的每一个参与者中,它们通过交换事件的方式来进行沟通。
  • 命令/协同式:把Saga的决策和执行顺序逻辑集中在一个Saga控制类中,它以命令/回复的方式与每项服务进行通信,告诉它们应该执行哪些操作。

分布式事务_第3张图片

事件/编排式
在基于事件的编排模式中,第一个服务执行完一个本地事务之后,发送一个事件。这个事件会被一个或者多个服务监听,监听到事件的服务再执行本地事务并发布新的事件,此后一直延续这种事件触发模式,直到该业务流程中最后一个服务的本地事务执行结束,才意味着整个分布式长事务也执行结束,如图所示。

分布式事务_第4张图片

这个流程看起来很复杂,但是却是比较常见的解决方案,下面简单描述一下具体的步骤。

  • 订单服务创建新的订单,把订单状态设置为待支付,并发布一个ORDER_CREATE_EVENT
  • 事件。
  • 库存服务监听到ORDER_CREATE_EVENT事件后,执行本地的库存冻结方法,如果执行成功,则发布一个ORDER_PREPARED_EVENT 事件。
  • 支付服务监听ORDER_PREPARED_EVENT事件后,执行账户扣款方法,并发布 PAY_ORDER_EVENT 事件。
  • 最后,积分服务监听PAY_ORDER_EVENT事件,增加账户积分,并更新订单状态为成功。

上述任一步骤执行失败,都会发送一个失败的事件,每个服务需要监听失败的情况根据实际需求进行逐一回滚。

命令/协同式


命令/协同式需要定义一个Saga协调器,负责告诉每一个参与者该做什么,Saga协调器以命令/回复的方式与每项服务进行通信,如图所示。

分布式事务_第5张图片

命令/协同式的实现步骤如下:

  • 订单服务首先创建一个订单,然后创建一个订单Saga协调器,启动订单事务。
  • Saga协调器向库存服务发送冻结库存命令,库存服务通过Order Saga Reply Queue回复执行结果。
  • 接着,Saga协调器继续向支付服务发起账户扣款命令,支付服务通过Order Saga Reply Queue 回复执行结果。
  • 最后,Saga协调器向积分服务发起增加积分命令,积分服务回复执行结果。

需要注意的是,订单Saga协调器必须提前知道“创建订单事务”的所有流程(Seata是通过基于 JSON 的状态机引擎来实现的),并且在整个流程中任何一个环节执行失败,它都需要向每个参与者发送命令撤销之前的事务操作。

你可能感兴趣的:(1024程序员节,java)