详述分布式事务Seata TCC空回滚/幂等/悬挂问题、解决方案(seata1.5.1如何解决?)

news2025/7/19 12:10:27

文章目录

  • 一、前言
  • 二、问题介绍、seata1.5.1版本之前的解决方案
    • 1、空回滚
      • 出现原因
      • 解决措施
      • 事务控制记录表
      • try()、cancel()中获取xid、branch_id
    • 2、幂等
      • 出现原因
      • 解决措施
      • 事务控制记录表
    • 3、悬挂
      • 出现原因
      • 解决措施
    • 4、总述
      • 最终的事务控制记录表
  • 三、seata1.5.1版本起官方提供的解决措施
    • 1、开启TCCFence
      • 事务控制记录表tcc_fence_log
    • 2、try时使用TCCFence
    • 3、commit时使用TCCFence
    • 4、cancel时使用TCCFence
  • 四、总结

一、前言

更多内容见Seata专栏:https://blog.csdn.net/saintmm/category_11953405.html

至此,seata系列的内容已出:

  1. can not get cluster name in registry config ‘service.vgroupMapping.xx‘, please make sure registry问题解决;
  2. Seata Failed to get available servers: endpoint format should like ip:port 报错原因/解决方案汇总版(看完本文必解决问题)
  3. Seata json decode exception, Cannot construct instance of java.time.LocalDateTime报错原因/解决方案最全汇总版
  4. 【微服务 31】超细的Spring Cloud 整合Seata实现分布式事务(排坑版)
  5. 【微服务 32】Spring Cloud整合Seata、Nacos实现分布式事务案例(巨细排坑版)【云原生】
  6. 【微服务33】分布式事务Seata源码解析一:在IDEA中启动Seata Server
  7. 【微服务34】分布式事务Seata源码解析二:Seata Server启动时都做了什么
  8. 【微服务35】分布式事务Seata源码解析三:从Spring Boot特性来看Seata Client 启动时都做了什么
  9. 【微服务36】分布式事务Seata源码解析四:图解Seata Client 如何与Seata Server建立连接、通信
  10. 【微服务37】分布式事务Seata源码解析五:@GlobalTransactional如何开启全局事务
  11. 【微服务38】分布式事务Seata源码解析六:全局/分支事务分布式ID如何生成?序列号超了怎么办?时钟回拨问题如何处理?
  12. 【微服务39】分布式事务Seata源码解析七:图解Seata事务执行流程之开启全局事务
  13. 分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
  14. 分布式事务Seata源码解析九:分支事务如何注册到全局事务
  15. 分布式事务Seata源码解析十:AT模式回滚日志undo log详细构建过程
  16. 分布式事务Seata源码解析11:全局事务执行流程之两阶段全局事务提交
  17. 分布式事务Seata源码解析12:全局事务执行流程之全局事务回滚
  18. Spring Cloud整合Seata实现TCC分布式事务模式案例
  19. 分布式事务Seata源码解析13:TCC事务模式实现原理

在Spring Cloud整合Seata实现TCC分布式事务模式案例一文,笔者提到Seata存在三种问题:空回滚、幂等、悬挂。

本文详细介绍一下这三种问题、相应的解决方案、以及seata1.5.1版本开始对其的解决措施。

二、问题介绍、seata1.5.1版本之前的解决方案

1、空回滚

try()未执行,cancel()执行了;即:在没有调用 TCC 资源 Try 方法的情况下,调用了二阶段的 Cancel 方法。

出现原因

因为某些原因,可能是TCC分支事务所在的服务宕机 或 网络异常,导致try()超时 / 未执行(TC直接没收到try);分支事务的执行结果为失败,会触发分支事务的回滚,从而形成了空回滚。

解决措施

空回滚问题的关键在于一阶段的try()方法未执行,解决思路就很简单:

  • 如果try()方法执行了,就正常回滚;
  • 如果try()方法未执行,那就是空回滚。不应该做回滚操作,直接返回操作成功即可。

我们可以维护一个事务控制记录表(tcc_fence_log),其中有全局事务xid、分支事务branch_id;

  • 一阶段 try() 方法里会插入一条记录,表示一阶段执行了。
  • 二阶段 cancel() 方法中读取该记录;如果记录存在,则正常回滚;如果记录不存在,则是空回滚,直接返回成功。

事务控制记录表

CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(
    `xid`           VARCHAR(128)  NOT NULL COMMENT 'global id',
    `branch_id`     BIGINT        NOT NULL COMMENT 'branch id',
    PRIMARY KEY (`xid`, `branch_id`),
    KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

try()、cancel()中获取xid、branch_id

在这里插入图片描述

1> 全局事务xid获取:

String xid = RootContext.getXID();

2> 分支事务branch_id获取:

String branchId = MDC.get(RootContext.MDC_KEY_BRANCH_ID);

2、幂等

多次执行cancel() 或 confirm();

为了保证TCC二阶段提交的重试机制不会引发数据不一致,要求 TCC 的二阶段 Try、 Confirm 和 Cancel 接口保证幂等,不会重复使用或者释放资源。如果幂等没做好,很有可能导致数据不一致问题,相信大家都不想疲于手工修数据的。

出现原因

RM网络出现异常(比如:cancel()、confirm()超时),导致TC 回滚/提交时异常,TC会多次重试;

解决措施

在上述空回滚解决方案(维护一个事务控制记录表(tcc_fence_log)的基础上,增加一个执行状态字段(status),每次执行cancel()、confirm()时都根据xid、branchId查询相应记录的状态。

以Cancel操作为例:

  • 如果没有记录,说明是空回滚,啥也不做。
  • 如果记录状态是已回滚,cancel() 操作直接返回;
  • 如果记录状态是已提交,cancel() 操作抛出异常,理论上这种情况永远不可能发生;
  • 如果记录状态是事务初始化,cancel() 操作正常执行。

在这里插入图片描述

事务控制记录表

CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(
    `xid`           VARCHAR(128)  NOT NULL COMMENT 'global id',
    `branch_id`     BIGINT        NOT NULL COMMENT 'branch id',
    `status`        TINYINT       NOT NULL COMMENT 'status(tried:1;committed:2;rollbacked:3;suspended:4)',
    PRIMARY KEY (`xid`, `branch_id`),
    KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

3、悬挂

cancel()比try()先执行;

  • 因为Seata允许空回滚的原因,Cancel接口认为try接口没执行,空回滚直接返回成功;这样对于steata而言,分布式事务的二阶段cancel()已经执行成功,整个分布式事务就结束了。
  • 但由于某种原因,这之后try()才真正开始执行,预留业务资源;然而这个事务已经被seata认为结束了,并且对于一个try方法预留的业务资源,只有该分布式全局事务才能使用;也就是说这个一阶段预留的资源,后面没有人处理了,对于这种情况我们称为悬挂;即业务资源预留后没法继续处理。

出现原因

在分布式事务Seata源码解析13:TCC事务模式实现原理一文中,我们聊过对于TCC分支事务而言,其会先注册分支事务,然后再执行一阶段 try进行RPC调用。

  • 如果RPC调用出现网络问题,比如:网络拥堵等,RPC调用会超时,超时以后TC会通知RM回滚该分布式全局事务;
  • 这时就可能出现回滚完成后,RPC 请求 才到达服务提供方开始真正执行。

解决措施

悬挂的本质问题是一阶段预留的资源后面没法处理了,所以解决思路在于一阶段的执行时机,如果二阶段执行完成,一阶段就不要再继续执行了。

  • 一阶段Try()执行的时候,我们先看一下二阶段是否已执行;如果已执行,一阶段不再执行,否则正常执行;
  • 在二阶段cancel() 执行时就插入一条事务控制记录,状态为悬挂;一阶段执行时判断是否可以读取到该条记录;

在这里插入图片描述

4、总述

  • 增加事务控制表,核心三个字段:全局事务ID(tx_id)、分支事务ID(branch_id)、状态(status);
  • try() 时插入记录;cancel() 时有记录则更新记录状态、没有记录则插入数据;confirm() 时更新记录状态。

最终的事务控制记录表

CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(
    `xid`           VARCHAR(128)  NOT NULL COMMENT 'global id',
    `branch_id`     BIGINT        NOT NULL COMMENT 'branch id',
    `status`        TINYINT       NOT NULL COMMENT 'status(tried:1;committed:2;rollbacked:3;suspended:4)',
    PRIMARY KEY (`xid`, `branch_id`),
    KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
  • xid -> 全局事务id
  • branch_id -> TCC分支事务Id
  • status -> TCC分支事务状态,包含四种状态:已尝试、已提交、已回滚、空悬挂。

三、seata1.5.1版本起官方提供的解决措施

TCC模式下的空回滚、幂等、悬挂问题,seata1.5.1版本开始进行了处理(版本说明);

在这里插入图片描述

有兴趣可以看一下GIthub上的pull request:https://github.com/seata/seata/pull/3545,整体解决方案和我们上面提供的一样,只是它体现在seata源码里,而上面的解决方案需要我们自己写在try、confirm、cancel的业务代码里。

具体TCC事务原理 / 源码解析见博文:分布式事务Seata源码解析13:TCC事务模式实现原理。

1、开启TCCFence

虽然seata1.5.1版本开始支持TCC空回滚、幂等、悬挂问题的解决,但默认并没有开启,需要手动开启;
在这里插入图片描述

开启方式如下:

  • @TwoPhaseBusinessAction注解中设置useTCCFence = true;
    在这里插入图片描述

事务控制记录表tcc_fence_log

只在@TwoPhaseBusinessAction注解中设置useTCCFence = true;也是没法使用TCCFence的,需要在每个TCC分支事务连接的数据库中创建表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;

建表SQL出处:

  • seata源码下的mysql.sql文件,如果使用Oracle、Postgresql,用另外两个文件。
    在这里插入图片描述

2、try时使用TCCFence

ActionInterceptorHandler#proceed()方法中执行TCC事务的一阶段try()方法时,会判断是否使用TCCFence;如果使用,则尝试新增一条事务控制记录,如果新增失败、说明存在悬挂问题,直接抛出异常TCCFenceException

在这里插入图片描述

3、commit时使用TCCFence

TCCResourceManager#branchCommit()方法中执行TCC事务的二阶段commit()方法时会先根据xid和branch_id判断是否存在TCCFenceLog;

  • 不存在,则抛出异常;
  • 存在,并且状态是已提交,说明是重复提交,直接返回操作成功。
  • 存在,并且状态是已回滚、悬挂,打印个日志,直接返回操作失败。
  • 存在,并且状态是已尝试,则更新TCCFenceLog记录状态为已提交。

在这里插入图片描述

4、cancel时使用TCCFence

TCCResourceManager#branchRollback()方法中执行TCC事务的二阶段cancel()方法时会先根据xid和branch_id判断是否存在TCCFenceLog;

  • 不存在,则插入一条状态为悬挂的记录;空回滚的场景。
  • 存在,并且状态是已回滚、悬挂,说明是重复提交,直接返回操作成功。
  • 存在,并且状态是已提交,打印个日志,直接返回操作失败。
  • 存在,并且状态是已尝试,则更新TCCFenceLog记录状态为已回滚。

在这里插入图片描述

四、总结

TCC 空回滚、幂等、悬挂问题的解决方案目前是唯一的:

  • 增加事务控制表,核心三个字段:全局事务ID(tx_id)、分支事务ID(branch_id)、状态(status);
    • TCC分支事务状态,包含四种状态:已尝试、已提交、已回滚、空悬挂。
  • try() 时插入记录;cancel() 时有记录则更新记录状态、没有记录则插入数据;confirm() 时更新记录状态。

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

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

相关文章

[附源码]java毕业设计基于Java烟支信息管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

前端框架 网络请求 Fetch Axios

目录 一、Fetch请求的使用 1、 Fetch官网 2、基本案例 二、跨域请求解决 三、Axios的使用 1、Axios官网 2、基本使用 推荐使用Axios更方便! 一、Fetch请求的使用 1、 Fetch官网 使用 Fetch - Web API 接口参考 | MDN 2、基本案例 二、跨域请求解决 &…

2023第二届中国能源管理碳中和国际峰会

峰会背景 应对气候变化已经成为21世纪人类社会面临的紧迫挑战,推进绿色发展成为全球共识。中国积极参与和引导应对气候变化国际合作,向世界作出“力争2030年前实现碳达峰、2060年前实现碳中和”的承诺,逐步完善碳达峰碳中和“1N”政策体系&a…

史上最全安装Maven教程一看就会吊炸天的教程

史上最全安装Maven教程 简单了解一下什么是Maven 1.Maven翻译为“专家“, ”内行”的意思,是著名Apache公司下基于Java开发的开源项目。 2.Maven项目对象模型(POM)是一个项目管理工具软件,可以通过简短的中央信息描述…

LeetCode第 319 场周赛题解

目录2469. 温度转换2470. 最小公倍数为 K 的子数组数目2471. 逐层排序二叉树所需的最少操作数目2472. 不重叠回文子字符串的最大数目2469. 温度转换 模拟 class Solution { public:vector<double> convertTemperature(double celsius) {return {celsius273.15,celsius*1…

前端面试中小型公司都考些什么

什么是物理像素&#xff0c;逻辑像素和像素密度&#xff0c;为什么在移动端开发时需要用到3x, 2x这种图片&#xff1f; 以 iPhone XS 为例&#xff0c;当写 CSS 代码时&#xff0c;针对于单位 px&#xff0c;其宽度为 414px & 896px&#xff0c;也就是说当赋予一个 DIV元素…

Ubuntu20.04 中已经安装 Pytorch 但 Import 报错 - 解决记录

01 问题描述 笔者使用的是 Ubuntu 20.04.3 LTS&#xff0c;在使用 PyTorch 训练模型的时候&#xff0c;torch 模块引用失败&#xff0c;报错信息是 OSError: /home/wang/.local/lib/python3.8/site-packages/torch/lib/../../nvidia/cublas/lib/libcublas.so.11: undefined s…

C++对象和类概述

11 对象和类 11.1 过程式和面向对象编程 面向过程编程&#xff1a;先考虑函数&#xff0c;然后再细化到数据 面向对象编程&#xff1a;对象&#xff08;数据函数&#xff09; 11.2 抽象和类 在计算中&#xff0c;抽象是根据与用户的接口来表示信息的关键步骤。 11.2.1 什…

QT默认自带mscv2017 2019 ,配置vs2022

试验QT版本&#xff1a;5.14.2 所需文件&#xff1a; QT安装程序--qt-opensource-windows-x86-5.14.2.exe具体地址是&#xff1a;Index of /archive/qthttps://download.qt.io/archive/qt/Microsoft 生成工具 2022 Visual Studio 2022 IDE - 适用于软件开发人员的编程工具win…

Cholesterol胆固醇参数说明及相关研究

Cholesterol胆固醇是哺乳动物细胞中产生的一种主要甾醇&#xff0c;是细胞存活和增殖所必需的。它是哺乳动物细胞膜的一种成分&#xff0c;与膜磷脂、鞘脂和蛋白质相互作用&#xff0c;影响它们的行为。它也是各种基于脂质的药物递送&#xff08;LBDD&#xff09;系统的组成部分…

[oeasy]python0015_十六进制_hexadecimal_字节形态_hex函数

十六进制(hexadecimal) 回忆上次内容 上次数制可以转化 bin(n)可以把数字转化为 ​​2进制​ binary接收一个整数(int)得到一个二进制数形式的字符串数字在计算机中是用二进制存储的 但是展示给我们的时候用的是十进制也就是0-9这10个字符的形式都说字节是计算机存储的最小单…

基于微信小程序的自习室预约系统设计与实现-计算机毕业设计源码+LW文档

小程序开发说明 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Mav…

Me-Tetrazine-DBCO,1802908-04-8,ICG-Tetrazine四嗪类试剂知识分享

Me-Tetrazine-DBCO&#xff0c;Methyltetrazine-PEG4-azide&#xff0c;ICG-Tetrazine这几种试剂都含有四嗪&#xff0c;或者甲基四嗪&#xff0c;其主要的性能特点有哪些&#xff1f;西安凯新生物是国内业PEG供应商&#xff0c;其中包括各种规格的点击试剂&#xff0c;&#x…

nvm (node 版本管理器)

ps: 如果已经安装node&#xff0c;或者nvm&#xff0c;先卸载&#xff0c;再执行下面操作。 1. 下载nvm nvm github 下载后以管理员身份运行 setup.exe 安装就根据步骤点下一步就行了 2. 安装node nvm基础操作 使用 nvm install node版本号&#xff0c;但是这里有时候会报…

[附源码]java毕业设计基于的城镇住房公积金管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Vue项目实战

Vue项目实战 1、项目介绍 1.1、对象 有Vue2、Vue3组合api基础知识&#xff0c;TypeScript基础知识1.2、涉及技术 CSS3 TypeScript Vue3.2 Vuex4.x Vue Router4.x Vite2.x Element-Plus1.3、技能 掌握Vue3.2语法糖的使用掌握Vue3中组合api的使用掌握组件中业务逻辑抽离的方…

第七章 Java编程-多线程

线程几乎在每个编程语言中都有&#xff0c;它其实是操作系统的概念&#xff0c;编程语言是运行在操作系统上的

RK3568平台开发系列讲解(图像篇)BMP图像处理

🚀返回专栏总目录 文章目录 一、BMP文件格式解析1.1、位图文件头(bitmap-file header)1.2、位图信息头(bitmap-information header)二、LCD上显示代码沉淀、分享、成长,让自己和他人都能有所收获!😄 📢我们今天来讲解BMP文件格式的解析。 一、BMP文件格式解析 BMP是一…

发那科机床联网

一、设备信息确认 1、确认型号 数控面板拍照确认&#xff1a; 此系统为&#xff1a;0I-TD 注&#xff1a;凡是系统中带i的&#xff0c;基本上都有网络通讯和采集功能。如果系统中带有mate字样&#xff0c;并且比较老可能不含网口。 2、确认通讯接口 发那科的通讯接口有两种…

【SpringBoot项目】SpringBoot项目-瑞吉外卖【day02】员工管理业务开发

文章目录前言员工管理业务开发完善登录功能问题分析代码实现功能测试新增员工需求分析数据模型代码开发功能测试统一处理异常员工信息分页查询需求分析代码开发功能测试启用/禁用员工需求分析代码实现测试编辑员工信息需求分析代码实现功能测试总结&#x1f315;博客x主页&…