Go微服务: 关于TCC分布式事务

TCC 分布式事务

  • T: Try 预处理, 尝试执行,完成所有的业务检查,做好一致性,预留必要的业务资源,做好准隔离性
  • C: Confirm 确认,如果所有的分支Try都成功了, 就到了这个阶段, Confirm 是真正执行业务的过程, 不做任何业务检查, 只使用 try 阶段预留的业务资源
  • C: Cancel 取消,所有的分支中,如果有一个失败了,则走到 Cancel 的阶段,Cancel 就释放了 Try 阶段预留的业务资源
  • 所以,Confirm 和 Cancel 是互斥的,只会执行一个,按照TCC的协议,Confirm 和 Cancel 只返回成功,不返回失败
  • 如果有网络问题,或服务器临时故障, 比如崩溃,掉电这种, 事务管理器会进行重试,最终让他成功
  • 在 Try 阶段要做业务检查,保障一致性以及资源预留隔离的一些问题
  • 此阶段只是一个初步的操作, 它和后续的Confirm一起才能真正构成完整的业务逻辑, 这个算是一部分,当所有的 Try 都完成了,就会向下执行,到Confirm
  • Confirm 阶段做一个确认提交, Try 阶段的所有分支事务执行成功后, 开始执行 Confirm, 采用TCC时候,只要Try 成功了,就表示Confirm 阶段不会出错,如果 Confirm 阶段出错,就引入重试机制, 或者人工处理
  • 上图是在 Try 阶段, 资源2执行失败,资源1执行成功, 要回滚资源1,这时候资源1要回滚,就是执行 Cancel, 业务执行错误,需要回滚,执行分支的事务的业务取消,预留资源的释放,一般认为Cancel阶段也是一定成功的, 如果Cancel 出错,也是重试机制和人工处理
  • 上面全局事务发起方是全局事务的管理器,是独立的第三方,可以实现独立的服务,会生成全局的事务记录,全局的事务id贯穿整个分布式事务的调用链,类似 jaeger 的链路追踪traceID,都是分布式的产品,这些产品设计思路都是相互借鉴,所以,这个全局事务管理器可以追踪和调用状态,由于 Confirm 和 Cancel 失败需要进行重试, 所以要实现幂等性,也就是说同一个操作,无论请求多少次,结果都应该是相同的
  • TCC 的三种异常处理:空回滚,幂等,悬挂
    • 1 )空回滚:在没有调用 Try 阶段的方法而调用了第二阶段的 Cancel 方法
    • Cancel 方法要识别出这是一个空回滚, 然后直接返回成功
    • 也就是说空回滚在某种情况下,没有执行 Try, 就直接回滚了
    • 2 )幂等:为了保证TCC的二阶段提交重试机制不会引发数据不一致
    • 就要求TCC的二阶段Try, Confirm, Cancel 接口保证幂等,这样不会重复使用或者释放资源,如果幂等没有控制做好,就很容易导致数据不一致的严重问题
    • 解决思路是增加执行状态,每次执行前,就要查询状态,这就是说你能不能证明你的状态执行到哪里了,可以做一个记录
    • 3 )悬挂:对于一个分布式事务,二阶段的Cancel接口比Try接口先执行了
    • 悬挂对于分布式的二阶段,Cancel 接口比Try接口先执行
    • 对比空回滚是Try是不执行;而悬挂是Cancel先执行,Try再执行
    • 它的解决思路是,如果二阶段执行成功,一阶段就不能再继续执行了,在执行一阶段事务时要判断一下,全局事务是否已经有二阶段事务的记录,如果有,就不执行Try了

TCC 为何这么难?


1 ) 从代码上来说

  • 可以把我们的TCC放到我们的代码,或者说放到一些场景里来看一下
  • 好,我们先从代码说起, 那我们在这里先新建一个目录,就叫 TCC Demo
  • 按照TCC的规则来,我们每一个方法函数都需要有这三个函数: Try, Confirm, Cancel
  • 比如订单业务,有三个函数
    • func TryOrder() {}
    • func ConfirmOrder() {}
    • func CancelOrder() {}
  • 比如下单的时候,需要协同构建库存,增加积分
  • 对于库存来说, 有:
    • func TryStock(){}
    • func ConfirmStock(){}
    • func CancelStock(){}
  • 对于积分来说,有:
    • func TryPoint(){}
    • func ConfirmStock(){}
    • func CancelOrder(){}
  • 如果我们业务中有10个这种,那么我们要写30个这类服务,而且需要有数据库的配合,非常的繁琐

