Java开发 - 不知道算不算详细的分布式事务详解

news2024/10/6 8:22:58

前言

前日对JUC进行了一个深度总结,不过现在博主能记得的也不多了,只是这东西,不是看几遍写几遍就能完全记住的,功夫在平时,很多知识点都需要反复的看,不光要看,还要用,这样才能了解其原理,掌握其原理,从而能更好的运用于平时的开发中,提高开发效率。今天给大家带来一篇分布式事务相关的总结,详不详细的不敢说,大家还是自己来看看吧。

事务

虽然我们说的是分布式事务,但在这之前,我们还是要了解一下事务的本质,事务分为两种,一种是我们本篇要说的分布式事务,另一种是本地事务。下面,我们对这两种事务的特点进行说明。

本地事务

本地事务也叫做单机事务。但说起来和单机游戏并不一样,它只是相对于分布式事务的一种描述。学完此篇,相信你对单机事务的理解能够加深不少。

本地事务由四大特点,俗称ACID,分别是:

  • A:原子性,即事务中的所有操作,要么全部成功,要么全部失败;
  • C:一致性,即要保证数据库内部完整性约束,声明性约束。约束指的是数据定义的组成部分,比如PRIMARY KEY,NOT NULL ,UNIQUE等等,共五大约束;声明性,约束都是声明性的;
  • I:隔离性,即对同一资源操作的事务不能同时发生,比如不能喝水的同时还在唱歌,你可以试试看;
  • D:持久性,即数据库的这些操作必须永久保存,不论对错。

分布式事务

分布式事务指的是在多个服务或多个数据库架构下产生的事务,有跨数据源的分布式事务,也有跨服务的分布式事务,可能还有其他类型的分布式事务。最典型的案例就是生成订单的时候,在生成订单时,还要修改库存,如果是购物车下单还要删除购物车下单商品,如果账户可充值还要扣除账户余额,是不是很复杂?但这,就是分布式事务的一部分!

这时,你会发现,每一个服务都是一个单独的单机事务,他们共同组成了这个分布式事务,原子性要求他们要么全部成功,要么全部失败,但对于上图的情况,你很难保证原子性,ACID恐怕就无法保证了,而这就是分布式事务要解决的问题。 

分布式事务的理论基础

为了解决分布式事务问题,诞生了一些用于解决分布式问题原子性的理论,分别是CAP原则和BASE理论,以及在他们基础上提出的最终解决思路。

CAP原则

CAP定理是在1998年,由加州大学的科学家Eric Brewer提出,主要有灿个特性,分别对照CAP:

  • C:一致性,即在分布式系统中的所有数据备份,在同一时刻数据要一致;
  • A:可用性,即在访问多个服务的任何节点时,都能得到相应,不论成功还是失败;
  • P:分区容错性,即系统中任意信息的丢失或失败不会影响系统的继续运作,其原理是,分布式系统中的某节点出现故障时,形成独立分区,分区即使形成,也要保证整个系统依然可以对外提供服务。

CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。关于这点,我们在解决思路上再说。大家看下下面的图,他们的关系如下:

但他们之间存在一个不可调和的矛盾,那就是P一定存在,因为谁也不敢100%保证不会发生服务器故障,这个没有任何争议。这就是我们要说的解决思路,暂且不提,继续往下说。

BASE理论

BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

BASE理论有三大特性,分别是:

  • BASE是Basically Available(基本可用):分布式系统发生故障时,允许损失部分可用性,但要保证核心功能依然可用,其中,损失包括响应时间上的损失和非核心功能的损失;
  • Soft state(软状态):在一定时间内,允许出现数据不一致的临时状态,称为软状态;
  • Eventually consistent(最终一致性):在无法保证强一致性的条件下,在软状态结束后,要达到数据的最终一致性。

分布式事务解决思路

上面两个理论看完之后,相信你对解决思路已经有了一个大概的了解,总结起来就是两个模式:AP和CP:

  • AP:最终一致性模式,即各子事务分别执行和提交,允许出现软状态,然后采取弥补措施保证数据的最终一致性;
  • CP:强一致性模式,即各子事务执行后后想等待,要么全部成功,要么全部失败,失败后回滚。

