如何用TCC实现分布式事务?

TCC事务介绍

TCC(Try-Confirm-Cancel)是除可靠消息队列以外的另一种常见的分布式事务机制,它是由数据库专家帕特 · 赫兰德(Pat Helland)在2007年撰写的论文《Life beyond Distributed Transactions: An Apostate’s Opinion》中提出的。正式以Try-Confirm-Cancel作为名称的是Atomikos公司,其注册了TCC商标。

Atomikos公司在商业版本事务管理器ExtremeTransactions中提供了TCC方案的实现,但是由于其是收费的,因此相应的很多的开源实现方案也就涌现出来,如:tcc-transactionByteTCChmilyspring-cloud-rest-tcc

上次我们分享的使用RocketMQ实现分布式事务,虽然它也能保证最终的结果是相对可靠的,过程也足够简单(相对于TCC来说),但可靠消息队列的整个实现过程完全没有任何隔离性可言。

如果业务需要隔离,我们通常就应该重点考虑TCC方案,它天生适合用于需要强隔离性的分布式事务中

在具体实现上,TCC的操作有点复杂,它是一种业务侵入性较强的事务方案,要求业务处理过程必须拆分为“预留业务资源”和“确认/释放消费资源”两个子过程。另外,你看名字也能看出来,TCC的实现过程分为了三个阶段:

图片

• Try: 尝试执行阶段,完成所有业务可执行性的检查(保障一致性),并且预留好事务需要用到的所有业务资源(保障隔离性)。

  • Confirm: 确认执行阶段,不进行任何业务检查,直接使用Try阶段准备的资源来完成业务处理。注意,Confirm阶段可能会重复执行,因此需要满足幂等性。

  • Cancel: 取消执行阶段,释放Try阶段预留的业务资源。注意,Cancel阶段也可能会重复执行,因此也需要满足幂等性。

空回滚和业务悬挂问题

空回滚:当某分支事务的try阶段阻塞时,可能导致全局事务超时而触发二阶段的cancel操作。在未执行try操作时先执行了cancel操作,这时cancel不能做回滚,就是空回滚

业务悬挂:对于已经空回滚的业务,如果以后继续执行try,就永远不可能confirm或cancel,这就是业务悬挂。应当阻止执行空回滚后的try操作,避免悬挂。

TCC与XA区别

之前分布式事务-两阶段、三阶段提交介绍了二阶段提交,TCC与XA两阶段提交有着异曲同工之妙。下面我们看下两者的区别:

图片

  • 执行阶段上:

    • 阶段1: 在XA中,各个RM准备提交各自的事务分支,事实上就是准备提交资源的更新操作(insert、delete、update等);而在TCC中,是主业务活动请求(try)各个从业务服务预留资源。

    • 阶段2: XA根据第一阶段每个RM是否都prepare成功,判断是要提交还是回滚。如果都prepare成功,那么就commit每个事务分支,反之则rollback每个事务分支。TCC中,如果在第一阶段所有业务资源都预留成功,那么confirm各个从业务服务,否则取消(cancel)所有从业务服务的资源预留请求。

  • XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁 XA事务中的两阶段提交内部过程是对开发者屏蔽的,JTA规范中,通过UserTransactioncommit方法来提交全局事务,这只是一次方法调用,其内部会委派给TransactionManager进行真正的两阶段提交,因此开发者从代码层面是感知不到这个过程的。而事务管理器在两阶段提交过程中,从preparecommit/rollback过程中,资源实际上一直都是被加锁的。如果有其他人需要更新这两条记录,那么就必须等待锁释放。

  • TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁 TCC中的两阶段提交并没有对开发者完全屏蔽,也就是说从代码层面,开发者是可以感受到两阶段提交的存在。如下单案例中:在第一阶段,库存中心需要提供try接口(库存预留)。在第二阶段,库存需要提供confirm/cancel接口(确认库存扣减/取消库存预扣减)。开发者明显的感知到了两阶段提交过程的存在。try、confirm/cancel在执行过程中,一般都会开启各自的本地事务,来保证方法内部业务逻辑的ACID特性。其中:

    1. 1. try过程的本地事务,是保证资源预留的业务逻辑的正确性。

    2. 2. confirm/cancel执行的本地事务逻辑确认/取消预留资源,以保证最终一致性,也就是所谓的补偿型事务(Compensation-Based Transactions)。

示例

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:资金服务、红包服务、订单服务。

红包服务

public interface RedPacketTradeOrderService {@EnableTccpublic String record(RedPacketTradeOrderDto tradeOrderDto);
}

资金服务

public interface CapitalTradeOrderService {@EnableTccpublic String record(CapitalTradeOrderDto tradeOrderDto);
}

订单服务

