Seata之TCC模式解读

目录

基本介绍

起源

概述

案例流程分析

TCC注意事项

空回滚

幂等

悬挂

具体使用 

@LocalTCC

@TwoPhaseBusinessAction  

小结 


基本介绍

起源

关于TCC的概念,最早是由Pat Helland于2007年发表的一篇名为《Life beyond Distributed Transactions:an Apostate’s Opinion》的论文提出。

在该论文中,TCC还是以Tentative-Confirmation-Cancellation命名。正式以Try-Confirm-Cancel作为名称的是Atomikos公司,其注册了TCC商标。
 

概述

TCC是Try-Confirm-Cancel的简称。 

TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复。需要实现三个方法:

  • Try:资源的检测和预留。做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm 一起才能真正构成一个完整的业务逻辑。

  • Confirm:完成资源操作业务;要求 Try 成功 Confirm 一定要能成功。做确认提交,Try阶段所有分支事务执行成功后开始执行 Confirm。通常情况下,采用TCC则 认为 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。若Confirm阶段真的出错了,需引入重试机制或人工处理。

  • Cancel:预留资源释放,可以理解为try的反向操作。在业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,采 用TCC则认为Cancel阶段也是一定成功的。若Cancel阶段真的出错了,需引入重试机制或人工处理。

TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作,若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel 操作若执行失败,TM会进行重试。 

与AT模式与TCC模式的对比 

                        AT模式                TCC模式
一阶段 prepare 在本地事务中,一并提交业务数据更新和相应回滚日志记录调用 自定义的 prepare 逻辑
二阶段 commit马上成功结束,自动异步批量清理回滚日志调用 自定义的commit 逻辑
二阶段 rollback通过回滚日志,自动 生成补偿操作,完成数据回滚。调用 自定义的rollback 逻辑
其他支持本地 ACID 事务 的 关系型数据库不依赖于底层数据资源的事务支持

TCC支持把自定义的分支事务纳入到全局事务的管理中。 

案例流程分析

假设一个扣减用户余额的业务。假设账户A原来余额是100,需要余额扣减30元。

 阶段一( Try ):检查余额是否充足,如果充足则冻结金额增加30元,可用余额扣除30

 

总金额 = 冻结金额 + 可用金额,数量依然是100不变。事务直接提交无需等待其它事务。

阶段二(Confirm):,现在库存充足,可以提交(Confirm),则冻结金额扣减30确认可以提交,不过之前可用金额已经扣减过了,这里只要清除冻结金额就好了

阶段二(Canncel):如果库存不足,需要回滚(Cancel),则冻结金额扣减30,可用余额增加30需要回滚,那么就要释放冻结金额,恢复可用金额:

TCC注意事项

空回滚

  • 在没有调用 TCC 资源 Try 方法的情况下,调用了二阶段的 Cancel 方法,Cancel 方法需要识别出这是一个空回 滚,然后直接返回成功。
  • 出现原因是当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败,这个时候其实是没有执行Try阶 段,当故障恢复后,分布式事务进行回滚则会调用二阶段的Cancel方法,从而形成空回滚。
  • 解决思路是关键就是要识别出这个空回滚。思路很简单就是需要知道一阶段是否执行,如果执行了,那就是正常回 滚;如果没执行,那就是空回滚。前面已经说过TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分 布式事务调用链条。再额外增加一张分支事务记录表,其中有全局事务 ID 和分支事务 ID,第一阶段 Try 方法里会 插入一条记录,表示一阶段执行了。Cancel 接口里读取该记录,如果该记录存在,则正常回滚;如果该记录不存 在,则是空回滚。


幂等

  • 为了保证TCC二阶段提交重试机制不会引发数据不一致,要求 TCC 的二阶段 Try、 Confirm 和 Cancel 接口保证幂等,这样不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致数据 不一致等严重问题。
  • 解决思路在上述“分支事务记录”中增加执行状态,每次执行前都查询该状态。

悬挂

  • 悬挂就是对于一个分布式事务,其二阶段 Cancel 接口比 Try 接口先执行。
  • 出现原因是在 RPC 调用分支事务try时,先注册分支事务,再执行RPC调用,如果此时 RPC 调用的网络发生拥堵, 通常 RPC 调用是有超时时间的,RPC 超时以后,TM就会通知RM回滚该分布式事务,可能回滚完成后,RPC 请求 才到达参与者真正执行,而一个 Try 方法预留的业务资源,只有该分布式事务才能使用,该分布式事务第一阶段预 留的业务资源就再也没有人能够处理了,对于这种情况,我们就称为悬挂,即业务资源预留后没法继续处理。
  • 解决思路是如果二阶段执行完成,那一阶段就不能再继续执行。在执行一阶段事务时判断在该全局事务下,“分支 事务记录”表中是否已经有二阶段事务记录,如果有则不执行Try。

