Seata架构篇 - TCC模式

news2024/11/15 23:47:35

TCC 模式

概述

TCC 是分布式事务中的两阶段提交协议,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel)。Try:对业务资源的检查并预留;Confirm:对业务处理进行提交,只要 Try 成功,那么该步骤一定成功;Cancel:对业务处理进行回滚,对 Try 预留的资源进行释放。

TCC 是一种侵入式的分布式事务解决方案,以上三个操作都需要业务系统自行实现,对业务系统有着非常大的侵入性,设计相对复杂,但优点是完全不依赖数据库,能够实现跨数据库、跨应用的资源管理,对这些不同数据的访问通过侵入式的编码方式实现一个原子操作,更好解决了各种复杂业务场景下的分布式事务问题。

TCC 模式最大的优势是效率高。在 try 阶段的锁定资源并不是真正意义上的锁定,而是提交了本地事务,将资源预留到中间状态,不需要阻塞等待,因此效率比其它模式更高。而且采用异步提交的方式,try 阶段执行成功后,启动定时任务异步执行 confirm/cancel 方法。

Seata TCC模式1.5.1版本的优化

代码演示

假设现在有一个业务需要同时使用服务 A 和服务 B 完成一个事务操作。

对服务 A 定义一个 TCC 接口:

public interface TccActionOne {
  
  @TwoPhaseBusinessAction(name = "DubboTccActionOne", commitMethod = "commit", rollbackMethod = "rollback")
  public boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "a") String a);
  
  public boolean commit(BusinessActionContext actionContext);
  
  public boolean rollback(BusinessActionContext actionContext);
}

对服务 B 定义一个 TCC 接口:

public interface TccActionTwo {
  
  @TwoPhaseBusinessAction(name = "DubboTccActionTwo", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true)
  public boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "b") String b);
  
  public boolean commit(BusinessActionContext actionContext);
  
  public boolean rollback(BusinessActionContext actionContext);
}

在业务系统中开启全局事务并执行服务 A 和服务 B 的 TCC 预留资源方法:

@GlobalTransactional
public String doTransactionCommit() {
  tccActionOne.prepare(null, "one");
  tccActionTwo.prepare(null, "two");
}

以上就是使用 Seata TCC 模式实现一个全局事务的例子。

使用 @GlobalTransactional 注解开启一个全局事务,而服务 A 和服务 B 的 TCC 接口为事务参与者,Seata 会把一个 TCC 接口当成一个 Resource,也叫做 TCC Resource。

TCC 接口可以是 RPC,也可以是 JVM 内部调用,这也意味着一个 TCC 接口,会有发起方和调用方两个身份。在以上例子中,TCC 接口在服务 A 和服务 B 中是发起方,在业务系统中是调用方。

Seata 启动时会对 TCC 接口进行扫描并解析,如果 TCC 接口是一个发起方,则在 Seata 启动时会向 TC 注册 TCC Resource,每个 TCC Resource 都有一个资源 id;如果 TCC 接口是一个调用方,则 Seata 会代理调用方,代理会拦截 TCC 接口的调用,即每次调用 Try 方法,会向 TC 注册一个分支事务,接着才执行原来的 RPC 调用。

当全局事务决议提交/回滚时,TC 会通过分支注册的资源 id 回调到对应参与者服务中执行 TCC Resource 的 Confirm/Cancel 方法。

原理

1.5.1版本之前

在这里插入图片描述

TM 开启全局事务时,RM 需要向 TC 发送注册信息,TC 保存分支事务的状态。TM 请求提交/回滚时,TC 需要向 RM 发送提交或者回滚信息。这样包含两个分支事务的分布式事务中,TC 与 RM 之间有四次 RPC。

1.5.1版本

在这里插入图片描述

TM 开启全局事务时,RM 不再需要向 TC 发送注册消息,而是把分支事务状态保存在了本地。TM 向 TC 发送提交或回滚消息后,RM 异步线程首先查出本地保存的未提交分支事务,然后向 TC 发送消息获取(本地分支事务)所在的全局事务状态,来决定是提交还是回滚本地事务。

这样优化后,RPC 次数减少了 50%,性能大幅提升。

处理异常

在 TCC 模型执行的过程中,可能会出现各种异常,最常见的有空回滚、幂等、悬挂等。

可以对 @TwoPhaseBusinessAction 注解的 useTCCFence 属性设置为 true,开启保护机制来解决这些问题。

并且需要在 MySQL 中创建 tcc_fence_log 表。

CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(
    `xid`           VARCHAR(128)  NOT NULL COMMENT 'global id',
    `branch_id`     BIGINT        NOT NULL COMMENT 'branch id',
    `action_name`   VARCHAR(64)   NOT NULL COMMENT 'action name',
    `status`        TINYINT       NOT NULL COMMENT 'status(tried:1;committed:2;rollbacked:3;suspended:4)',
    `gmt_create`    DATETIME(3)   NOT NULL COMMENT 'create time',
    `gmt_modified`  DATETIME(3)   NOT NULL COMMENT 'update time',
    PRIMARY KEY (`xid`, `branch_id`),
    KEY `idx_gmt_modified` (`gmt_modified`),
    KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

处理空回滚问题

空回滚指在一个分布式事务中,在没有调用参与者的 Try 方法的情况下,TM 驱动二阶段回滚调用了参与者的 Cancel 方法

比如全局事务开启后,参与者 A 分支注册完成之后会执行参与者一阶段 RPC 方法,如果此时参与者所在的机器发生宕机,网络异常都会造成 RPC 调用失败,即参与者一阶段方法没有成功执行,但是此时全局事务已经开启,最终必须要走向结束状态,在全局事务回滚时会调用参与者的 Cancel 方法,从而造成空回滚。

如何解决空回滚问题?在一阶段执行 Try 方法时,往 tcc_fence_log 表里插入一条记录(包括事务的 XID 和 BranchID 信息),status 字段值为 TRIED。在二阶段执行 Cancel 方法时判断对应记录是否存在,如果不存在,则不执行回滚操作。

处理幂等问题

幂等问题指 TC 没有收到分支事务的响应,需要进行重试,因此 Confirm/Cancel 接口需要支持幂等处理,即不会产生资源重复提交或者释放。

比如参与者执行完二阶段操作之后,由于网络抖动或者宕机问题,会造成 TC 收不到参与者执行二阶段操作的返回结果,则 TC 会重复发起调用,直到成功收到二阶段操作的执行结果。

如何解决幂等问题?提交事务时首先会判断 tcc_fence_log 表中是否有对应的记录,如果没有则插入一条记录;如果有则判断事务状态,如果状态是 COMMITED,就不会再次提交。回滚事务的逻辑与之相似。

处理悬挂问题

悬挂问题指 二阶段 Cancel 方法比一阶段 Try 方法优先执行,由于允许空回滚的原因,执行完二阶段 Cancel 方法之后直接空回滚返回成功,此时全局事务已经结束,但是 Try 方法随后执行,就会造成一阶段 Try 方法预留的资源永远无法提交和释放了。

比如执行一阶段 Try 方法时,出现网络拥堵,由于 Seata 全局事务有超时限制,执行 Try 方法超时后,TM 决议全局回滚,回滚完成后如果此时 RPC 请求才到达参与者,然后参与者执行 Try 方法进行资源预留,从而造成悬挂。

如何解决悬挂问题?当执行二阶段 Cancel 方法时,先判断 tcc_fence_log 表是否存在当前 xid 的记录,如果不存在则插入一条记录,状态是 SUSPENDED,并且不执行回滚操作。后面执行 Try 方法时首先会向 tcc_fence_log 表插入一条当前 xid 的记录,这样会造成主键冲突,从而避免了悬挂问题。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL进阶】视图 存储过程 触发器

😊😊作者简介😊😊 : 大家好,我是南瓜籽,一个在校大二学生,我将会持续分享Java相关知识。 🎉🎉个人主页🎉🎉 : 南瓜籽的主页…

Unity3D -知识点(1)

1.场景视图鼠标滚轮:场景放大缩小鼠标右键:场景左右平移场景编辑器中,能看到什么?网格,每一格大小为1unit,建模不同,规定不同,(对应屏幕上100个像素)世界坐标系y轴向上为正x轴向右为…

每天10个前端小知识 【Day 18】

前端面试基础知识题 1.如何实现单行/多行文本溢出的省略样式? 在日常开发展示页面,如果一段文本的数量过长,受制于元素宽度的因素,有可能不能完全显示,为了提高用户的使用体验,这个时候就需要…

2023金三银四跳槽必会Java核心知识点笔记整理

现在互联网大环境不好,互联网公司纷纷裁员并缩减 HC,更多程序员去竞争更少的就业岗位,整的 IT 行业越来越卷。身为 Java 程序员的我们就更不用说了,上班 8 小时需要做好本职工作,下班后还要不断提升技能、技术栈&#…

惠普LaserJet M1005 MFP报错b2

故障现象: 惠普LaserJet M1005 MFP开机后直接报b2错误; 检测维修: 故障大意是:机器的硬件可能出现点突变,此问题建议联系当地维修中心进行处理。

【计算机网络】网络层

文章目录网络层概述网络层提供的两种服务IPv4地址IPv4地址概述分类编址的IPv4地址划分子网的IPv4地址无分类编址的IPv4地址IPv4地址的应用规划IP数据报的发送和转发过程静态路由配置及其可能产生的路由环路问题路由选择路由选择协议概述路由信息协议RIP的基本工作原理开放最短路…

SciencePlots绘图

简介 使用Python作为核心开发工具的机器学习和深度学习研究者自然会希望使用Matplotlib进行科研图表的绘制,但是Matplotlib默认的样式并不适合科研论文的出版,而SciencePlots就是为此定制的一系列科研绘图样式库,可以绘制很合适科研图表。 …

蓝桥杯算法训练合集十五 1.打翻的闹钟2.智斗锅鸡3.文件列表

目录 1.打翻的闹钟 2.智斗锅鸡 3.文件列表 1.打翻的闹钟 问题描述 冯迭伊曼晚上刷吉米多维奇刷的太勤奋了,几乎天天迟到。崔神为了让VonDieEman改掉迟到的坏毛病,给他买了个闹钟。 一天早上,老冯被闹钟吵醒,他随手将闹钟按掉丢…

PHP教材管理系统设计(源代码+毕业论文)

【P003】PHP教材管理系统设计(源代码论文) 设计方案 本系统采用B/S结构,所有的程序及数据都放在服务器上,终端在取得相应的权限后使用Web页面浏览,录入,修改等功能。在语言方面使用PHP语言,在…

如何使用断点续传上传大文件

概念 大文件上传的需求介绍 不管怎样简单的需求,在量级达到一定层次时,都会变得异常复杂。 文件上传简单,文件变大就复杂 上传大文件时,以下几个变量会影响我们的用户体验 服务器处理数据的能力请求超时网络波动 上传时间会变长…

[acwing周赛复盘] 第 91 场周赛20230218

[acwing周赛复盘] 第 91 场周赛20230218 一、本周周赛总结二、 4861. 构造数列1. 题目描述2. 思路分析3. 代码实现三、4862. 浇花1. 题目描述2. 思路分析3. 代码实现四、4863. 构造新矩阵1. 题目描述2. 思路分析3. 代码实现六、参考链接一、本周周赛总结 这周挺难的。T1 贪心分…

2022黑马Redis跟学笔记.实战篇(六)

2022黑马Redis跟学笔记.实战篇 六4.7.达人探店功能4.7.1.分享探店图文1. 达人探店-发布探店笔记2. 达人探店-查看探店笔记4.7.2.点赞功能4.7.3.基于List实现点赞用户列表TOP104.7.4.基于SortedSet实现点赞排行榜4.8.关注列表4.8.1.关注列表实现原理4.8.2.添加关注1. 好友关注-关…

JAVA 双亲委派

双亲委派 问题? 什么是双亲委派?为什么需要双亲委派,不委派有什么问题?"父加载器"和"子加载器"之间的关系是继承的吗?双亲委派是怎么实现的?我能不能主动破坏这种双亲委派机制&#x…

nginx平滑升级

1.平滑升级操作1.1 备份安装目录下的nginxcd /usr/local/nginx/sbin mv nginx nginx.bak1.2 复制objs目录下的nginx到当前sbin目录下cp /opt/software/nginx/nginx-1.20.2/objs/nginx /usr/local/nginx/sbin/1.3 发送信号user2给nginx老版本对应的进程kill -user2 more /usr/lo…

【TypeScript】TypeScript的基础类型(string,number,boolean,void,null,undefined):

文章目录一、安装【1】安装npm install typescript -g【2】基础类型:Boolean、Number、String、null、undefined 以及 ES6 的 Symbol 和 ES10 的 BigInt二、字符串类型(string)三、数字类型(number)四、布尔类型(boolean)五、空值类型(void)六、null和undefined类型…

初探Mysql反向读取文件

前言 Mysql反向读取文件感觉蛮有意思的,进行了解过后,简单总结如下,希望能对在学习Mysql反向读取文件的师傅有些许帮助。 前置知识 在Mysql中存在这样一条语句 LOAD DATA INFILE它的作用是读取某个文件中的内容并放置到要求的表中&#x…

IOS崩溃文件符号化实践

1.背景与项目难点 1.1 背景 由于公司之前使用的友盟要收费,filebase服务由谷歌提供,存在数据合规风险。需要实现稳定性分析功能,通过支持app崩溃信息实时采集、实时上报、实时自动解析并定位出代码问题,帮助研发同学及时定位崩溃…

Java 布隆过滤器

你在么?在!一定在么?不在!一定不在么? 你想要100%的准去性,还是99%的准确性附带较高的速度和较小的资源消耗。 任何算法,任何经营收到的背后,都是时间效益 资源消耗 准确性的平衡&am…

ASO优化之如何更新APP

ASO是一个持续的迭代过程,应用商店排名和热门关键词每天都在变化,为了跟上应用行业快节奏的性质,我们必须灵活地制定应用商店的优化策略,并时常的更新我们的应用。 那我们该如何做到这一点呢? 如果是刚上新的应用&am…

93.【Vue-细刷-02】

Vue-02(十六)、基本列表渲染 (v-for)1.使用v-for遍历数组2.使用v-for遍历对象3.使用v-for遍历字符串(十七)、列表过滤 (filter())1.⭐JS中Change属性的原生状态⭐2.使用watch监听实现3.const {xxx} this 在Vue的作用⭐⭐4.JS箭头函数参数的简写⭐5.使用computed进行计算实现(最…