Seata是什么?一文了解其实现原理

一、背景

随着业务发展,单体系统逐渐无法满足业务的需求,分布式架构逐渐成为大型互联网平台首选。伴随而来的问题是,本地事务方案已经无法满足,分布式事务相关规范和框架应运而生。

在这种情况下,大型厂商根据分布式事务实现规范,实现了不同的分布式框架,以简化业务开发者处理分布式事务相关工作,让开发者专注于核心业务开发。

Seataz T G t + p ) { ]就是这么一个分布式事务处理框架,Seata是由阿里开源,前身为Fescar,经过品牌升级变身Seata。

二、分布式事务规范

1.分布式事务相关概念

事务:] Q L y m个程序执行单元,是用户定义的一组操作序列,需要满足ACID属性。

本地事务:事务由本地资源管理管理

分布式事务:事务的操作位于不同的节点。

分支事务:在分布式事务中,由^ [ ; b y资源管理器管理的本地@ 8 ] O - . w事务。

全局事务:一次性操作多个资源V s o J Z 5 r N管理器完成的事务,由一组分支x ) y x Ri g X w m S ! | *务组成。

2. 分布式事务实现规范

对于本地事务,可以借助DBMS系统来实现事务的管理,但是对于分布式事务,它就无能为力了。对于分布式事务,目前主要有2种思路:XA协议的强一致规范以及柔性事务的最终一致性A f # R o规范。

2.1 XA

XA是基于2阶段提交协议设计q G - 1 ^ d H ~ A的接口标准,实现了XA规范的资源管理器就可Q n * d K ` H以参与XA全局事务。应用承担事务管理器TM工作h & S 8,数据库承担资源管理器RM工作,TM生成全局事务id,控制RM的提交和回滚。

2.2 柔性事务的最终一致性

该规范主要有3种实现方式,TCC、MQ事务消息、本 d ( ` Y 1 ) 1消息表。(还存在其他一些不常用实现方式如Saga)。

TV $ C ; j n ! aCA 7 j y B 3C:try/confirm/cancel,在try阶段锁定资源,U 2 o Y - jconfirm阶段进行提交,资源锁定失败执行cancel1 s m a B $阶段释放资源。

Seata是什么?一文了解其实现原理

MQ事务消息:前提消息系统需要支持事务如RocketMQ,在本地事_ r u 1 q . r务执行前,发送事务消息prepare,本地事务执行成功,发送事务消息commit,实现分布式事务最终一致性。如果事务消息commit失败,RocketMQ会回查消息发送者确保消息正常提交,如果步骤5执行失败,进行重试,达到最终一致性。

Seata是什么?一文了解其实现原理