具体使用 

@LocalTCC

该注解需要添加到上面描述的接口上,表示实现该接口的类被 seata 来管理,seata 根据事务的状态,自动调用我们定义的方法,如果没问题则调用 Commit 方法,否则调用 Rollback 方法。

@LocalTCC
public interface AccountTCCService {

}

@TwoPhaseBusinessAction  

该注解用在接口的 Try 方法上,该注解的用法如下:

@LocalTCC
public interface AccountTCCService {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                @BusinessActionContextParameter(paramName = "money")int money);

    boolean confirm(BusinessActionContext ctx);

    boolean cancel(BusinessActionContext ctx);
}

该注解包含这几个属性

  • name 为 tcc 方法的 bean 名称,需要全局唯一,一般写方法名即可;
  • commitMethod 自然地写 Commit 方法的方法名;
  • rollbackMethod 写 Rollback 方法的方法名; 

@BusinessActionContextParameter
该注解用来修饰 Try 方法的入参,被修饰的入参可以在 Commit 方法和 Rollback 方法中通过 BusinessActionContext 获取。 

最后对接口进行实现即可:

@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private AccountFreezeMapper freezeMapper;

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        // 0.获取事务id
        String xid = RootContext.getXID();
        // 1.扣减可用余额
        accountMapper.deduct(userId, money);
        // 2.记录冻结金额,事务状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);
        freezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        // 1.获取事务id
        String xid = ctx.getXid();
        // 2.根据id删除冻结记录
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        // 0.查询冻结记录
        String xid = ctx.getXid();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        // 1.恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        // 2.将冻结金额清零,状态改为CANCEL
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }
}

小结 

性能:好

模式:AP,存在数据不一致的中间状态

难易程度:复杂,SEATA TC只负责全局事务的提交与回滚指令,具体的回滚处理全靠程序员自己实现(手动写代码)

使用要求

  • 所有服务与数据库必须要自己拥有管理权
  • 支持异构数据库,可以使用不同选型实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/134626.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《网络协议》05. 网络通信安全 · 密码技术

