Seata架构篇 - TCC模式
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 的记录,这样会造成主键冲突,从而避免了悬挂问题。
相关文章:

Seata架构篇 - TCC模式
TCC 模式 概述 TCC 是分布式事务中的两阶段提交协议,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel)。Try:对业务资源的检查并…...

前端最全面试题整理
前端基础 一、 HTTP/HTML/浏览器 1、说一下 http 和 https https 的 SSL 加密是在传输层实现的。 (1) http 和 https 的基本概念 http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(T…...

大数据之-Nifi-监控nifi数据流信息_监控数据来源_bub轻松复现---大数据之Nifi工作笔记0011
通过数据流功能可以轻松复现,数据的流向在某个时间点数据是怎么流动的,出现了什么问题,太强大了.. 真的是,可以看到通过右键,处理器,打开view data province就可以看到, 上面是处理器处理数据的详细信息 点击左侧的详情图标可以查看详情信息,details是这个事件处理的内容详情,…...

CUDA编程接口
编程接口 文章目录编程接口3.1利用NVCC编译3.1.1编译流程3.1.1.1 离线编译3.1.1.2 即时编译3.1.2 Binary 兼容性注意:仅桌面支持二进制兼容性。 Tegra 不支持它。 此外,不支持桌面和 Tegra 之间的二进制兼容性。3.1.3 PTX 兼容性3.1.4 应用程序兼容性3.1…...
惠普打印机使用
https://support.hp.com/cn-zh/product/hp-officejet-4500-all-in-one-printer-series-g510/3919445/document/c02076511HP 打印机 - 无法打印校准页本文适用于 HP 喷墨打印机。安装新墨盒后,打印机无法按预期打印校准页。步骤 1:确保打印机可以开始打印…...

Ubuntu升级cmake
目录 1、下载cmake安装包 2、开始安装 3、查看cmake版本 参考链接: https://blog.csdn.net/qq_27350133/article/details/121994229 1、下载cmake安装包 cmake安装包下载:download | cmake 我们根据自身需求下载所需版本的cmake安装包,这…...

CCNP350-401学习笔记(101-150题)
101、Refer to the exhibit SwitchC connects HR and Sales to the Core switch However, business needs require that no traffic from the Finance VLAN traverse this switch. Which command meets this requirement? A. SwitchC(config)#vtp pruning B. SwitchC(config)#…...

分享112个HTML娱乐休闲模板,总有一款适合您
分享112个HTML娱乐休闲模板,总有一款适合您 112个HTML娱乐休闲模板下载链接:https://pan.baidu.com/s/15uBy1SVSckPPMM55fiudeQ?pwdkqfz 提取码:kqfz Python采集代码下载链接:采集代码.zip - 蓝奏云 Bootstrap视频网站模板 …...

k8s快速入门
文章目录一、Kubernetes(K8S)简介1、概念1.1 Kubernetes (K8S) 是什么1.2 核心特性1.3 部署方案2、Kubernetes 集群架构2.1 架构2.2 重要概念 Pod2.3 Kubernetes 组件二、Kubernetes集群安装1、安装方式介绍2、minikubute安装3、裸机搭建(Bar…...
NG ZORRO知识点总结
NG ZORRO的常用属性,包括但不限于,结合代码 <button nz-button [nzType]"primary" [nzSize]"large" [nzLoading]"loading" [nzDisabled]"disabled" (click)"onClick()">点击我</button>nz-button是一个按钮组件…...
go中的值方法和指针方法
go中的值方法和指针方法1前言2 不同类型的对象调用不同类型的方法2.1 值对象可以调用值方法和指针方法3 指针对象可以调用值方法和指针方法4 !注意:结构体对象实现接口方法1前言 golang中在给结构体对象添加方法时,接收者参数类型可以有两种…...
OKR常见挑战以及应对方法探讨
背景 OKR是大家经常听到的一个词,也有不少团队说自己实行过,但每个实行过的团队都遇到过挑战。很多团队都感觉OKR有些空,很难落地,普通团队成员更是时常感觉无所适从,感觉就像看电影。2022年我们在更大的范围落地了OK…...

SpringAMQP消息队列(SpringBoot集成RabbitMQ)
一、初始配置1、导入maven坐标<!--rabbitmq--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>2、yml配置spring:rabbitmq:host: 你的rabbitmq的ipport: …...

DIDL5_数值稳定性和模型初始化
数值稳定性和模型初始化数值稳定性梯度不稳定的影响推导什么是梯度消失?什么是梯度爆炸?如何解决数值不稳定问题?——参数初始化参数初始化的几种方法默认初始化Xavier初始化小结当神经网络变得很深的时候,数值特别容易不稳定。我…...
火狐浏览器推拽开新的窗口
今天我测试的时候,发现我拖拽一下火狐会打开了新的窗口,谷歌就不会,所以我们要阻止一下默认行为const disableFirefoxDefaultDrop () > {const isFirefox navigator.userAgent.toLowerCase().indexOf(firefox) ! -1if (isFirefox) {docu…...

vrrp+mstp+osfp经典部署案例
LSW1和LSW2和LSW3和LSW4上面启用vrrpmstp组网: vlan 10 全走LSW1出再走AR2到外网,vlan 20 全走LSW2出再走AR3到外网 配置注意:mstp实例的根桥在哪,vrrp的主设备就是谁 ar2和ar3上开nat ar2和ar3可以考虑换成两台防火墙来做&…...

AI_News周刊:第二期
2023.02.13—2023.02.17 1.ChatGPT 登上TIME时代周刊封面 这一转变标志着自社交媒体以来最重要的技术突破。近几个月来,好奇、震惊的公众如饥似渴地采用了生成式人工智能工具,这要归功于诸如 ChatGPT 之类的程序,它对几乎任何查询做出连贯&a…...

【C++的OpenCV】第一课-opencv的间接和安装(Linux环境下)
第一课-目录一、基本介绍1.1 官网1.2 git源码1.3 介绍二、OpenCV的相关部署工作2.1 Linux平台下部署OpenCV一、基本介绍 1.1 官网 opencv官网 注意:官网为英文版本,可以使用浏览器自带的翻译插件进行翻译,真心不推荐大家去看别人翻译的&am…...
为什么建议使用你 LocalDateTime ,而不是 Date
为什么建议使用你 LocalDateTime ,而不是 Date? 在项目开发过程中经常遇到时间处理,但是你真的用对了吗,理解阿里巴巴开发手册中禁用static修饰SimpleDateFormat吗 通过阅读本篇文章你将了解到: 为什么需要LocalDate…...

【大数据】HADOOP-YARN容量调度器Spark作业实战
目录需求配置多队列的容量调度器验证队列资源需求 default 队列占总内存的40%,最大资源容量占总资源的60% ops 队列占总内存的60%,最大资源容量占总资源的80% 配置多队列的容量调度器 在yarn-site.xml里面配置使用容量调度器 <!-- 使用容量调度器…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...