但无论是AP还是CP,在执行的过程中都离不开一个很重要的东西,那就是事务的协调者TC,我们会在下面的Seata中讲到。在分布式系统下,子系统的事务就是分支事务,有关联的事务统称为全局事务。

Seata核心架构

关于Seata,其实博主在微服务那篇博客中讲到过,也有过使用的案例:Java开发 - 数风流人物,还看“微服务”

有兴趣的可以看看,也可以去搜下其他Seata相关的教程,了解Seata的可以继续往下看。关于Seata,博主就不再详细介绍了,我们直接切入正题,说说Seata的架构 。

在Seata的事务管理中,有三个重要的角色,我们在上面已经提到了一个事务协调者TC,还有一个事务管理器TM和资源管理器RM。他们的作用如下:

  • TC:维护全局和分支事务的状态,说白了就是提交或者回滚,类似于接线员;
  • TM:定义了全局事务的范围,控制全局事务的开始,提交或者回滚,是真正的管理者;
  • RM:用于管理各分支事务的资源,比如向TC注册分支事务,向TC报告分支事务的状态,驱动分支事务的提交或者回滚,是个执行者。

三者的关系结构如下图:

Seata基于此架构又提出了四种用于解决分布式事务的方案:

XA:强一致性分阶段事务模式,强一致性虽有性能损耗,但却没有业务侵入;

AT:最终一致的分阶段事务模式,无业务侵入,是Seata的默认模式;

TCC:最终一致的分阶段事务模式,有业务侵入;

SAGA:长事务模式,有业务侵入。

Seata四大模式

XA模式

原始的XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范提供了支持。

原始的XA其实是一种规范,目前的主流数据库都实现了次规范,其实现原理是基于两阶段提交:

第一阶段:

TC通知分支事务进行事务处理本地事务,并将执行结果上报TC,此过程只执行SQL,不提交,继续持有数据库锁。

第二阶段:

TC根据各分支事务上报的结果进行处理,如果全部执行成功,则通知所有分支事务进行提交,提交后锁释放;如果有一条以上的失败消息,则通知所有分支事务进行回滚,最终释放锁。

原始的XA请看下图:

Seata中的XA是在XA的基础上做了封装和改造,我们来看看其架构图,它和我们前面画的TM,TC,RM的关系图很像:

看图,其两个阶段都在做什么就一目了然了。

虽然XA模式实现简单,使用了强一致性,且没有代码的侵入,但和传统XA一样,第一阶段不提交,所以锁在第二阶段释放,性能略差,此模式也必须依赖关系型数据库才可以使用。

其实现也比较简单,分两步完成:

第一步,开启XA模式:

seata:
  data-source-proxy-mode: XA

第二步,给发起全局事务的入口方法添加@GlobalTransactional注解。

关于Seata的使用就不再详细说了,既然你看到这里,就代表Seata你至少是知道怎么用的,比如依赖和配置,不了解的可查看博主在上面放的微服务的链接或自行查找学习。

AT模式

AT模式前面提到过,是分阶段提交的事务模型,它主要解决了XA模式中资源锁定时间太久的问题,因此,它并不是强一致性的,而是最终一致性的,它对代码同样没有侵入,是Seata的默认模式。

下面,我们来看看它的架构流程图:

架构图很清晰,但也略微复杂,我们来画一个简易版的流程图:

这样,流程有没有更清晰一点?画图能省不少文字啊,不过画图确实比较费时间。

注意:这里存在一个问题,就是AT模式因为在第一阶段直接提交后释放的锁,第二阶段无法保证其他事务是否会操作同一条数据,所以会存在脏写的问题。 

解决办法就是引入全局锁,在释放DB锁之前,先拿到全局锁,避免在同一时刻有另外一个事务来操作当前数据。这一点要格外注意。

目前使用全局锁@GlobalLock时,限制条件过于苛刻,必须要添加@Transaction注解,同时必须是for update语句,否则不会触发全局锁检查。更详细的大家在使用过程中再详细了解,本文不再延伸介绍。

