分布式事务理论基础

今天啊,本片博客我们一起来学习一下微服务中的一个重点和难点知识:分布式事务。

我们会基于Seata 这个框架来学习。

1、分布式事务问题

事务,我们应该比较了解,我们知道所有的事务,都必须要满足ACID的原则。也就是

image-20230328192513554

在我们以前所学习的单体架构当中的这个服务直接访问一个数据库,业务比较简单。基于数据库本身的特性,就已经能够实现ACID了。

但是,我们现在要研究的是微服务。微服务的业务往往比较复杂,可能一个业务啊,就会跨越多个服务,而每个服务又会有自己的数据库。

这个时候你再靠数据库本身的特性,还能保证整个业务的ACID吗?这可就不一定了。

我们来看一个例子啊。

image-20230328192752165

比方说我这里有一个微服务,它里边啊包含三个服务啊,有订单有账户和库存。

现在,我们有一个用户下单的业务,用户下单时,我希望订单服务去创建订单,并且写入数据库。

然后,他再去调用账户服务和库存服务,账户服务呢,去扣减用户的余额,而库存服务呢,则去扣减商品库存。

那你可以看到这个业务里边就包含了三个不同的微服务的调用,而每个微服务都有自己独立的数据库,也就是独立的事务。

那我们最终希望的肯定是我这个下单业务一旦执行,每一个是不是都要成功?当然,如果你失败,是不是大家都失败?

1.1 演示分布式事务问题

结果是这样一个的结果,但是能不能达到这样一个效果?我们来验证一下。

微服务结构如下:

image-20230328194429179

其中:

seata-demo:父工程,负责管理项目依赖

  • account-service:账户服务,负责管理用户的资金账户。提供扣减余额的接口
  • storage-service:库存服务,负责管理商品库存。提供扣减库存的接口
  • order-service:订单服务,负责管理订单。创建订单时,需要调用account-service和storage-service

我们先来看一下这个order(订单服务)。看下它里边的业务逻辑啊,在controller里边啊我们可以看到一个创建订单的接口。

image-20230328195453369

在controller当中呢,它就调了service,所以我们进去入service方法。

image-20230328203507452

在这个service方法当中 ,我们可以看到它先去创建订单,把这个订单数据直接写到数据库当中。

那创建完订单了就去调用accountClient (扣用户余额)和storageClient(扣库存)完成扣余额和扣库存。

accountClient 和 storageClient 是通过 Feign调用的。

image-20230328200505074

这是这三张表的数据。

业务逻辑就是这样的了,我们接下来使用Postman去做一下测试。

image-20230328202949554

我们发送请求。

image-20230328204822270

返回了500,我们看一下数据库。

image-20230328204905021

发现用户余额少了200。

image-20230328204924437

订单并没有创建

image-20230328204940524

库存也没有减少。

这个时候事务的状态是一致的吗?不是吧?

那为什么会这样子呢?

那在刚才的业务当中,我们的订单服务去创建了订单。

然后去调用账务服务和库存服务,完成余额扣减和库存扣减。

其中,订单和账务服务啊,都执行成功了。

image-20230328205156568

而库存服务在执行的时候却因为库存不足而报错了。

image-20230328205213745

那按照理论上讲,这里一报错,前边是不是都应该跟着回滚啊?但是我们所看到的结果是库存服务失败了,账户的余额该扣还是扣了?为什么呢?

第一,我们的每一个服务都是独立的。

那现在库存服务你抛了异常。

账户服务它知不知道?它是不知道的呀!

那我都不知道你抛异常了,我去回滚什么呢?

第二,每一个服务是独立的,所以他们的事务呢,也是独立的。

那现在我订单服务和账务服务,我执行完业务以后,我事务结束了,我是不是直接就提交了呀?

现在你让我回滚,我怎么回滚?我事都办完了,提交了,就撤销不了了。

所以最终就没有达成事务状态的一致,那么这个时候啊,就出现了分布式事务的问题了!

1.2 什么是分布式事务

那我们总结一下什么是分布式事务。

在分布式系统下一个业务,它跨越了多个服务和数据源。每一个服务都可以认为是一个分支事务,而我们要保证的是所有分支事务最终状态一致。

要么大家都成功,要么大家都失败。那么这样的一种事务就是分布式事务了。

那为什么分布式事务出现了问题?

就是因为各个服务之间,或者说各个分支事务之间互相是感知不到的,大家各提交各的,那将来呀,就无法去回滚,就导致状态无法一致。