主要业务逻辑如下:

@Service
public class PaymentServiceImpl {@AutowiredCapitalTradeOrderService capitalTradeOrderService;@AutowiredRedPacketTradeOrderService redPacketTradeOrderService;@AutowiredOrderRepository orderRepository;@Compensable(confirmMethod = "confirmMakePayment", cancelMethod = "cancelMakePayment", asyncConfirm = false)public void makePayment(@UniqueIdentity String orderNo) {System.out.println("order try make payment called.time seq:" + DateFormatUtils.format(Calendar.getInstance(), "yyyy-MM-dd HH:mm:ss"));Order order = orderRepository.findByMerchantOrderNo(orderNo);String result = capitalTradeOrderService.record(buildCapitalTradeOrderDto(order));String result2 = redPacketTradeOrderService.record(buildRedPacketTradeOrderDto(order));}public void confirmMakePayment(String orderNo) {System.out.println("order confirm make payment called. time seq:" + DateFormatUtils.format(Calendar.getInstance(), "yyyy-MM-dd HH:mm:ss"));Order foundOrder = orderRepository.findByMerchantOrderNo(orderNo);//check if the trade order status is PAYING, if no, means another call confirmMakePayment happened, return directly, ensure idempotency.if (foundOrder != null) {foundOrder.confirm();orderRepository.update(foundOrder);}}public void cancelMakePayment(String orderNo) {System.out.println("order cancel make payment called.time seq:" + DateFormatUtils.format(Calendar.getInstance(), "yyyy-MM-dd HH:mm:ss"));Order foundOrder = orderRepository.findByMerchantOrderNo(orderNo);//check if the trade order status is PAYING, if no, means another call cancelMakePayment happened, return directly, ensure idempotency.if (foundOrder != null) {foundOrder.cancelPayment();orderRepository.update(foundOrder);}}
}

相关资料

开源TCC实现方案

  • https://github.com/changmingxie/tcc-transaction

  • https://github.com/liuyangming/ByteTCC

  • https://github.com/dromara/hmily

  • https://github.com/prontera/spring-cloud-rest-tcc

Atomikos的官方TCC参考文档

  • https://www.atomikos.com/downloads/articles/TransactionsForSOA-WhitePaper.pdf

  • https://www.atomikos.com/Main/DownloadPublications?article=TccForRestApi.pdf

