[深度] Seata TCC 分布式事务源码分析

Seata 是什么

Seata 是阿里近期开源的分布式事务框架,地址:https://github.com/seata/seata。框架包括了集团的 TXC(云版本叫 GTS)和蚂蚁金服的 TCC 两种模式,短短数月 Github 上的 star 数已经接近一万,算是目前唯一有大厂背书的分布式事务解决方案。

TXCSeata 中又叫 AT 模式,意为补偿方法是框架自动生成的,对用户完全屏蔽,用户可以向使用本地事务那样使用分布式事务,缺点是仅支持关系型数据库(目前支持 MySQL),引入 Seata AT 的服务需要本地建表存储 rollback_info,隔离级别默认 RU 适用场景有限。

TCC 不算是新概念,很早就有了,用户通过定义 try/confirm/cancel 三个方法在应用层面模拟两阶段提交,区别在于 TCC 中 try 方法也需要操作数据库进行资源锁定,后续两个补偿方法由框架自动调用,分别进行资源提交和回滚,这点同单纯的存储层 2PC 不太一样。蚂蚁金服向 Seata 贡献了自己的 TCC 实现,据说已经演化了十多年,大量应用在在金融、交易、仓储等领域。

分布式事务的诞生背景

早期应用都是单一架构,例如支付服务涉及到的账户、金额、订单系统等都由单一应用负责,底层访问同一个数据库实例,自然事务操作也是本地事务,借助 Spring 可以轻松实现;但是由于量级越来越大,单一服务需要进行职责拆分变为三个独立的服务,通过 RPC 进行调用,数据也存在不同的数据库实例中,由于这时一次业务操作涉及对多个数据库数据的修改,无法再依靠本地事务,只能通过分布式事务框架来解决。

TCC 就是分布式事务的一种解决方案,属于柔性补偿型,优点在于理解简单、仅 try 阶段加锁并发性能较好,缺点在于代码改造成本。

什么是 TCC 本文就不再赘述了,TCC 的概念本身并不复杂

Seata TCC 使用方法

在分析源码之前,我们先简要提及下 Seata TCC 模式的使用方法,有助于后续理解整个 TCC 流程。

Seata TCC 参与方

Seata 中的 TCC 模式要求 TCC 服务的参与方在接口上增加 @TwoPhaseBusinessAction 注解,注明 TCC 接口的名称(全局唯一),TCC 接口的 confirmcancel 方法的名称,用于后续框架反射调用,下面是一个 TCC 接口的案例:

public interface TccAction {
   
    @TwoPhaseBusinessAction(name = "yourTccActionName", commitMethod = "confirm", rollbackMethod = "cancel")
    public boolean try(BusinessActionContext businessActionContext, int a, int b);
    public boolean confirm(BusinessActionContext businessActionContext);
    public boolean cancel(BusinessActionContext businessActionContext);
}

紧接着定义实现类 Impl 实现这个接口,为三个方法提供具体实现。最后将参与方服务进行发布,注册到远端,主要为了后续能让 Seata 框架调用到参与方的 confirm 或者 cancel 方法闭环整个 TCC 事务。

Seata TCC 发起方

Seata TCC 的发起方类似于我们上图中的 payment service,参与方需要在业务方法上增加 @GlobalTransactional 注解,用于开启切面注册全局事务,业务方法中调用 TCC 参与方的若干 try 方法,一旦业务方法调用成功,Seata 框架会通知 TC 回调这些参与方的 confirmcancel 方法。

源码分析

SeataTCC 模式的源码并不复杂,主要集中于:

module class 功能
seata-spring GlobalTransactionalInterceptor.class 全局事务切面逻辑,包括注册全局事务,拿到 xid
seata-spring TccActionInterceptor.class TCC 参与方切面逻辑
seata-tcc TCCResourceManager.class 解析 TCC Bean,保存 TCC Resources,便于后续回调
seata-tcc ActionInterceptorHandler.class TCC 分支事务注册实现
seata-server DefaultCoordinator.class、FileTransactionStoreManager.class 主要是 TC 的实现、事务存储等实现
注册 TCC Resources

Seata 中一个 TCC 接口被称作一个 TCC Resources,其结构如下:

public class TCCResource implements Resource {
   

    private String resourceGroupId = "DEFAULT";

    private String appName;

    private String actionName; // TCC 接口名称     

    private Object targetBean; // TCC Bean

    private Method prepareMethod; // try 方法

    private String commitMethodName;

    private Method commitMethod; // confirm 方法

    private String rollbackMethodName;

    private Method rollbackMethod; // cancel 方法

    // …… 省略
}

Seata 解析到应用中存在 TCC Bean,则通过 parserRemotingServiceInfo 方法生成一个 TCCResource 对象,进而调用 TCCResourceManager 类的 registerResource 方法,将 TCCResource 对象保存到本地的 tccResourceCache 中,它是一个 ConcurrentHashMap 结构,同时通过 RmRpcClient 将该 TCCResourceresourceIdaddress 等信息注册到服务端,便于后续 TC 通过 RPC 回调到正确的地址。

// 解析 TCCResource 的部分代码
Class<?> interfaceClass = remotingBeanDesc.getInterfaceClass();
Method[] methods = interfaceClass.getMethods();
if(isService(bean, beanName)){
   
    try {
   
        // 如果是 TCC service Bean,解析并注册该 resource
        Object targetBean = remotingBeanDesc.getTargetBean();
        for(Method m : methods){
   
            TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class);
            if(twoPhaseBusinessAction != null){
   
                // 如果有 TCC 参与方注解,定义一个 TCCResource,
                TCCResource tccResource = new TCCResource();
                tccResource.setActionName(twoPhaseBusinessAction.name());
                // TCC Bean
                tccResource.setTargetBean(targetBean); 
                // try 方法
                tccResource.setPrepareMethod(m); 
                // confirm 方法名称
                tccResource.setCommitMethodName(twoPhaseBusinessAction
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值