2、理论基础

接下来我们就进入分布式事务理论基础的学习。

解决分布式事务问题,需要一些分布式系统的基础知识作为理论指导。

2.1 CAP定理

CAP定理是1998年啊,加州大学的计算机科学家Eric Brewer 提出的,那它说分布式系统里边往往有三个指标。

分别是:

  • Consistency(一致性)
  • Availability(可用性)
  • Partition tolerance (分区容错性)

那艾瑞克说呢,这三个指标啊,分布式系统它不可能同时满足。

你像这三个圆,不就是分别三个特性吗?

image-20230328211612211

但是你看这三个圆不会出现三个同时重叠啊,最多就是两两重叠。

那么这个结论就叫CAP定理了。那为什么会出现这样一个情况呢?

我们必须得先弄清楚啊,一致性,可用性和分区容错性代表的含义才能理解这个其中含义。

2.1.1.一致性

那我们先来看一下其中的第一个,一致性。

一致性是说用户在访问分布式系统中的任意节点时得到的数据必须是一致的。比方说我现在有两个结点。

image-20230328212029032

那第一个结点上面有一个数据叫data值是v0,第二个结点上也是如此。那它们其实就形成了一个什么呢?主从。

现在用户去访问这两个节点啊,不管访问的是谁,拿到结果是不是都一样的?

image-20230328212247822

但是呢,现在如果我对node 1节点的数据发生了修改。

image-20230328212305352

这个时候两个节点数据是不是就不一样了?

那为了满足一致性,你要做什么?

你是不是一定要把node 01的数据同步给node 02啊?

image-20230328212322284

一旦两者的数据同步完成,数据是不是再次一致了?所以呢,作为一个分布式系统。

在做数据备份的时候,你一定要及时的去完成数据同步,这样才能满足一致性。

2.1.2.可用性

第二个概念可用性。

它说用户在访问集群中的任意健康节点的时候啊,必须得到响应,而不是超时或者拒绝。

比方说我现在这个集群里就有三个节点啊。

image-20230328212442424

正常情况下用户访问任何一个是不是都没问题。

image-20230328212504702

现在啊,这三个节点没有出现宕机的情况。但是不知道什么原因啊,比如说这个node3,它的请求就会被阻塞或者拒绝了。

image-20230328212521372

那所有请求进来根本就无法访问了。这个时候node3不就不可用了。所以可用性是指这个节点能不能被正常的访问。

2.1.3 分区容错

第三个概念 :分区容错。

分区是指因为网络的故障或者其他原因导致分布式系统中的部分节点与其他节点失去了连接,形成独立分区。

比方说还是这三个节点啊node 123。

image-20230328213428467

然后用户呢,可以访问其中任意一个。

但是因为网络出现了故障,机器没有挂,然后node 3与node 1和node 2之间断开了连接。

image-20230328213509738

node 1,node 2,正常访问啊,它们之间是能够感知到对方的,但node 3感知不到了。所以呢,此时整个集群就会被划分成两个区了。

那node1和node2它们俩是一个区,node3自己是一个分区。

这个时候如果有用户向node 02写入了一个新的数据。

image-20230328213621216

那node 02是可以把数据同步给node 01的。

image-20230328213631968

但是那么node 3上面有没有同步?

显然没有,因为他们感知不到了,怎么去做同步?

那这两个分区数据就不一致了。

那分区容错是什么意思呢?

容错就是不管集群有没有出现分区啊,整个系统也要持续对外提供服务。

2.1.4.矛盾

那也就是说,尽管你这儿分区了,那用户该访问是不是还要访问呢?

但是如果我现在去访问node1,我拿到的结果和访问node3拿到结果一样吗?不一样。

所以出现了数据不一致的情况,没有满足一致性。那如果我一定要满足一致性。

我应该怎么办?那我是不是可以这么做?

我让node 3它等待node 2这个网络的恢复和数据的同步。

在恢复之前。所有来访问我的请求,我都阻塞在这里,说你们等等我这数据还没好。

可不可以?

那如果这么做,我是不是就能够满足数据的一致性了?但是你的node3明明是一个健康的节点,结果进来的请求你都卡在这里,不让人家访问了。

那node3不就变成不可用了吗?所以它就不满足可用性了。

所以你现在就会发现当网络出现分区时,可用性和一致性是不是没有办法同时满足?但是呢,这个分区它又是不可避免的。