  • Atomikos ExtremeTransactions Guide:atomikos 商业版本事务管理器ExtremeTransactions使用指南。

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

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

相关文章

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的体育赛事目标检测系统(Python+PySide6界面+训练代码)

摘要:开发和研究体育赛事目标检测系统对于增强体育分析和观赏体验至关重要。本篇博客详细讲述了如何运用深度学习技术构建一个体育赛事目标检测系统,并提供了完整的实现代码。系统基于先进的YOLOv8算法,对比了YOLOv7、YOLOv6、YOLOv5的性能&a…

爬虫入门到精通_实战篇7(Requests+正则表达式爬取猫眼电影)_ 抓取单页内容,正则表达式分析,保存至文件,开启循环及多线程

1 目标 猫眼榜单TOP100:https://www.maoyan.com/board 2 流程框架 抓取单页内容:利用requests请求目标站点,得到单个网页HTML代码,返回结果。正则表达式分析:根据HTML代码分析得到电影名称,主演,上映时间,评分,图片…

C语言中的分支和循环语句:从入门到精通

分支和循环语句 1. 前言2. 预备知识2.1 getchar函数2.2 putchar函数2.3 计算数组的元素个数2.4 清屏2.5 程序的暂停2.6 字符串的比较 3. 结构化3.1 顺序结构3.2 分支结构3.3 循环结构 4. 真假性5. 分支语句(选择结构)5.1 if语句5.1.1 语法形式5.1.2 else…

Java网络通信UDP

目录 网络通信基础 UDP通信 服务器 1.想要使用UDP通信 要先打开DatagramSocket文件 端口号可以手动指定或系统随机分配 2.阻塞等待接收客户端数据;创建DatagramPacket接收客户端传来的数据 3.处理客户端传来的数据,并进行业务处理(这里…

MySQL 教程 2.4

MySQL UNION 操作符 本教程为大家介绍 MySQL UNION 操作符的语法和实例。 描述 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合,并去除重复的行。 UNION 操作符必须由两个或多个 SELECT 语句组成,每个 SELECT 语句的列数…

Python降维数据库之umap使用详解

概要 在数据科学和机器学习领域,数据通常是高维度的,而高维度数据不仅难以可视化,还会增加建模的复杂性。降维是一种处理高维数据的关键技术,而Python UMAP(Uniform Manifold Approximation and Projection)是一种强大的降维工具,它在保留数据结构的同时,将高维数据映…

【IDEA+通义灵码插件】实现属于你的大模型编程助手

目录 1.前言 2.下载安装 3.解释代码 4.生成单元测试 5.生成注释 6.智能补全 1.前言 大模型到底该以一种什么方式落地,从而嵌入我们的工作当中,助力我们工作效率的提升,其实最好的方式也许就是虚拟助手的方式,就像钢铁侠的&…

【OpenCV基础(三)】Ubuntu系统下EasyPR环境配置

环境配置 1、资源下载2、环境配置2.1、1、将EasyPR压缩包拷贝到Ubuntu 三种方法任选一种2.2、解压得到EasyPR文件夹(文件夹一层进入后EasyPR资源内容)2.3、终端命令修改权限**chmod -R 777 ./ EasyPR**2.4、查找EasyPR/include/easypr/config.h,使用gedit方式打开2.…

vue2本地开发环境正常,生产环境下this.$router.push({ name: ‘login‘ })不跳转

如果在Vue.js 2中在本地开发环境下正常运行,但在生产环境下使用​​this.$router.push({ name: login })​​不起作用,可能有几个原因需要检查和解决: 路由配置问题: 确保你的路由配置正确,特别是确保在生产环境中,路由的配置和本地开发环境一致。检查是否正确设置了name…

基于springboot+vue的智能学习平台系统

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

SAP PP学习笔记 - 豆知识07 - 如何查看BOM一览

SAP标准提供了CS03,只能查询单个的BOM,如果想查看一览,只能自己写SQVI 查询。 有其他高招的童鞋,请赐教啊。 1,SQVI 工具 SAP MM学习笔记18- SQVI 工具_sap sqvi-CSDN博客 输入查询名,然后点击 登录 2&a…

#QT(DEMO2-登录界面)

1.IDE:QTCreator 2.实验:DEMO登录 3.记录 Line Edit输入不换行 密码框输入如下设置: 运行效果 4.代码

Vue.js+SpringBoot开发在线课程教学系统

目录 一、摘要1.1 系统介绍1.2 项目录屏 二、研究内容2.1 课程类型管理模块2.2 课程管理模块2.3 课时管理模块2.4 课程交互模块2.5 系统基础模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示4.1 管理后台4.2 用户网页 五、样例代码5.1 新增课程类型5.2 网站登录5.3 课…

五、西瓜书——集成学习

1.个体与集成 集成学习通过将多个学习器进行结合,常可获得比单一学习器显著优越的泛化性能,这对“弱学习器”(weak learner)尤为明显因此集成学习的很多理论研究都是针对弱学习器进行的而基学习器有时也被直接称为弱学习器。 要获得好的集成个体学习器应“好而不同”…

武汉灰京文化:多样化推广与创新引领游戏行业

作为专业的游戏推广服务商,武汉灰京文化注重多样化的推广策略,通过与各大媒体、社交平台和游戏社区建立紧密的合作关系,为游戏企业提供全方位的推广服务。他们通过精确的广告投放、内容创作和社交媒体互动等方式,将游戏信息传播给…

【C++】STL学习之旅——初识STL,认识string类

string类 1 STL 简介2 STL怎么学习3 STL缺陷4 string4.1 初识 string4.2 初步使用构造函数成员函数 5 小试牛刀Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!! 1 STL 简介 …

解读OWASP软件保障成熟度模型SAMM

OWASP软件保证成熟度模型(SAMM)可为所有类型的组织分析和改进其软件安全态势提供有效和可衡量的方法。OWASP SAMM支持完整的软件生命周期,包括开发和获取,并且与技术和过程无关。 1. 简介 OWASP软件保证成熟度模型(SA…

数据结构 第3章 栈、队列和数组(一轮习题总结)

第3章 栈、队列和数组 3.1 栈3.2 队列3.3 栈与队列的应用3.4 数组和特殊矩阵 3.1 栈(1 10 11 20) 3.2 队列(6 12 14 17) 3.3 栈与队列的应用(6 11) 3.4 数组和特殊矩阵 3.1 栈 T1 栈和队列具有相同的逻辑…

k8s-prometheus监控部署 22

新建项目仓库并上传部署prometheus所需的镜像 开始部署 修改svc访问方式为LoadBalancer 查看用户名和密码 访问grafana监控页面 http://192.168.182.103/​​​​​​ 修改可视化模板 官方监控模板:https://grafana.com/grafana/dashboards 访问prometheus监控页面…

1. vue3-环境准备

1、安装node.js 如果开发环境上面没有安装node.js,需要到node.js官方网站下载node.js。下载安装后,可以通过npm --version查看nodejs版本 2. 开发工具 开发工具建议使用vscode