本地消息表:跟MQ事务消息类似,区别在于MQ不支持事务消息( b `,需要借助本地数据库的事务管理能力。在步骤1中将需要发送的消息和本地事务一起提交到DB,借助DB的事务管理确保消息持久化。步骤2应用通过本地消息表扫描,重试发送,确保消息可以发送成功。

Seata是什么?一文了解其实现原理

三、Seata 架构

1.**系统组成**

Seata有三个核心组件:L _ Z f R

  • Transaction Coordinator(TC,事务协调器)

    维护全局事务和分支事务的状态,驱动全局事务提交或回滚。

  • Transaction Manager(TMa A F l r O ? A,事务管理器)

    定义全局事务的范围,开始事务、提交事务、回滚事务。

  • Resource Manager(RM,资源管理器):

    管理分支事务上的资源,向TC注册分支事务,汇报分支事务状态,驱动分支事务的提交或回滚。

三个组件相互协作,TC 以 Server 形式独立部署,TM和RM集成在应用中启动,其整体交互如下:

2.工作模式

Seata 支持四种工作模式:

2.1 AT(Auto Transaction)

ATi ] [ (模式是Seata默认的工作模式。需要基于支持本地 ACID 事务的关系型数据库,Java 应用,通过 JDBC 访问数据库。

2.1.1 整体机制

该模式是XA协议的演变,XA协议是基J 3 L ~ 9 o _ z于资源管理器实现,而AT并不是如此。AT的2个阶段分别是:

  • 一阶段:业务数据和回滚Y g R H G 3 P p _日志记录在同一个本地事务中提交,释放本地锁和连接{ M 2 A $资源。

  • 二阶段:提交异步化,非常快速地完成;回滚通过一阶段的回滚日志进行反向补偿。

下图中,步骤1开启全局事务;步骤2注册分支事务,这里对应着一阶段;步骤3提交或者回滚分支事务,对应着二阶段。

Seata是什么?一文了解其实现原理

2.1.2 特点

  • 优点:对代码无侵入;并发度高,本地锁在一阶段就会释放;不需要数据库对XA协议的支持。

  • 缺点:只能用在支持ACID的关系型数据库;SQL解析还不能支持全部语法。

2.2 TCC

该模式工作分为三个阶段:prepare/commit/cancel。

2.2.1 整体机制

  • TM向TC申请全局事务XID,传播给各个子调用。

  • 子调用的所在^ f t q j CTM h { F A ! , R s向TC注册分支事: + P ^ t H N C Z务,并执行本地prepare,并向TC报告执行结果。

  • TC根据各分支事务的执行结果确定二阶段是执a k G K ^ 8 v Q行commit或rollback。

Seata是什么?一文了解其实现原理

2.2W 5 ,.2 特点

  • 优点:不依赖本地a k m 0 R Q O R i事务。

  • 缺点:回滚逻辑依赖手动编码;业务侵入性较大。

2.3Saga 模式

2.3.1 Saga 是什么?

1987年普林斯顿大学的Hector Garcia-Molina和Kenneth Salem发表了一篇Paper St . : Uagas,讲述的是如何处理long lived transaction(长活事务)。Sag0 V n [a是一个长活事务可被分解成可以交错运行的子事务& 6 x % 8 ! 1 i集合。论文见这里。

简单来说,Saga将一个长事务(T)分解成一系列Sub事务(Ti),每个Sub事务X a | 9都有对应的补偿动作(Ci),用于撤销Ti事务产生的影响。Sub事务是直接提交到库,在出现异常时,逆向进行补偿。

因此Saga事务的组成有2种:

  • T1, T2, T3, ..., Tn

  • T1, T2, ..., Tj, Cj,..., C2, C1,其中0 < j < n

第一种就是正常提交的情况,第二种在提交Tj事o 9 Y P @ l 7 u =务出现异常,开始逆向补偿的情况。

Sagak m V 6 m G模式是Set d } @ T b F M Lata提供的长事务解决方案。例如全局事务中涉及到外部系统,无b 8 S 0 3 r法管理它的资源管理器,让它改造成TCC也不好实行,这时就可以采用此类方案。

2.3.2 整体机制

在Saga模式中,业务流程^ y [ W ^ p中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务[ v X ) q开发实现。

上图中对于多个分支事务,省略了多次出现的 2.* 步骤。对于全局事务执行过程中业务应用宕机情况,业务应用集群中对等节点会通过从TC获取相关会话,从DB加载I q O O详细信息来恢复状态机。

2.3.3 特点

  • 优点:一阶段提交本地事务,无锁,高性能;事件驱# y k | { ]动架构,参与者 D y J g T 2可异步执行,高吞吐;补偿服务易于实现。

  • 缺点:不保证隔离性。

2.4XA模式

XA是基b | V ] , H C ? ^于二阶段提交设计的接口标准。对于支持XA的资源管理器,借助Seata框架的XA模式,会使XA方案更简U O o 9 k 1单易用。使用前提:需要分K C X Q支数据库支持XA 事务,应用为 Java应用,且使用JDBC访问数据库。

2.4.1 整体机制

在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机w 9 k O # m / b制来管理) E _分支事务的一种 事务模式。

  • 执行阶段:业务sql在XA分支中执行,由分支事务的RM管理器管理,然后执行XA prepare。% s L _ / ; e a `

  • 完成阶段:j i 5TM根据各个8 B i分支执行结果通过TC通知+ f 0 A各个分支执行_ $ lXA commit或者V T : rXA rollback。

Seata是什么?一文了解其实现原理

2.4.2**特点**

  • 优点:继承了XA协议的优势,事务具有强一致性。

  • 缺点:同样继承了XA协议的劣势,由于分支事务长时间开启,并发度低。

2.5 Seata 各模式对比

分布式事务方案没有银弹,根据自己的业务特性选择合适的模式。例如追求强一致性,可以选择AT和XA,存在和外部系统对接,可以选择7 & 3 oSaga模式,不能依赖本地事务,可以采用TCC等等。结合各模式的优缺点进行选择。

Seata是什么?一文了解其实现原理

四、AT 模式核心实现

鉴于Seata支持的模式较多,而其默认的模式是AT,为节省篇幅,以下围绕AT模式分析其相关的核心模块实现。

1.事务协调器的启动

TC(事务协调器)以独立的服务启动,? f $ O M f f . ^作为Server,维护全局事务和分支事务的状态,驱动全] f 局事务提交或回滚。下面是TC的启动流程:

