分布式事务无压力:轻松整合Spring Cloud与Alibaba Seata,事务管理so easy

news2024/11/18 13:58:41

今天我们聊聊在SpringCloud微服务架构中如何解决分布式事务这一技术难题,本文主要包含三个方面内容:

  • 讲解分布式事务的解决方案;
  • 介绍 Alibaba Seata 分布式事务中间件;
  • 分析 Seata 的 AT 模式实现原理。

分布式事务的解决方案

下面咱们先聊一下为什么会产生分布式事务。举个例子,某线上商城会员在购买商品的同时产生相应的消费积分,消费积分在下一次购物时可以抵用现金。这个业务的逻辑如果放在以前的单点应用是很简单的,如下所示。

开启数据库事务创建订单会员积分增加商品库存减少提交数据库事务

在这个过程中,因为程序操作的是单点数据库,所以在一个数据库事务中便可完成所有操作,利用数据库事务自带的原子性保证了所有数据要么全部处理成功,要么全部回滚撤销。但是放在以微服务为代表的分布式架构下问题就没那么简单了,我们来看一下示意图。

fb0409e81e9ee7c0ea4e47ef3bdf7c71.jpeg

分布式架构下调用关系图

可以看到,商城应用作为业务的发起者分别向订单、会员、库存服务发起了调用,而这些服务又拥有自己独立的数据存储,因为在物理上各个数据库服务器都是独立的,每一个步骤的操作都会创建独立的事务,这就意味着在分布式处理时无法通过单点数据库利用一个事务保证数据的完整性,我们必须引入某种额外的机制来协调多个事务要么全部提交、要么全部回滚,以此保证数据的完整性,这便是“分布式事务”的由来。

在分布式架构中有两种经典的分布式事务解决方案:二阶段提交(2PC)与三阶段提交(3PC)

二阶段提交

首先分析下二阶段提交的处理过程,下面是二阶段提交中的第一个阶段:事务预处理阶段。

833a12420bafeed2b15bce0c8e5cf3ce.jpeg

2PC 阶段一:事务预处理阶段

可以看到,相比单点事务,分布式事务中增加了一个新的角色:事务协调者(Coordinator),它的职责就是协调各个分支事务的开启与提交、回滚的处理。

以上图为例,当商城应用订单创建后,首先事务协调者会向各服务下达“处理本地事务”的通知,所谓本地事务就是每个服务应该做的事情,如订单服务中负责创建新的订单记录;会员服务负责增加会员的积分;库存服务负责减少库存数量。在这个阶段,被操作的所有数据都处于未提交(uncommit)的状态,会被排它锁锁定。当本地事务都处理完成后,会通知事务协调者“本地事务处理完毕”。当事务协调者陆续收到订单、会员、库存服务的处理完毕通知后,便进入“阶段二:提交阶段”。

536ba8e3c0bc2c4948a98ac0857c4b28.jpeg

2PC 阶段二:提交阶段

在提交阶段,事务协调者会向每一个服务下达提交命令,每个服务收到提交命令后在本地事务中对阶段一未提交的数据执行 Commit 提交以完成数据最终的写入,之后服务便向事务协调者上报“提交成功”的通知。当事务协调者收到所有服务“提交成功”的通知后,就意味着一次分布式事务处理已完成。

这便是二阶段提交的正常执行过程,但假设在阶段一有任何一个服务因某种原因向事务协调者上报“事务处理失败”,就意味着整体业务处理出现问题,阶段二的操作就自动改为回滚(Rollback)处理,将所有未提交的数据撤销,使数据还原以保证完整性。

对于二阶段提交来说,它有一个致命问题,当阶段二某个服务因为网络原因无法收到协调者下达的提交命令,则未提交的数据就会被长时间阻塞,可能导致系统崩溃。

dd593803ca5309d2c6d13251759a3e80.jpeg

二阶段提交的缺陷

以上图为例,假如在提交阶段,库存服务实例与事务协调者之间断网。提交指令无法下达,这会导致库存中的“飞科剃须刀”商品库存记录会长期处于未提交的状态,因为这条记录被数据库排他锁长期独占,之后再有其他线程要访问“飞科剃须刀”库存数据,该线程就会长期处于阻塞状态,随着阻塞线程的不断增加,库存服务会面临崩溃的风险。