2 ) 基于业务场景来看

  • 先看左边的订单服务,它有自己的这个mysql数据库。它第一步先启动事物和这个TCC事务管理器去交互
  • 它启动事物之后,第二步就调用这个Try,调用所有的资源上的Try
  • 第三步就是要执行提交或者回滚,现在,我们的Try都是ok的
  • 下面它就要执行第四步,这第四步的这个Confirm和Cancel是互斥的, 只能择其一执行
  • 因为你这个Try执行成功了,就直接都是 confirmStock 和 confirmPoint
  • 如果要是有问题,中间可能就是 CancelStock 和 CancelPoint
    在实际开发中一般是一个什么样的情况呢?
    • 就是说 Try 一般是执行主业务的, 比如我们有一个非常难的业务, 在try里基本都搞定了
    • 那对于这个 Confirm和Cancel, 它一般都是基本是比较简单的操作
    • 其实一般只要Try里没有问题, 那么Confirm和这个Cancel就基本上可以认为是没有太大问题,但是还有其他的问题
    • 并不是说,Try ok了,然后 Confirm OK了,Cancel 也 ok 了,就没有问题
    • 分布式的复杂,它是存在各种问题的,比如说你这个分布式网络,你永远不要相信分布式里网络永远是好的
    • 或者说我现在这个库存有另一个小组维护,这个库存它没有问题,但是我们这个积分服务挂了,或者说很慢
    • 我们说这个库存服务,还有这个积分服务,都是其他小组维护的,我们站在我们这个订单角度来说,比如说我是订单服务的负责人
    • 那我不能说动人家这个积分服务的这个代码,比如说积分服务,是挂了或者处理很慢
    • 就要去看这个TCC的事务管理器了,其实这个TCC在开启事务之前,它会详细的记录日志
    • 它有一个日志,每个服务调用了哪个接口,当前事务执行到哪里?
    • 比如,即便积分服务挂了,重启了,对吧?重启以后,我们找到日志,找到这个日志仍然可以继续执行
    • 假如,我们的积分服务 Cancel 执行这个出错了, 那么我们的TCC事务会一直重试
    • 那么TCC事务管理器,要保证执行Cancel不出错,它就会重试。
    • 这样一来就可以解决大部分的网络带来的这个问题
    • 因为Cancel, Confirm, 这里面的这个业务逻辑基本不是很复杂
    • 可能改个状态,或者是添加个什么东西,就是这种类型的,它可能就是网络抖动, 给你造成了一下这个小麻烦
    • 那你你这个重试几次之后呢,补偿一下就可以
    • 从这儿可以看到TCC事务管理器控制整个流程
  • 我们调用TCC,如果Try阶段有问题,那TCC框架就会执行服务的Cancel逻辑撤销之前的操作
  • 如果,我们调用这个TCC如果Try阶段它就有问题,比如说你的这个业务太复杂了,在某个地方突然出了一个小bug
  • 那么TCC框架就会执行各种Cancel逻辑撤销之前的操作
  • 如果上图这个Confirm或Cancel它就是一直不成功,怎么办?
  • 其实分布式它本身虽然比较复杂,但是大部分业务的Confirm和Cancel代码就是很简单
  • 一般的都是网络问题,通过一直调用的进行补偿就可以了
  • 如果一直不成功,你可以在某种程度上做一个记录器进行报警,人为干预
  • 自己做的计录器可以按你自己的业务逻辑,因为你这个TCC事务,比如三次或五次都不成功,它要保证成功,则可以通过电话,微信,钉钉通知人报警
  • 这时候,比如说开发人员肯定是收到了嘛,人为介入解决这个问题就行了嘛
  • 所以,其实TCC真的是不简单,我们只要使用了微服务和这个分布式,就没有办法避免没有这些问题,只要你用了就会遇到这些问题

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

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

相关文章

【多模态】37、TextSquare | 借助 Gemini-Pro 通过四个步骤来生成高质量的文本问答数据

文章目录 一、背景二、方法2.1 Square-10M2.2 模型结构2.3 使用 Square-10M 进行有监督微调 三、效果3.1 实验设置3.2 Benchmark 测评 论文:TextSquare: Scaling up Text-Centric Visual Instruction Tuning 代码:暂无 出处:字节 | 华中科技…

linux 服务器上离线安装 node nvm

因为是离线环境 如果你是可以访问外网的 下面内容仅供参考 也可以继续按步骤来 node 安装路径 Node.js — Download Node.js nvm 安装路径 Tags nvm-sh/nvm GitHub 后来发现 nvm安装后 nvm use 版本号 报错 让我去nvm install 版本 我是内网环境 install不了 下面 你要 把安…

玄机平台应急响应—apache日志分析

1、前言 apache的日志一共有两个,一个是access.log,这个日志记录了所有对Web服务器的访问,被入侵时重点排查这个。另一个是error.log,错误日志记录了服务器运行期间遇到的各种错误,以及一些普通的诊断信息&#xff0c…

【Python】推荐比print更好用的调试方法

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【Vue】作用域插槽

插槽分类 默认插槽:组件内定制一处结构 具名插槽:组件内定制多处结构 插槽只有两种,作用域插槽不属于插槽的一种分类。作用域插槽只是插槽的一个传参语法 作用: 定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据&a…

LeetCode 算法:滑动窗口最大值c++

原题链接🔗:滑动窗口最大值 难度:困难⭐️⭐️⭐️ 题目 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动…

Skins

本主题解释如何将DevExpress主题/皮肤应用到应用程序中,如何允许用户在运行时在主题之间切换,如何自定义现有皮肤或创建自己的皮肤,等等。 WinForms订阅包括许多基本控件:按钮、复选框、表单、消息框、对话框、对话框等。 我们实现…