Seata是什么?一文了解其实现原理

2.**事务管理器的启动**

TM(事务管理器)集成在应用中启动,负责定义全局事务的范围,开始事务、提交事务、回滚事务。
TM所在v 4 +应用中需要配置G| ( / & _ 2lobalTransactionScannerbean,在应用启动时会进行如下初始化流程:

3.资源管理器的启动

RM(资源管理器)集成在应用中启动,负责管理分支事务上的资源,向TC注册分支事务,汇报分支事务状态? D ` h / ! r *,驱动分支事务的提交或回滚。
RM所在的应用中除了需要跟TM一样配置V ? % ] m A = GlobalTransactionScanner以启动RMClient,还^ F o D @ W s [需要配置DataSourceProxy,以实现对数据源访问代理。该数据源代理实现了sql的解析 →生成undo-log →业务sql和uq a b K f lndo-log一并本地提交等操作。

4. 全局事务的工作流程

下面以一个简单的例子来说明全局事务的工作1 9 | [原理

  • BusinessService:发起购买服务

  • StorageService:库存管理服务

购买操作实现在businessService.purchase中,purchase方法实现s 4 D n ; %上通过GlobalTransaction注解,通过Dubbo服务,调用了库存服务deduct方法方法,样例如下:

@GlobalTransactional(timeoutMiT + ] | K Olls = 300000, name = "dubbo-demo-tx")
public void purchase(String userId, String commodityCode, int orderCount) {
storageService.deduct(commodityCod` + Z - B v Pe, orderCount);
// throw new RuntimeException("xxx");
}

4.1 成功的全局事! z 3 @ - ` ] S务处理流程

4.2 成功的全局事务处理流程

} L W 8 h R ( ^里设定BusinessService在成功调用StorageService后,本地出现异常。

5.写隔离实现

I M B I S局事务未提交,分支事I i I l V务本地已经提交的情况下(假设修改了资源A),如何避免其他事务在此时修改资源A?Seata采用全局锁来实现,L a W其流程如下:

Seata是什么?一文了解其实现原理

6.读隔离实现

在数据库本地隔离级别为读已提交或以l D 2 E I k 上的基础上,Seata提供了读未提交,这个很好理解,全局事务提交前分支事# ( 5 f G务本地已经提交。如果想要实现读已提交,则需要在select语句上加fo1 i 0 / ur update。

五、总结

Seata是Java领域很强大的分布式事务框架,其支持了多种模式。其中默认支持的AT模式,相比于传统的2PC协议(基于数据库的XA协议),很好地解决了2PC长期锁资源的问题,提高了并发度。Seata支持的各个模式中,AT模式对业务零***实现分布式事务,对于开发者更加m T J . ! M . a z友好。另外Seata的Server在选择合适的存储介质时可以进行集群模式,G ( *减少单点故障影响。

本文主要参考# } E A t官网和部分博客,同时阅读了AT模式实现源o 5 )码,如果有不对的地方,望指出,一起讨论交流。

六、参考

  • Seata的Saga模式

  • 根据GlobalTransactional注解生成代理类

  • Seata项[ 1 Q目地址

  • Seata使用

作者:vivo官网商城开发团队