使用AT模式也很简单:

seata:
  data-source-proxy-mode: AT # 默认就是AT

修改配置即可直接使用,详细代码不再给出,可参考:

详解 Seata AT 模式事务隔离级别与全局锁设计 

Seata AT 模式

https://github.com/seata/seata-samples

TCC模式

TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复(其实就是业务侵入)。需要实现三个方法:

  • Try:资源的检测和预留;
  • Confirm:完成资源操作业务,要求 Try 成功 Confirm 也一定能成功;
  • Cancel:预留资源释放,可以认为是回滚操作。

它和AT相比的优点是不依赖undolog,事务回滚通过资源的预留和cancel操作。其架构如下:

看起来和AT及其相似,只是没有了对undolog文件的操作,多了try,confirm和cancel操作。 从图中,我们应该还能看出来一个问题,那就是TCC模式不依赖数据库事务,可用于非事务性数据库。

那么,你在上图还能看出有哪些问题呢?Let us see......

有两个问题需要格外注意:空回滚和事务悬挂

空回滚

我们假设在try阶段发生了阻塞,这可能会导致全局事务超时,进而导致cancel操作被触发,在try操作没有执行的情况下,执行cancel的回滚操作就是空回滚。如果不对空回滚加以防范的话,可能会造成资源的无效释放,即在没有预留资源的情况下就释放资源,造成异常。

解决办法是:执行cancel操作时,应当判断try是否已经执行,如果尚未执行,则不应执行空回滚。

事务悬挂

对于已经空回滚的业务,之前被阻塞的try操作恢复,继续执行try,就永远不可能confirm或cancel ,事务一直处于中间状态,这就是业务悬挂

解决办法是:执行try操作时,应当判断cancel是否已经执行过了,如果已经执行,应当阻止空回滚后的try操作,避免悬挂。

总结

总的来说,这俩其实算是一个问题,可以通过创建一张新表,字段自己随便定,只要每个事务不一样即可,推荐使用全局事务id,三个函数中的操作如下:

  • try中记录事务状态到表中;
  • confirm中根据全局事务id删除这条数据;
  • cancel中恢复记录表中的数据到初始状态;

判断空回滚方法:

  • cancel业务中,根据xid查询数据,如果为null则说明try还没做,可不执行空回滚,然后根据全局事务id插入一条状态数据留给try做空回滚判断;
  • try业务中,根据xid查询数据 ,如果已经全局事务id,则存在Cancel已经执行的情况,可拒绝执行try业务
  • 以上两条满足一条即可,如果空回滚做了,try绝对不能执行,但若是经过判断避免了,那try继续,否则try执行了,真到了要执行cancel的时候是要正常执行的。

SAGA模式

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

看图,分布式事务执行过程中,各节点依次执行正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任意一个正向操作执行失败,那么分布式事务会在当前节点,也就是FAILS的地方通过补偿服务退回去,执行前面各节点的逆向回滚操作,把已提交的节点的操作回滚,使分布式事务回到初始状态。 

适用场景:

  • 业务流程长、业务流程多
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

优势:

  • 一阶段提交本地事务,无锁,高性能
  • 事件驱动架构,参与者可异步执行,高吞吐
  • 补偿服务易于实现

缺点:

  • 不保证隔离性,其实还是脏写问题
  • 其软状态持续时间不可预测

关于Saga,更详细内容可见这里:Seata Saga 模式

博主个人感觉Sage模式是四大模式中最复杂的了,说实话,没用过,和前三种比起来,Saga更难理解,博主也没有理解透,惭愧惭愧!!!但有一点博主是明确的,其补偿服务是另类的回滚,可以通过一个单独的节点完成此操作。大家还是自己看吧,不要被误导,谁要是搞懂了回来给博主科普科普。

四大模式对比

XAATTCCSAGA
一致性强一致性弱一致性弱一致性最终一致性
隔离性完全隔离基于全局锁隔离基于资源预留隔离无隔离
代码侵入有,try,confirm,cancel有,编写状态机和补偿服务
性能非常好非常好
使用场景对一致性和隔离型要求高的事务基于关系型数据库的大多数分布式事务场景都可以,比较通用
  • 对性能要求高
  • 使用非关系型数据库的
  • 业务流程长、业务流程多
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

