PancrasL的博客

Seata——分布式事务中间件

2021-07-16

img

1. Seata简介

Seata(Simple Extensible Autonomous Transaction Architecture) 是 阿里巴巴开源的分布式事务中间件,以高效并且对业务 0 侵入的方式,解决微服务场景下面临的分布式事务问题。

Seata支持AT、TCC、SAGA 和 XA 事务模式。

事务模式对比

分布式事务模式 介绍 技术栈
AT 模式 无侵入的分布式事务解决方案,适用于不希望对业务进行改造的场景,几乎0学习成本(sql都由框架托管统一执行,会存在脏写问题) seata、shardingsphere
TCC 模式 高性能分布式事务解决方案,适用于核心系统等对性能有很高要求的场景(第一阶段会产生行锁,事务执行太久会锁行很久 seata、service-comb
Saga 模式 长事务解决方案,适用于业务流程长且需要保证事务最终一致性的业务系统(第一阶段就操作DB,会存在脏读问题) seata、shardingsphere、service-comb
XA模式 分布式强一致性的解决方案,但性能低而使用较少。 seata、shardingsphere

1.1 核心组件

  • TC (Transaction Coordinator) - 事务协调者

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

  • TM (Transaction Manager) - 事务管理器

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

  • RM (Resource Manager) - 资源管理器

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

image-20210716124159995

1.2 全局事务和分支事务

image-20210716124213606

2. Seata事务过程解析

2.1 全局事务扫描器

通过再配置文件中配置GlobalTransactionScanner,这个实例在项目启动时会扫描所有实例,具体实现见【spring】模块。并将标注了@GlobalTransactional注解的方法织入GlobalTransactionalInterceptor的invoke方法逻辑。同时应用启动时,会初始化TM(TmRpcClient)和RM(RmRpcClient)的实例,这个时候,服务已经和TC事务控制中心勾搭上了。在往下看就涉及到TM模块的事务模板类TransactionalTemplate。

1
2
3
4
<bean class="com.alibaba.fescar.spring.annotation.GlobalTransactionScanner">
<constructor-arg value="dubbo-demo-app"/>
<constructor-arg value="my\_test\_tx_group"/>
</bean>

2.2 【TM】模块启动全局事务

DefaultGlobalTransaction :全局事务具体的开启,提交、回滚动作

DefaultTransactionManager :负责使用TmRpcClient向TC控制中心发送指令,如开启全局事务(GlobalBeginRequest)、提交(GlobalCommitRequest)、回滚(GlobalRollbackRequest)、查询状态(GlobalStatusRequest)等。

以上是TM模块核心内容点,TM模块完成全局事务开启后,接下来就开始看看全局事务iD,xid是如何传递、RM组件是如何介入的

2.3 【dubbo】全局事务xid的传递

首先是xid的传递,目前已经实现了dubbo框架实现的微服务架构下的传递,其他的像spring cloud和motan等的想要实现也很容易,通过一般RPC通讯框架都有的filter机制,将xid从全局事务的发起节点传递到服务协从节点,从节点接收到后绑定到当前线程上线文环境中,用于在分支事务执行sql时判断是否加入全局事务。

2.4 【RM】模块本地资源管理的介入

3. 各事务模式介绍

3.1 AT模式(Automatic Transaction)

image-20210716124237493

3.2 SAGA模式

image-20210716124304758

3.3 XA模式

两阶段提交理论的一个广泛工业应用是XA协议。目前几乎所有收费的商业数据库都支持XA协议。XA协议已在业界成熟运行数十年,但目前它在互联网海量流量的应用场景中,吞吐量这个瓶颈变得十分致命,因此很少被用到。

img

3.4 TCC模式(Try、Confirm、Cancel)

image-20210716133155144 image-20210716124251062

TCC事务其实主要包含两个阶段:Try阶段、Confirm/Cancel阶段。TCC 模式需要用户根据自己的业务场景实现 Try、Confirm 和 Cancel 三个操作,事务发起方在一阶段执行 Try 方式,在二阶段提交执行 Confirm 方法,二阶段回滚执行 Cancel 方法。

TCC的核心思想是try阶段检查并预留资源,确保在confirm阶段有资源可用,这样可以最大程度的确保confirm阶段能够执行成功,避免死锁问题。

(1)try:尝试执行业务

完成所有业务检查(一致性)

预留必须业务资源(准隔离性)

(2)confirm:确认执行业务

真正执行业务

不作任何业务检查

只使用Try阶段预留的业务资源

Confirm操作必须保证幂等性

(3)cancel:取消执行业务

释放Try阶段预留的业务资源

Cancel操作必须保证幂等性

TCC具有三大特性:允许空回滚、防悬挂控制、幂等控制。

允许空回滚

当 Try 接口因丢包出现超时,或未收到Try而收到Cancel时,事务管理器会触发Cancel 接口执行回滚,如果执行时发现没有对应的事务不存在时,需要返回回滚成功,以让事务服务管理器认为已执行回滚,避免不断重试。

防悬挂控制

悬挂:Try 由于网络拥堵而超时,事务管理器生成回滚,触发 Cancel 接口,而最终又收到了 Try 接口调用,即Cancel 比 Try 接口先执行。

因允许空回滚的逻辑,事务管理器认为事务已回滚成功,则此时的 Try 接口不应该执行,否则会产生数据不一致。Cancel空回滚返回成功之前标识这条记录已回滚,Try接口先检查该事务是否被标记为回滚成功来决定是否执行。

幂等控制

幂等性:对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。因为网络抖动或拥堵可能会超时,事务管理器会对资源进行重试操作,所以很可能一个业务操作会被重复调用,为了不因为重复调用而多次占用资源,需要在服务设计时进行幂等控制。

4. TCC二阶段异步提交功能实现

4.1 总体思路

修改tcc模块和server模块的相关代码,参考异步提交的实现,完成异步回滚特性,通过异步操作提升回滚性能,从而降低全局回滚的时间成本。

同步全局回滚时,跳过可异步执行的分支,将它们交由handleAsyncRollbacking()来处理。特性的实现主要涉及以下内容:

  • 为分支调用过程的方法添加rollbackType参数,以及对应的日志。

  • 实现handleAsyncRollbacking()的处理逻辑。

  • 通过默认参数保证不同版本之间的兼容性问题。

4.2 方案设计

  • 修改TCC的注解@TwoPhaseBusinessAction,添加TCCRollbackType rollbackType() default TCCRollbackType.SyncRollback

  • 分支注册接口,添加参数TCCRollbackType rollbackType,且RPC交易时的序列化中,添加对该参数的序列化

  • TC端三种store模式,添加对rollbackType的持久化功能。db模式添加字段rollback_type

  • 同步全局回滚时,将可异步执行的分支加入到待处理集合中

  • 实现handleAsyncRollbacking()的处理逻辑:

    • 配置:修改server模块,使该方法由异步定时任务触发。
    • 算法逻辑:获取待异步处理的分支,枚举回滚分支,调用doGlobalRollback方法执行回滚操作。

4.3 方案实现

首先,学习异步提交的代码接口设计,设计异步回滚操作的代码接口,参考其实现完成TCC异步回滚的特性。其次,编写的测试用例,保证功能的正常执行,在测试时需要注意不同版本之间的兼容性,保证高版本兼容低版本。最后,撰写方案测试和使用文档。

Reference:
[1] https://seata.io/zh-cn/blog/seata-analysis-simple.html