MFC 使用sapi文字转换为语音

文章目录 添加头文件声明变量 添加头文件 声明变量 pSpVoice NULL; //默认构造函数中初始化为空 bool CChKBarSCCodeApp::InitSpVoice() {HRESULT hr ::CoInitialize(NULL); // COM初始化if (!SUCCEEDED(hr)){AfxMessageBox(_T("声音环境初始化失败!…

自定义模块设置示例

CSDN 针对部分博主开放了自定义模块设置&#xff0c;我也是简单的使用了一下这个功能&#xff0c;感觉很不错&#xff0c;下面是我编写的参考代码大家可以复制下面代码来使自己的博客主页多样化。 <div class"pmusic"><iframe frameborder"no" bo…

.net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript

.net core 使用js&#xff0c;.net core 使用javascript&#xff0c;在.net core项目中怎么使用javascript 我项目里需要用到“文字编码”&#xff0c;为了保证前端和后端的编码解码不处bug, 所以&#xff0c;我在项目中用了这个 下面推荐之前在.net F4.0时的方法 文章一&#…

将div渲染成textarea框,类似于ant design 的TextArea

一 先看效果 原始效果 输入时效果 二 代码如下 1. html 代码 <div className{style.divTextArea} contentEditable"true"></div> 2. Css(Less)代码 .divTextArea {width: 90%;margin-top: 10px;line-height: 28px;min-height: 60px;border: 1px solid …

MySQL有哪些锁?

文章目录 前言一、全局锁1.全局锁是怎么用的&#xff1f;2.全局锁应用场景是什么&#xff1f;3.加全局锁又会带来什么缺点呢&#xff1f;4.既然备份数据库数据的时候&#xff0c;使用全局锁会影响业务&#xff0c;那有什么其他方式可以避免&#xff1f; 二、表级表1.MySQL 表级…

selenium中, quit 和close的区别

close时 """ close和quit的区别 close关闭当前页 (只是关闭了当前) quit离开整个浏览器 &#xff08;走远了&#xff09; """ from selenium import webdriver import time# 创建浏览器驱动对象 from selenium.webdriver.co…

js如何实现当文本内容过长时,中间显示省略号...,两端正常展示

前一阵做需求时&#xff0c;有个小功能实现起来废了点脑细胞&#xff0c;觉得可以记录一下。 产品的具体诉求是&#xff1a;用户点击按钮进入详情页面&#xff0c;详情页内的卡片标题内容过长时&#xff0c;标题的前后两端正常展示&#xff0c;中间用省略号...表示&#xff0c…

如何在MySQL中实现upsert:如果不存在则插入?

目录 1 使用 REPLACE 2 使用 INSERT ... ON DUPLICATE KEY UPDATE 使用 INSERT IGNORE 有效会导致 MySQL 在尝试执行语句时忽略执行错误 INSERT 。这意味着 包含 索引或 字段 INSERT IGNORE 中重复值的语句 不会 产生错误&#xff0c;而只是完全忽略该特定 命令。其明显目的是…

[word] word大括号怎么打两行 #其他#其他#微信

word大括号怎么打两行 Word给用户提供了用于创建专业而优雅的文档工具&#xff0c;帮助用户节省时间&#xff0c;并得到优雅美观的结果。 一直以来&#xff0c;Microsoft Office Word 都是最流行的文字处理程序。 作为 Office 套件的核心程序&#xff0c; Word 提供了许多易…

秒杀优化+秒杀安全

1.Redis预减库存 1.OrderServiceImpl.java 问题分析 2.具体实现 SeckillController.java 1.实现InitializingBean接口的afterPropertiesSet方法&#xff0c;在bean初始化之后将库存信息加载到Redis /*** 系统初始化&#xff0c;将秒杀商品库存加载到redis中** throws Excepti…

【YOLOv10】使用 TensorRT C++ API 调用GPU加速部署 YOLOv10 实现 500FPS 推理速度——快到飞起!

NVIDIA TensorRT ™ 是一款用于高性能深度学习推理的 SDK&#xff0c;包含深度学习推理优化器和运行时&#xff0c;可为推理应用程序提供低延迟和高吞吐量。YOLOv10是清华大学研究人员近期提出的一种实时目标检测方法&#xff0c;通过消除NMS、优化模型架构和引入创新模块等策…

平稳交付 20+ 医院,卓健科技基于 OpenCloudOS 的落地实践

导语&#xff1a;随着数字化转型于各个行业领域当中持续地深入推进&#xff0c;充当底层支撑的操作系统正发挥着愈发关键且重要的作用。卓健科技把 OpenCloudOS 当作首要的交付系统&#xff0c;达成了项目交付速度的提升、安全可靠性的增强、运维成本的降低。本文将会阐述卓健科…

【转】ES, 广告索引

思考&#xff1a; 1&#xff09;直接把别名切换到上一个版本索引 --解决问题 2&#xff09;广告层级索引如何解决&#xff1f; -routing、join 3&#xff09;查询的过程&#xff1a;query and fetch, 优化掉fetch 4&#xff09;segment合并策略 5&#xff09;全量写入时副…