那这个问题要怎么解决呢?其实只要在服务这一侧增加超时机制,过一段时间被锁定的“飞科剃须刀”数据因超时自动执行提交操作,释放锁定资源。尽管这样做会导致数据不一致,但也比线程积压导致服务崩溃要好,出于此目的,三阶段提交(3PC)便应运而生。

三阶段提交

三阶段提交实质是将二阶段中的提交阶段拆分为“预提交阶段”与“提交阶段”,同时在服务端都引入超时机制,保证数据库资源不会被长时间锁定。下面是三阶段提交的示意流程:

e0e569121fae1cd512d49a32b8a02092.jpeg

3PC 阶段一:事务预处理阶段

  • 阶段一:事务预处理阶段。

3PC 的事务预处理阶段与 2PC 是一样的,用于处理本地事务,锁定数据库资源,当所有服务返回成功后,进入阶段二。

7a3e9a694821dc3d79f1e1633d99f9f2.jpeg

3PC 阶段二:预提交阶段

  • 阶段二:预提交阶段。

预提交阶段只是一个询问机制,以确认所有服务都已准备好,同时在此阶段协调者和参与者都设置了超时时间以防止出现长时间资源锁定。当阶段二所有服务返回“可以提交”,进入阶段三“提交阶段”。

  • 阶段三:提交阶段。

3PC 的提交阶段与 2PC 的提交阶段是一致的,在每一个数据库中执行提交实现数据的资源写入,如果协调者与服务通信中断导致无法提交,在服务端超时后在也会自动执行提交操作来保证资源释放。

通过对比我们发现,三阶段提交是二阶段提交的优化版本,主要通过加入预提交阶段引入了超时机制,让数据库资源不会被长期锁定,但这也会带来一个新问题,数据一致性也很可能因为超时后的强制提交被破坏,对于这个问题各大软件公司都在各显神通,常见的做法有:增加异步的数据补偿任务、日终跑批前的数据补偿、更完善的业务数据完整性的校验代码、引入数据监控及时通知人工补录这些都是不错的补救措施。

讲到这,相比你对 2PC 与 3PC 的分布式事务方案应该有了初步的了解,这里我还是要强调下,无论是 2PC 与 3PC 都是一种方案,是一种宏观的设计。如果要落地就要依托具体的软件产品,在 Java 开源领域能够提供完善的分布式事务解决方案的产品并不多,比较有代表性的产品有 ByteTCC、TX-LCN、EasyTransaction、Alibaba Seata,其中无论从成熟度、厂商背景、更新频度、社区活跃度各维度比较,Alibaba Seata都是数一数二的分布式事务中间件产品,本讲后面的内容将围绕Alibaba Seata的AT模式展开,探讨Alibaba Seata是如何实现自动化的分布式事务处理的。

Alibaba Seata 分布式事务中间件

Alibaba Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。它的官网是http://seata.io/,截止到目前 Seata 在 GitHub 已有 23147 star,最新版本已迭代到 1.6.0,阿里多年的技术沉淀让 Seata 的内部版本平稳渡过了多次双 11 的考验。2019 年 1 月为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备,按官方的说法Seata目前已具备了在生产环境使用的条件。

3a01229933915ef4329bccd436dbbf60.jpeg

Seata 提供了多种分布式事务的解决方案,包含 AT 模式、TCC 模式、SAGA 模式以及 XA 模式。其中 AT 模式提供了最简单易用且无侵入的事务处理机制,通过自动生成反向 SQL 实现事务回滚。从 AT 模式入手使用,使我们理解分布式事务处理机制是非常好的学习办法。

205b5f722b4945f8b2dcdb5dbfecab58.jpeg

特色功能

AT 模式是 Seata 独创的模式,它是基于 2PC 的方案,核心理念是利用数据库 JDBC 加上 Oracle、MySQL 自带的事务方式来对我们分布式事务进行管理。说起来有点晦涩,下边我就结合这张 AT 模式方案图给大家介绍,在 Seata 中关于分布式事务到底需要哪些组件,以及他们都起到了什么样的职能。

7c6e97c251f1ea114d7a96d738569668.jpeg