Seata高可用架构了解

这个东西说起来其实很简单,但做起来嘛又很麻烦,博主只简单的提一嘴,毕竟做起来是有成本在里面的,各公司做起来还可能不一样。

使用Seata就一定离不开类似Nacos的注册中心,使用分布式事务,就一定离不开类似Dubbo的远程调用服务。然后集群搞起来,高可用性的主从架构搞起来,再土豪一点的话搞异地容灾,其实都不复杂,就是砸钱。

关于这些内容,不再本篇详细介绍,准备单独出,各位,咱今天就到这里吧。

结语

看到这里,想必你对分布式事务的解决方案就多多少少有些了解了,虽然没有提供详细的代码,但在各位略懂Seata的情况下,你基本已经可以通过默认的AT模式来解决大部分问题了,这篇博客虽然才写了短短五六千字,但却浓缩了精华,觉得不错,就给博主点个赞吧!

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

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

相关文章

在CentOS上安装Jenkins并配置Docker

文章目录 步骤1 - 安装Java 11步骤2 - 安装Jenkins步骤3 - 安装Docker步骤4 - 配置Docker Cloud步骤 5 - 验证步骤 6 - 可能会遇到的问题 在本教程中,我们将展示如何在CentOS上安装Jenkins和Docker,并将它们配置在同一台机器上,使Jenkins能够…

《花雕学AI》WeTab+ChatGPT:让浏览器变成你的智能助手

引言: 浏览器是我们日常使用的最重要的工具之一,它可以帮助我们获取信息、娱乐、学习、工作等。但是,传统的浏览器往往不能满足我们的个性化需求,也不能给我们提供智能化的服务。那么,有没有一种浏览器可以让我们的体…

yoloV2细节改进

文章目录 1 v2 细节升级概述2 .网络结构特点3. 架构细节解读4. 基于聚类来选择先验框尺寸5. 偏移量计算方法6. 坐标映射与还原7 感受野8. 特征融合的改进其他知识点filter 是什么? 1 v2 细节升级概述 2 .网络结构特点 使用dropout,杀死部分神经元&#…

Java集合之单列集合

分类 集合分为单列集合(Collection)和双列集合(Map) 单列集合的体系结构 List集合和Set集合的区别 List系列集合:添加元素是有序的(添加的顺序,而非数据的大小顺序)、可重复、有索引…

为什么在Ubuntu系统使用附加驱动更新Nvidia显卡驱动不起作用

1. 硬件环境 CPU:AMD Ryzen 9 5950x 16-core processor 32 GPU:双GeForce RTX 3090 操作系统:Ubuntu 22.04.2 LTS 64 位 主板:ASUS的ROG CROSSHAIR VIII EXTREME 2. 问题描述 使用上图所示的附加驱动程序更新Nvidia显卡驱动&am…

恢复item2和oh-my-zsh的配置

1. 首先正常安装item2 2. 加载onedrive里的传家宝iterm2_default_profile.json,让iterm2的配置生效 2. 然后正常安装oh-my-zsh (官方步骤: sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&q…

C# 学习abstract

abstract 顾名思义:抽象 从微软官方文档来看:abstract 修饰符指示被修改内容的实现已丢失或不完整。 abstract 修饰符可用于类、方法、属性、索引和事件。 在类声明中使用 abstract 修饰符来指示某个类仅用作其他类的基类,而不用于自行进行…

linux内核调试的几个方法

参考 以下内容: Linux 笔记: https://xuesong.blog.csdn.net/article/details/109522945?spm1001.2014.3001.5502 printk: printk在内核源码中用来记录日志信息的函数,只能在内核源码范围内使用。用法和printf非常相似; printk…

InsCode体验报告

文章目录 前言一、InsCode是什么?二、体验过程1.创建项目2.在线IDE3.运行和部署项目4.浏览和学习项目5.分享和协作项目6.支持AI助手 三、体验感受优点缺点 总结 官方宣传视频 InsCode-AI 前言 作为一个大三计算机专业的学生,我对编程有着浓厚的兴趣和热…

Triloga 的任务 — Satta 系列来袭!

谁战胜了这些凶兽,谁就获得了力量,让我们通过装备体现出来!来自神秘洞穴的疯狂昆虫外壳,黄昏之地燃烧中的部落的骨质盔甲,以及深海的美妙灯光。 Triloga 的任务——Satta 系列已在 The Sandbox 市场平台上架&#xff1…

JVM(类的加载与ClassLoader、双亲委派机制)

文章目录 1. 类的生命周期2. 类的加载过程3. 类加载器(classloader)3.1 类加载器的作用3.2 类加载器的分类(JDK8)3.3 双亲委派机制3.3.1 双亲委派机制优势 3.4 查看某个类的类加载器对象3.5 使用ClassLoader获取流 1. 类的生命周期 类在内存中完整的生命周期&#…

( “ 图 “ 之 并查集 ) 684. 冗余连接 ——【Leetcode每日一题】

❓684. 冗余连接 难度:中等 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1~n ) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n…

