分布式事务之 Seata

在企业应用程序开发中,我们生产环境会不止一台存储节点,特别是在微服务领域中,我们会设计每个业务Service模块都会对应一个自身业务模块的DB存储节点。然后再对这个DB存储节点做高可用部署,如主从同步,半同步,异步复制+主从切换这些方案,并且后续当数据库数据体积越来越庞大时,便要继续对存储节点做垂直或水平拆分。

那么我们在编写Service中的业务逻辑时,肯定会遇到一个业务操作会调用到其他不同的业务模块,那么对应的产生数据就会落盘到不同的存储节点中,为了保障多个数据库实例之间的事物ACID特性,故此我们肯定需要通过一些手段来保障两个不同的数据库存储节点对这个业务开启的事物作出相同的操作,达到以下效果:

1、如果整个业务调用链路均成功,那么所有对应的数据库做事物提交。

2、如果调用链路中抛出了异常,那么所有对应的数据库做回滚操作。

为了到达这个目的,故此出现了Seata:

在这些分布式事务解决方案中,一般有以下这些角色:

RM (Resource Manager) 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

TC (Transaction Coordinator) - 事务协调者

TM (Transaction Manager) - 事务管理器,AP上进行集成

AP (Application Program),访问RM的应用程序

图中的TC,事务协调者组件需要进行单独部署,并且加入到整个微服务集群的注册中心中,目前所有常见的注册中心均支持,如Nacos,Zookeeper,Etcd,Eureka,Consul。并需要在AP中做对应连接配置设置(需要保障TC模块的高可用性,如果该模块宕机,分布式事务将无从谈起)。

事务分组与高可用
Seata 事务分组与高可用的最佳实践

刚性事务:通常无业务改造,强一致性,原生支持回滚/隔离性,低并发,适合短事务。

对应方案:XA 协议(2PC、JTA、JTS)、3PC


柔性事务:有业务改造,最终一致性,实现补偿接口,实现资源锁定接口,高并发,适合长事务。

对应方案:TCC/FMT、Saga(状态机模式、Aop模式)、本地事务消息、消息事务(半消息)


什么是长事物,什么是短事物呢?

长事物:长时间占用了一个资源(X锁,间隙锁,表锁,页锁),修改的数据较多或者执行速度较慢,业务流程长,那么其他事物需要访问此资源时将会被堵塞等待,这样便容易导致死锁。

短事物:对资源的占用很短暂,修改的数据较少或执行速度很快完成,业务流程短,事物很快结束,故此产生死锁的概率较小。


目前Seata中间件支持4中分布式事务的管理模式:

1、AT模式

AT模式算是Seata中最具特色的模式,总的来说就是优化过的2PC模式,也是属于二阶段提交的一种,使用这种模式需要在本地数据库节点中创建一张undolog表,通过代理DataSourceProxy从而拦截到应用程序执行的DML SQL语句,对SQL语句进行语义解析,从而转化为查询SQL语句,把执行前对应的数据镜像存入undolog表中以作为二阶段回滚使用。以上这些步骤均为代理模式完成,所以实现了零业务逻辑代码入侵。

Seata AT 模式
Seata AT 模式。

但此方案并非完美,存在一定的问题,性能损失还是相当大的,一次DML SQL将会多出一次语义转化并执行查询SQL,以及新增数据镜像到undolog表,如果发生二阶段回滚,还需要获取本地锁,再操作回退原始数据镜像。并且存在一个比较严重的问题,如果在回滚的时候,其他本地事物没有走Seata的全局事物管理去获取全局锁,而是直接走了本地事物修改了undolog中记录的某条数据镜像所对应的数据信息,那么在Seata进行回滚时将会发现回滚数据镜像与当前本地数据匹配不了,将会出现数据丢失问题,有点类似于CAS中的ABA问题。

2、TCC模式

TCC模式较为简单,其实也是2PC两阶段提交,此模式和AT模式的区别就是需要自己去实现一阶段 prepare 准备, 二阶段commit,以及rollback逻辑。Seata的事物管理器会依次调用实现方法。

Seata Tcc 模式
Seata Tcc 模式。

3、Saga模式

Saga是由一系列的本地事务构成。每一个本地事务在更新完数据库之后,会发布一条消息或者一个事件来触发Saga中的下一个本地事务的执行。如果一个本地事务因为某些业务规则无法满足而失败,Saga会执行在这个失败的事务之前成功提交的所有事务的补偿操作。所以Saga算是实现起来最为繁琐的一种模式,但基于Saga的状态机可用非常灵活的控制每一个分布式事物步骤。对于长事物的场景,则更需要自身更细粒的控制每一种情况。不关注整个分布式事务的状态,只需要做好每个事件的处理,以及本身方法的幕等性即可。但他的事物没有阶段提交一说,所以事物都是本地提交,如果在回滚途中,其他数据进行了数据读取并修改值,则会发生胀读,胀写的情况,对于这种情况我想还需要自己去实现对应的一套txid的方案,以避免胀读,胀写。

Seata Saga 模式
Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

4、XA模式

XA模式首先必须需要数据库支持XA协议,其实现有2PC,3PC,不过其中的实现完全是由数据库自身提供,应用程序不需要做任何处理,本质和AT模式很相似,但区别就是数据库在进行XA事物的过程中会为了强一致性而保持数据资源持续占用(X锁,间隙锁,表锁,页锁都是根据数据范围而定),如果是长事物,则在高并发场景非常容易导致死锁出现。并且对于数据库来说性能下降得比较厉害。如果都是短事物则可用使用此模式。

Seata XA 模式
Seata XA 模式。


随心笔记

hi 欢迎留言,共同探讨IT技术~