Seata 组件图

通过Seata组件图我们可以看到三个组成部分:

  • 第一个是事务协调者(TC),它的作用是维护全局和分支事务的状态,驱动全局事务提交或者回滚,这正是前面讲解 2PC 或者 3PC 方案时提到的事务协调者组件的具体实现,TC 由 SEATA 官方提供。
  • 第二个是事务管理器(TM),事务管理器用于定义全局事务的范围,开始全局事务提交或者回滚全局事务都是由 TM 来决定。
  • 第三个是资源管理器(RM),他用于管理分支事务处理的资源,并且报告分支事务的状态,并驱动分支事务提交或者回滚。

这些概念可能有些晦涩,我们通过商城会员采购积分的例子进行讲解。

Seata AT 模式执行过程

b040fc2e5fe4e13e0f3c3e74cc96495f.jpeg

创建订单调用逻辑

这里我先给出商城应用中会员采购业务的伪代码。

会员采购(){
订单服务.创建订单();
积分服务.增加积分();
库存服务.减少库存();
}

在会员采购方法中,需要分别执行创建订单、增加积分、减少库存三个步骤完成业务,对于“会员采购”来说方法执行成功,则代表这个全局分布式事务需要提交,如果中间过程出错,则需要全局回滚,这个业务方法本身就决定了全局提交、回滚的时机以及决定了哪些服务需要参与业务处理,因此商城应用的会员采购方法就充当起事务管理器(TM)的角色。

而与之对应的在订单服务中创建订单、会员服务中增加积分、库存服务减少库存这些实际产生的数据处理的服务模块,则被称为资源管理器(RM)。

最后就是由Seata提供的Seata-Server中间件则提供事务协调者(TC)这个角色,实施全局事务1的提交、回滚命令下发。

为了方便理解,我画了时序图介绍 Seata 的执行过程。

3ddec3dd7d2658178058e96912f39df6.jpeg

执行过程

第一步,在商城应用(TM)与三个服务(RM)启动后自动向事务协调者Seata-Server(TC)进行注册,让 TC 知晓各个组件的详细信息。

第二步,当会员购物时会执行 TM 的“会员采购”方法,当进入方法前 Seata 为 TM 提供的客户端会自动生效,向 TC 发出开启全局事务的请求。

第三步,会员采购方法开始执行,会依次执行 3 个服务的新增订单、增加积分、减少库存,在请求送往新的 RM 时,都会向 TC 注册新的分支事务。这些分支事务在处理时不但向业务表写入数据,还会自动向 Seata 强制要求的 UNDO_LOG 回滚日志表写入回滚 SQL 日志。

以新增订单事务为例:新增订单时执行的 SQL 语句如下:

INSERT INTO order(id,...) values(1001,...)

与之对应的,Seata 的回滚日志是基于 SQL 反向生成,新增订单创建了 1001 订单,那 Seata会对 SQL 进行解析生成反向的回滚 SQL 日志保存在 UNDO_LOG 表,如下所示:

DELETE FROM order WHERE id = 1001

与之类似会员积分会生成加积分的业务 SQL 以及减积分的回滚 SQL。

#加积分
UPDATE FROM points SET point = 180 + 20 WHERE mid = 182


#UNDO_LOG表中的减积分SQL
UPDATE FROM points SET point = 200 - 20 WHERE mid = 182

第四步,当 RM 的分支事务执行成功后,会自动向 TC 上报分支事务处理成功。

第五步,当会员采购方法正确执行,所有 RM 也向 TC 上报分支事务处理成功,在“会员采购”方法退出前,TM 内置的 Seata 客户端会向 TC 自动发起“提交全局事务”请求。TC 收到“提交全局事务”请求,向所有 RM 下达提交分支事务的命令,每一个 RM 在收到提交命令后,会删除之前保存在 UNDO_LOG 表中的回滚日志。

但是事情总会有意外,假设某个 RM 分支事务处理失败,此时 TM 便不再向 TC 发起“提交全局事务”,转而发送“回滚全局事务”,TC 收到后,通知所有之前已处理成功的 RM 执行回滚 SQL 将数据回滚。