基于 EKS Fargate 搭建微服务性能分析系统

背景 近期 Amazon Fargate 在中国区正式落地,因 Fargate 使用 Serverless 架构,更加适合对性能要求不敏感的服务使用,Pyroscope 是一款基于 Golang 开发的应用程序性能分析工具,Pyroscope 的服务端为无状态服务且性能要求不敏感&…

Java阶段二Day14

Java阶段二Day14 文章目录 Java阶段二Day14复习前日知识点SpringFramework版本SpringFramework核心SpringFramework创建工程SpringFramework相关概念bean对象的创建过程xml配置文件中的标签 基于XML管理bean对象类型属性的注入数组类型属性注入集合类型属性注入p命名空间引入外…

ConMask: Open-World Knowledge Graph Completion

目录 Abstract Introduction Model Relationship-Dependent Content Masking Target Fusion Loss Function [1711.03438] Open-World Knowledge Graph Completion (arxiv.org) Abstract 引入一个名为ConMask的开放世界KGC模型,该模型学习实体名称和部分文本…

数据结构与算法基础-学习-23-图之邻接矩阵与邻接表

目录 一、定义和术语 二、存储结构 1、邻接矩阵 1.1、邻接矩阵优点 1.2、邻接矩阵缺点 2、邻接表 3、邻接矩阵和邻接表的区别和用途 3.1、区别 3.2、用途 三、宏定义 四、结构体定义 1、邻接矩阵 2、邻接表 3、网数据类型(造测试数据) 五…

如何使用TRIZ理论来分析问题和解决问题?

文章目录 TRIZ基础现代TRIZ步骤 TRIZ基础 现代TRIZ 经典的TRIZ方法对专利进行分析,认为专利分为两个部分,一部分是需要解决的问题,一部分是解决问题的解决方案.首先是问题的分析,确定是否是初始问题,比如工具功能分析/特性传递等工具. 步骤 问题识别 主要是识别出初始问题;…

MATLAB实现建筑热平衡模型建立及节能温控方案

全球大约1/3的能源消耗于建筑。在能源紧张的今天,如何减少建筑的能源浪费是一个值得研究的课题。 本文在综合国内外建筑能耗模拟方法的基础上,采用热平衡法,针对一小型建筑建立了热特性仿真模型,选用武汉地区的气象数据&#xff…

JAVA11新特性

JAVA11新特性 概述 2018年9月26日,Oracle官方发布JAVA11.这是JAVA大版本周期变化后的第一个长期支持版本,非常值得关注.最新发布的JAVA11将带来ZGC HttpClient等重要特性,一共17个需要我们关注的JEP,参考文档http://openjdk.java.net/projects/jdk/11/ 181:基于嵌套的访问控制…

云计算适合大专生学吗?

云计算适合大专生学吗? 对于大专毕业生来说,云计算的确是一个不错的选择,因为云计算技术应用专业,主要就是专科院校在办学。不管你是计算机相关专业的,还是零基础想学习都是可以的;原因就在于云计算这门专业…