title: 《网络协议》05. 网络通信安全 密码技术 date: 2022-09-10 15:16:15 updated: 2023-11-12 07:03:52 categories: 学习记录:网络协议 excerpt: 网络通信安全(ARP 欺骗,DoS & DDoS,SYN 洪水攻击,LAND 攻击&a…

2个器件,做1个恒流源

在项目中经常要用到恒流源,查找资料可以使用电压源芯片LM317构造一个电流源芯片。本文将电压源加上一个电阻改为电流源,这种设计思路可以扩展到其他类型的电源芯片上,如开关电源及其他类型的线性电源,关键点在于基准电压VREF的使用…

数据库 关系数据理论

问题 数据冗余更新异常插入异常删除异常 一个好的模式应当不会发生插入异常、删除异常和更新异常,数据冗余应尽可能少 数据依赖 定义:一个关系内部属性与属性之间的一种约束关系(该约束关系是通过属性间值的相等与否体现出来数据间相关联…

git02->gui图形化界面使用,ssh协议,idea集成GIT

gui图形化界面使用ssh协议idea集成GIT 1.gui图形化界面使用 2.ssh协议 git/github生成密钥并通过 操作分为本地电脑配置和github网站配置 第一步:本地电脑配置 右键空白处,选择Git Bash Here打开相关命令窗口 1.配置用户名和邮箱(如果已经配…

Go 14岁了

今天我们庆祝Go开源十四周年!Go度过了美好的一年,发布了两个功能齐全的版本和其他重要的里程碑。 我们在2月份发布了Go 1.20,在8月份发布了Go 1.21,更多地关注实现改进而不是新的语言更改。 在Go 1.20中,我们预览了配置…

基于多尺度分形残差注意力网络的超分辨率重建算法

1.引言 深度神经网络可以显著提高超分辨率的质量,但现有方法难以充分利用低分辨率尺度特征和通道信息,从而阻碍了卷积神经网络的表达能力。针对此类问题,本章提出了一种多尺度分形残差注意力网络(Multi-scale Fractal Residual A…

优秀智慧园区案例 - 深圳特区建发创智云城智慧园区,万字长文解析先进智慧园区建设方案经验

一、项目背景 1、项目背景 创智云城项目位于大湾区核心城市之一的深圳,且地处GDP第一的科技创新核心区——南山区,136万㎡新兴产业智慧之城矗立于湾区核心创新高地。项目所处西丽湖国际科教城,最具发展潜力,规划全域面积约57平方…

JavaWeb Day09 Mybatis-基础操作02-XML映射文件动态SQL

目录 Mybatis动态SQL介绍​编辑 一、案例 ①Mapper层 ②测试类 ③EmpMapper.xml ④结果​ 二、标签 (一)if where标签 ​①EmpMapper.xml ②案例 ③总结 (二)foreach标签 ①SQL语句 ②Mapper层 ③EmpMapper.xml ④…

N-133基于springboot,vue小说网站

开发工具:IDEA 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 系统分前后台,项目采用前后端分离 前端技术:vueelementUI 服务端技术:springbootmybatis-plus 本项…

141.环形链表(LeetCode)

想法一 快慢指针,设置slow和fast指针,slow一次走一步,fast一次走两步,如果链表有环,它们最终会相遇,相遇时返回true;如果链表无环,它们最终走到空,跳出循环,…

企业邮箱本地私有化部署解决方案

随着互联网化进程不断深入,加快推进企业信息化系统建设,已经成为提高企业核心竞争力的重要途径。企业对企业邮箱系统的需求越来越大,企业邮箱系统作为企业级通讯工具中的利器,在协同办公和内外业务交流上发挥着无可替代的巨大作用…

国际阿里云:Windows系统ECS实例中CPU使用率较高问题的排查及解决方案!!

问题现象 Windows系统ECS实例中CPU使用率较高,即CPU使用率≥80%。 问题原因 CPU使用率较高可能有以下原因。 ECS实例遭到病毒木马入侵。 ECS实例中第三方杀毒软件运行。 ECS实例中应用程序异常、驱动异常、高I/O使用率或高中断处理的应用程序。 解决方案 步骤…

[工业自动化-13]:西门子S7-15xxx编程 - 分布式从站 - 硬件配置

目录 前言: 一、通过博图软件完成对ET200 SP分布式从站的硬件配置 二、从站组态配置的常见问题与解决 三、分布式从站与CPU的profiNet连接 3.1 概述 3.2 配置主站与从站的profinet连接 四、Profinet和普通以太网区别 4.1 概述 4.2 协议栈 五、主站与从站连…

将复数中的虚部取反 即对复数求共轭 numpy.conjugate()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 将复数中的虚部取反 即对复数求共轭 numpy.conjugate() [太阳]选择题 请问以下代码中执行语句输出结果是? import numpy as np a np.array([1 2j, 3 - 4j]) print("【显示…

图论13-最小生成树-Kruskal算法+Prim算法

文章目录 1 最小生成树2 最小生成树Kruskal算法的实现2.1 算法思想2.2 算法实现2.2.1 如果图不联通,直接返回空,该图没有mst2.2.2 获得图中的所有边,并且进行排序2.2.2.1 Edge类要实现Comparable接口,并重写compareTo方法 2.2.3 取…

SAM + YOLO 智能抠图

在计算机视觉领域,对象检测和实例分割是使机器能够理解视觉数据并与之交互的关键任务。 准确识别和隔离图像中的物体的能力具有许多实际应用,从自动驾驶车辆到医学成像。 在这篇博文中,我们将探索如何在 Roboflow 和 Ultralytics YOLOv8 的帮…

服务器安全组端口规则配置手册

具体操作如下: 1、配置规则 进入服务器实例列表,服务器,选择安全组,点击右侧配置规则 2、添加安全组规则 点击右上方添加安全组规则 3、添加端口 添加6个端口:80,21,8888,888,443,3306,授权对象&#x…

openEuler编译安装nmon性能监控工具及可视化分析工具

ln 介绍 nmon(short for Nigel’s Monitor)是一个性能分析工具,由蓝色巨人IBM开发,最早用于自家操作系统UNIX,AIX (Advanced Interactive eXecutive)。现在也能用在Linux上。它可以显示系统的…

跨域:利用JSONP、WebSocket实现跨域访问

跨域基础知识点:跨域知识点 iframe实现跨域的四种方式:http://t.csdnimg.cn/emgFr 注:本篇中使用到的虚拟主机也是上面iframe中配置的 目录 JSONP跨域 JSONP介绍 跨域实验: WebSocket跨域 websocket介绍 跨域实验 JSONP跨域…

Javaweb之javascript的DOM对象的详细解析

1.5.3 DOM对象 1.5.3.1 DOM介绍 DOM:Document Object Model 文档对象模型。也就是 JavaScript 将 HTML 文档的各个组成部分封装为对象。 DOM 其实我们并不陌生,之前在学习 XML 就接触过,只不过 XML 文档中的标签需要我们写代码解析&#x…