比如 1001 订单在第三步“减少库存”时发现库存不足导致库存服务预处理失败,那全局回滚时第一步订单服务会自动执行删除 1001 订单的回滚 SQL。

DELETE FROM order WHERE id = 1001

以及第二步积分服务会自动执行减少积分的回滚 SQL。

UPDATE FROM points SET point = 200 - 20 WHERE mid = 182

Seata AT模式就是通过执行反向 SQL 达到数据还原的目的,当反向 SQL 执行后便自动从 UNDO_LOG 表中删除。这便是 Seata AT 模式的大致执行过程,在这个过程中我们发现 Seata AT 模式设计的巧妙之处,Seata 为了能做到无侵入的自动实现全局事务提交与回滚,它在 TM端利用了类似于“Spring 声明式事务”的设计,在进入 TM 方法前通知 TC 开启全局事务,在成功执行后自动提交全局事务,执行失败后进行全局回滚。同时在 RM 端也巧妙的采用了 SQL 解析技术自动生成了反向的回滚 SQL 来实现数据还原。

在这我也思考过,为什么 Seata 要生成反向 SQL,而不是利用数据库自带的排他锁机制处理呢?翻阅资料后理解到它的设计意图,如果采用排它锁机制会导致数据资源被锁死,可能会产生大量的数据资源阻塞,进而存在应用崩溃的风险。而生成反向 SQL 的方案则是在预处理阶段事务便已提交,不会出现长时间数据资源锁定的情况,这样能有效提高并发量。但这样做也有弊端,在研究时发现 Seata 是工作在“读未提交”的隔离级别,高并发环境下容易产生脏读、幻读的情况,这也是需要特别注意的地方。

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

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

相关文章

专业修图软件 Affinity Photo 2 mac中文版编辑功能

Affinity Photo for Mac是应用在MacOS上的专业修图软件,支持多种文件格式,包括psD、PDF、SVG、Eps、TIFF、JPEG等。 Affinity Photo mac提供了许多高级图像编辑功能,如无限制的图层、非破坏性操作、高级的选择工具、高级的调整层、HDR合成、全…

2023最新Google play 开发者账号注册矩阵批量,提高注册成功率需要注意什么?

Google play作为全球最大的应用市场,是很多开发者推广应用的首选平台。不过,不少开发者会通过上传多个马甲包的方式来抢占更多的市场份额,获得更多的收益。 但上传马甲包的行为严重扰乱了Google play的市场环境,是不被谷歌官方允许…

MySQL基本操作之修改表结构

1、末尾增加字段 在表结构末尾增加一个名为 beizhu 的字段,类型为 varchar(250),并添加注释 trie: ALTER TABLE student ADD beizhu VARCHAR(250) COMMENT trie; 2、在表结构开头增加一个名为 xxx 的字段,类型为 varchar(20): ALTER TABLE student ADD xxx VARCHAR(20)…

4 OpenCV实现多目三维重建(多张图片增量式生成稀疏点云)【附源码】

本文是基于 OpenCV4.80 进行的,关于环境的配置可能之后会单独说,先提一嘴 vcpkg 真好用 1 大致流程 从多张图片逐步生成稀疏点云,这个过程通常包括以下步骤: 初始重建: 初始两张图片的选择十分重要,这是整…

nginx+nodejs 一台服务器站架多个网站

一、一台服务器架设多个 nodejs 网站的拓扑结构 二、搭建 Nodejs 生产环境 1、下载 下载 nodejs 二进制代码包或者,然后减压到 /usr/local/nodejs 2、配置环境变量 (1).vi /etc/profile (2).最后面添加: export NODE_HOME/usr/local/nodejs/bin…

常见问题-找不到vcruntime140.dll无法继续执行代码解决方案

本文将介绍五种不同的解决方案,帮助大家解决这个问题。 首先,我们需要了解为什么会出现找不到vcruntime140.dll的情况。这种情况通常是由于以下几个原因导致的: 1. 系统环境变量设置不正确:系统环境变量中可能没有包含vcruntime…

卷积神经网络CNN学习笔记

目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.conv2d代码参考文章 1.全连接层存在的问题 在全连接层中,相邻层的神经元全部连接在一起,输出的数量可以任意决…

大数据之LibrA数据库系统概览