为什么这么说呢?

只要你是一个分布式系统,你的节点之间是不是一定是通过网络连接的?而你只要是通过网络连接的,你有没有办法保证网络100%永远是健康的?

这不可能吧?

所以我们可以认为凡是分布式系统分区一定会出现,既然分区一定会出现。

而你整个集群,又必须要对外提供服务,那也就认为.

Partition tolerance (分区容错性)一 定要实现,那么这个时候Consistency(一致性)和 Availability(可用性)之间,你是不是要做出抉择了?你要么Consistency,要么Availability。没有办法同时满足啊,

这也就是CAP 定理的一个原因了。

2.2 BASE理论

我们已经学习了CAP 的定理,我们知道在分布式系统下,因为分区不可避免,所以你不得不在一致性和可用性之间做出一个选择,但是这两个特性啊,其实都非常的重要,我一个都不想放弃,那我该怎么办呢?

好那么 BASE 理论正好可以解决这个问题.

BASE 理论它是对CAP 的一种解决的思路。其实呢,主要包含了三个思想:

  • Basically Available (基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
  • **Soft State(软状态):**在一定时间内,允许出现中间状态,比如临时的不一致状态。
  • Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。

其实BASE理论正是对CAP里边,这种Consistency(一致性)和 Availability(可用性)的矛盾去做一种调和和选择。

那在CAP里边你要达到了一致性,你就要牺牲可用性,但是在BASE 里我们如果达到了强的一致性,你是要牺牲可用性,但不是不可用,而是部分可用性的一个牺牲或者临时的不可用。

2.3.解决分布式事务的思路

说了这么多的思想,它能不能去解决我们分布式事务的问题呢?

其实是可以的。那我们分布式事务里边出现了什么问题呢?

分布式事务当中往往包含n个子事务,每个事务各自执行和提交。结果呢,有些成功,有些失败了,这个时候大家的状态不一致。

而我们希望的就是这个分布式事务里边的每个子事务,大家最终状态一定要一致,要么都成功,要么都失败。

那我们基于base理论怎么样去解决这分布式事务呢?

第一种解决方案其实就是基于AP的模式。

AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。

也就是满足可用性,牺牲一定的一致性。比如说我们各个子事务,将来我们执行的时候分别去执行和提交,那有些成功有些失败了,那这叫什么?

这叫状态不一致。

也就是说你处于一个什么?

软状态了。

临时的不一致状态,没关系,为什么呢?执行完了以后我们各个子事务可以通个气。

互相看一看哎,你成功了吗?哦,我成功了呃,你成功了吗?哎,这么一对比发现有人失败了怎么办?

这个时候别着急啊,我们采取一个弥补的措施去恢复数据啊,那有的说已经提交了,没法恢复了呀,那我们可以做反向的操作呀,比如说你之前新增了一个对不对?

那我接下来我把它删了不就完了吗?

这样不就把数据又恢复到原来的状态了,那这样不就实现了最终一致了吗?

所以这种模式啊,其实就是一种AP的一种思想了,

那反过来呢,我可不可以达成强一致呢?哎,也是可以的。

CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。

之前是各个子事务啊,是分别执行和提交,你一上来全部执行完了,那么没法回滚,对不对?

但现在呢,我各个子事务执行完,别提交,互相等待,大家彼此看一看啊诶,我这执行完了,你执行完了没有?这样直到什么我们全部都执行完都没问题。

那我们同时提交或者中间有人失败了,那我们同时回滚,那么这样是不是就能达成强一致了?没有中间状态对不对?

只不过在这个过程中啊,你的各个子事务是不是要互相等待啊?等待彼此的执行嘛,所以在这个过程当中,你的服务其实是处于一个弱可用状态。

因为你会锁定资源啊,导致无法访问嘛。

你看我们是不是就基于base的这种理论来实现了分布式事务的一种解决的一个思想了?

后面我们解决分布式事务都会基于这样一个思想去做,但是无论你是CP还是AP,这里边有一个共同点那就是各个子事务将来要做一个互相的通信,去辨别对方的执行状态。

那么各个子事务之间怎么去通信呢?

所以呢,它就需要有一个协调者来帮助分布式事务中的各个子事务进行一个通信啊感知。对方的或者彼此的状态,那我们就举个例子啊,就以我们之前的那个下单为例。

image-20230329192722139

用户下单调用订单服务,然后去调用账务服务和库存服务。那这个地方呢?我们就需要有一个事务的协调者了,然后每一个微服务都跟事务的协调者啊,保持一个联系。

image-20230329192830032

业务来了以后啊,大家各自执行。如果你现在要做强一致,那好第三服务执行的时候不要提交啊。执行下单扣款服务,执行扣款库存服务,执行库存。

但是执行完了以后,结果发现库存失败了。

image-20230329192952905

怎么知道的?他们要把自己的执行结果是不是告知这个协调者?然后这协调者一看有人失败了再通知他们将来去做这个回滚。

那这样大家是不是就能保持一致了?所以呢,这个事务的协调者啊,就起到了一个非常关键的作用了,那么在整个过程当中啊,我们参与分布式事务当中的每一个子系统的事务,我们称之为叫分支事务。

而整个分支事务称之为叫全局事务,所以事务协调者其实就是来去协调各个分支事务的状态的,让他们达成一致。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS中的display属性有哪些值?它们的作用?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS display 属性的不同取值和作用1. block2. inline3. inline-block4. none5. flex6. grid7. table、table-row、table-cell8. list-item9. inline-table、table-caption、table-column 等 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#x…

[ubuntu]ubuntu18.04使用自带共享桌面实现vncserver连接

vncserver有很多方法比如你安装vnc4server,tightvncserver,x11vnc等都可以实现vnc局域网连接,今天使用系统共享桌面设置vnc连接 Ubuntu开启远程桌面 Ubuntu18.04使用gnome桌面环境,系统自带屏幕共享和远程登录功能,默认使用的是vino作为VNC…

open suse 15.5(任意版本) 使用阿里云的repo

一、shell suse 的包管理工具叫 zypper. zypper addrepo -f http://mirrors.aliyun.com/opensuse/distribution/leap/15.5/repo/oss/ openSUSE-15.5-Oss zypper addrepo -f http://mirrors.aliyun.com/opensuse/distribution/leap/15.5/repo/non-oss/ openSUSE-15.5-Non-Oss …

python爬虫9:实战2

python爬虫9:实战2 前言 ​ python实现网络爬虫非常简单,只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点,方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论,并不会对网站产生不好…

Air780EG —— 合宙4G定位解决方案

定位模式: 外部单片机控制模式(常见于AT固件客户): 开机 -> 搜星 -> 定位成功 -> 上报 -> 关机 780E自行控制模式(常见于二次开发客户,AT用户也可以使用): 开机 -> 搜星 -> 定位成功 -> 模块休眠,关闭GP…

C++新经典01--函数递归

函数的递归 #include <stdio.h> void diguifunc() {printf("diguifunc()函数执行\n");diguifunc();//自己调用自己 }void main(){diguifunc(); }把程序执行起来&#xff0c;等几秒钟&#xff0c;可以看到&#xff0c;屏幕不断滚动并输出如下内容&#xff1a; …

AP9235 dc-dc升压恒流电源驱动IC 2000ma SOT23-6

概述 AP9235B 系列是一款固定振荡频率、恒流输出的升压型DC/DC转换器&#xff0c;非常适合于移动电话、PDA、数码相机等电子产品的背光驱动。输出电压可达30V &#xff0c;3.2V输入电压可以驱动六个串联LED&#xff0c; 2.5V输入电压可以驱动两路并联LED&#xff08;每路串联…

Android Studio调试出现错误时,无法定位错误信息解决办法

做项目时运行项目会出现问题&#xff0c;但是找不到具体位置&#xff0c;如下图所示&#xff1a;感觉是不是很懵逼~&#xff0c;Log也没有显示是哪里的问题 解决方案&#xff0c;在右侧导航栏中选择Gradle——app——build&#xff0c;然后点击运行 运行结果如下&#xff0c;很…

YOLO目标检测算法调试过程学习记录

先前已经完成过YOLO系列目标检测算法的调试过程&#xff0c;今天主要是将所有的调试加以总结 这里的conda环境就不再赘述了&#xff0c;直接使用requirement.txt文件的即可&#xff0c;也可以参考YOLOX的配置过程5 数据集处理 YOLOv5有自己的数据集格式&#xff0c;博主的数据…

live555在Windows WSL2中编译、运行,搭建RTSP流服务器

文章目录 1. 背景2. 实施步骤2.1 下载live555安装包2.2 解压压缩包2.3 编译源码2.3 安装ffmpeg2.4 安装opencv-python2.5 视频文件格式转换2.6 启动推流2.6 安装VLC&#xff0c;验证 3. 用opencv-python接口接收视频流参考 1. 背景 想要通过RTSP往opencv的接口中推流&#xff…

选择靠谱商城系统的重要性

电子商务的蓬勃发展&#xff0c;越来越多的企业和商家开始进入电商领域&#xff0c;希望通过搭建自己的网上商城来实现业务增长和利润提升。然而&#xff0c;在选择合适的商城系统时&#xff0c;很多人往往会忽视靠谱性这一关键因素。下面就选择靠谱商城系统的重要性作一些简单…

DataSecurity Plus:守护企业数据安全的坚实屏障

在数字化时代&#xff0c;数据被誉为企业最重要的资产之一。然而&#xff0c;随着大数据的兴起和信息的日益增长&#xff0c;企业面临着前所未有的数据安全挑战。为了应对这些挑战&#xff0c;数据安全管理变得至关重要。在这个领域&#xff0c;ManageEngine的DataSecurity Plu…

一篇文章教你自动化测试如何解析excel文件?

前言 自动化测试中我们存放数据无非是使用文件或者数据库&#xff0c;那么文件可以是csv&#xff0c;xlsx&#xff0c;xml&#xff0c;甚至是txt文件&#xff0c;通常excel文件往往是我们的首选&#xff0c;无论是编写测试用例还是存放测试数据&#xff0c;excel都是很方便的。…

【Linux】进程间通信之信号机制2

文章目录 信号阻塞代码验证验证信号的阻塞验证信号的阻塞不影响信号注册验证可靠信号不会丢信号&#xff0c;不可靠信号会丢信号验证9号和19号信号不能被阻塞 用信号解决僵尸进程volatile关键字 信号阻塞代码验证 在上篇详解信号机制的博文中&#xff0c;我们提到了设置阻塞位…

Vue-9.集成(.editorconfig、.eslintrc.js、.prettierrc)

介绍 同时使用 .editorconfig、.prettierrc 和 .eslintrc.js 是很常见的做法&#xff0c;因为它们可以在不同层面上帮助确保代码的格式一致性和质量。这种组合可以在开发过程中提供全面的代码维护和质量保证。然而&#xff0c;这也可能增加一些复杂性&#xff0c;需要谨慎配置…

一文详解4种聚类算法及可视化(Python)

在这篇文章中&#xff0c;基于20家公司的股票价格时间序列数据。根据股票价格之间的相关性&#xff0c;看一下对这些公司进行聚类的四种不同方式。 苹果&#xff08;AAPL&#xff09;&#xff0c;亚马逊&#xff08;AMZN&#xff09;&#xff0c;Facebook&#xff08;META&…

【Java】Java如何生成随机数?

文章目录 前言一、Random类介绍二、Random类生成随机数1.生成随机数2.nextInt()方法 三、使用场景四、官方提示总结 前言 我们在学习 Java 基础时就知道可以生成随机数&#xff0c;可以为我们枯燥的学习增加那么一丢丢的乐趣。本文就来介绍 Java 随机数。 一、Random类介绍 …

docker的资源控制及docker数据管理

文章目录 docker的资源控制及docker数据管理一.docker的资源控制1.CPU 资源控制1.1 资源控制工具1.2 cgroups有四大功能1.3 设置CPU使用率上限1.4 进行CPU压力测试1.5 设置50%的比例分配CPU使用时间上限1.6 设置CPU资源占用比&#xff08;设置多个容器时才有效&#xff09;1.6.…

合宙Air724UG LuatOS-Air LVGL API--简介

为何是 LVGL LVGL 是一个开源的图形库&#xff0c;它提供了创建嵌入式 GUI 所需的一切&#xff0c;具有易于使用的图形元素、漂亮的视觉效果和低内存占用的特点。 LVGL特点&#xff1a; 强大的 控件 &#xff1a;按钮、图表、列表、滑动条、图像等 高级图形引擎&#xff1a;动…

【Visual Studio】生成.i文件

环境 VS版本&#xff1a;VS2013 问题 如何生成.i预编译文件&#xff1f; 步骤 1、打开VS项目属性&#xff0c;打开C/C\预处理器页面&#xff0c;【预处理到文件】选择是&#xff0c;开启。 2、生成文件如下。 3、正常编译需要关闭此选项。