实时监控 “实时监控”页面如图1所示,用户可单击刷新按钮手动刷新当前页面,也可在点刷新按钮前选择自动刷新时长,刷新时长包括:每30秒刷新一次、每60秒刷新一次、停止刷新。 实时监控数据(监控时间轴产生的新曲线&am…

win32汇编-PUSHAD和POPAD指令

PUSHAD是一个x86汇编指令,用于将当前程序的所有通用寄存器(EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI)的值依次入栈 PUSHAD指令压入32位寄存器 其堆栈指针SP将加32 PUSHAD POPAD不会影响标志位 POPAD指令则是PUSHAD指令的逆操作。POPAD指令…

家装、家居两不误,VR全景打造沉浸式家装体验

当下,用户对生活品质要求日益提升,越来越多的用户对多功能家装用品需求较大,由此造就了VR全景家装开始盛行。VR全景家装打破传统二维空间模式,通过视觉、交互等功能让用户更加真实、直观的体验和感受家居布置的效果。 一般来说&am…

数据结构-----图(graph)的储存和创建

目录 前言 图的储存结构 1.邻接矩阵 无向图的邻接矩阵 有向图的邻接矩阵 网(赋权图)的邻接矩阵 代码表示 2.邻接表 无向图的邻接表 有向图的邻接表 代码表示 3.邻接矩阵和邻接表对比 邻接矩阵 邻接表 图的创建 1.邻接矩阵创建图&#xff0…

idea2023配置maven

看过【黑马程序员Maven全套教程,maven项目管理从基础到高级,Java项目开发必会管理工具maven】https://www.bilibili.com/video/BV1Ah411S7ZE?p9&vd_sourceedf9d91e5a0a27db51e3d6d4b9400637 配置的,前提要素配置也在这个课程里有啦&…

在 Tubi 做 Tech Lead 有多刺激!

上周我们发布了一篇《当你在 Tubi 是一位 Tech Lead》采访稿,后台收到了这样一条留言,说出了许多技术人在选择管理岗位还是继续深耕技术方向时的纠结: ‘有些同事更喜欢投入精力处理有挑战的事情,而不愿花费太多时间进行人际沟通&…

Janus: 逆向思维,以数据为中心的MoE训练范式

文章链接:Janus: A Unified Distributed Training Framework for Sparse Mixture-of-Experts Models 发表会议: ACM SIGCOMM 2023 (计算机网络顶会) 目录 1.背景介绍all-to-allData-centric Paradigm 2.内容摘要关键技术Janus细粒度任务调度拓扑感知优先级策略预取…

30二叉树-了解二叉树

目录 树的定义 二叉树(Binary Tree) 二叉树的存储方式 链式存储 顺序存储 二叉树的遍历方式 LeetCode之路——144. 二叉树的前序遍历 分析 树的定义 树结构(Tree Structure)是一种分层的非线性数据结构,它由节…

【OpenCV实现鼠标绘图,轨迹栏做调色板,图像的基本操作】

文章目录 鼠标绘图轨迹栏做调色板图像的基本操作 鼠标绘图 在OpenCV中操作鼠标事件 函数:cv.setMouseCallback() 目的是在鼠标双击的地方画一个圆。首先,我们需要创建一个鼠标回调函数,该函数会在鼠标事件发生时执行。鼠标事件包括左键按下…

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息:1.2 基本信息:1.2.1 软件支持的内容:1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具,主要是…

中国移动启动算网大脑“天穹”全网试商用

10月12日,中国移动在2023全球合作伙伴大会主论坛正式启动算网大脑“天穹”全网试商用,全面开启算力网络2.0新征程,标志着中国移动算力网络迈向“融合统一”新阶段。 为落实国家“东数西算”战略,中国移动开创性提出算力网络新理念…

操作系统【OS】微内核

基本概念 微内核结构将操作系统划分为两大部分:微内核多个服务器微内核包含: 与硬件处理紧密相关的部分一些较基本的功能客户和服务器间的通信客户与服务器之间是借助微内核提供的消息传递机制来实现交互的 基本功能 进程管理 进程的通信、切换、调度…

【算法练习Day24】递增子序列全排列全排列 II

​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 递增子序列容易出错的地方 …