分布式事务理论基础

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

我们会基于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

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

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

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

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

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

相关文章

Hadoop集群搭建(hadoop-3.3.5)

一、修改服务器配置文件 1、配置环境变量 vim /etc/profile #java环境变量 export JAVA_HOME/usr/local/jdk/jdk8 export JRE_HOME$JAVA_HOME/jre export CLASSPATH$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH export PATH$JAVA_HOME/bin:$JRE_HOME/bin:$PATH #hadoop环境变量 …

前端开发怎么解决前端安全性的问题? - 易智编译EaseEditing

前端安全性是保护前端应用程序免受恶意攻击和数据泄露的重要方面。以下是一些解决前端安全性问题的关键方法: 输入验证与过滤: 对所有用户输入进行验证和过滤,防止恶意用户通过注入攻击等手段破坏应用程序或获取敏感信息。 跨站点脚本&#…

[.NET/WPF] CommunityToolkit.Mvvm 异步指令

我们在开发中, 经常会有这样的需求: 点击按钮后, 进行一些耗时的工作工作进行时, 按钮不可再次被点击工作进行时, 会显示进度条, 或者 “加载中” 的动画 RelayCommand CommunityToolkit.Mvvm 中的 RelayCommand 除了支持最简单的同步方法, 还支持以 Task 作为返回值的异步方…

【数据结构入门指南】二叉树

【数据结构入门指南】二叉树 一、二叉树的概念二、现实中的二叉树三、特殊的二叉树四、二叉树的性质五、二叉树的存储结构5.1 顺序结构5.2 链式结构 一、二叉树的概念 二叉树是一棵特殊的树。一棵二叉树是结点的一个有限集合,该节点: ①:或者…

Spring Boot实现IP地址解析

一、本地解析 如果使用本地ip解析的话&#xff0c;我们将会借助ip2region&#xff0c;该项目维护了一份较为详细的本地ip地址对应表&#xff0c;如果为了离线环境的使用&#xff0c;需要导入该项目依赖&#xff0c;并指定版本&#xff0c;不同版本的方法可能存在差异。 <d…

SpringBoot整合Quartz,实现数据库方式执行定时任务

springboot整合quartz&#xff0c;实现数据库方式执行定时任务。把定时任务信息存进数据库&#xff0c;项目启动后自动执行定时任务。 1.引入依赖包&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <ar…

0基础入门代码审计-2 Fortify初探

0x01 序言 目前又加入一位新童鞋了&#xff0c;最近将会再加入cs相关的专栏&#xff0c;都是以基础为主&#xff0c;毕竟太复杂的东西&#xff0c;能看懂的人太少。 0x02 准备工具 1、Fortify 2、需要审计的源码 0x03 Fortify的简单使用 1、 1、在开始菜单栏中找到Audit Wo…

学习ts(五)类

定义 是面向对象程序设计&#xff08;OOP&#xff09;实现信息封装的基础 类是一种用户定义的引用数据类型&#xff0c;也称类类型 JavaScript的class,虽然本质是构造函数&#xff0c;但是使用起来已经方便了许多&#xff0c;js中没有加入修饰符和抽象类等特性 ts的class支持面…

Unity小项目__打砖块

//1.添加地面 1&#xff09;创建一个平面&#xff0c;命名为Ground。 2)创建一个Materials文件夹&#xff0c;并在其中创建一个Ground材质&#xff0c;左键拖动其赋给平面Plane。 3)根据喜好设置Ground材质和Ground平面的属性。 // 2.创建墙体 1&#xff09;创建一个Cube&…

vue3 基础知识 (组件之间的通信 and vuex) 02

侬好哇 &#xff01;&#x1f60d; 文章目录 一、组件的通信 &#xff08;父传子&#xff09;二、非 Prop 的Attribute (属性&#xff09;三、组件的通信 &#xff08;子传父&#xff09;四、非父子组件的相互通信&#xff08;Provide/Inject&#xff09;五、非父子组件的相互通…

高教杯数学建模2020C题总结

&#x1f9e1;1. 前言&#x1f9e1; 跟队友花了三天模拟2020C题&#xff0c;现在整理一下一些数据处理的代码&#xff0c;以及在模拟中没有解决的问题。方便以后回溯笔记。 &#x1f9e1;2. 数据处理&#x1f9e1; 2.1 导入数据&#xff0c;并做相关预处理 import pandas a…

更改计算机睡眠时间

控制面板–>系统和安全–>电源选项下的更改计算机睡眠时间 如果关闭显示器时间小于使计算机进入睡眠状态时间&#xff0c;时间先到达关闭显示器时间&#xff0c;显示器关闭&#xff0c;这时电脑还在正常工作状态。如果此时敲击键盘显示器出现画面&#xff0c;无需输入密…

【云原生】3分钟快速在Kubernetes1.25部署Prometheus2.42+Grafana9.5.1+Alertmanager0.25

文章目录 1、简介2、GitHub地址3、环境信息4、安装5、访问Grafana1、简介 Prometheus-operator帮助我们快速创建Prometheus+Grafana+Alertmanager等服务,而kube-prometheus更加完整的帮助我们搭建全套监控体系,这包括部署多个 Prometheus 和 Alertmanager 实例, 指标导出器…

Php“牵手”淘宝商品SKU信息数据采集方法,淘宝API接口申请指南

淘宝天猫商品属性sku信息接口 API 是开放平台提供的一种 API 接口&#xff0c;它可以帮助开发者获取商品的详细信息&#xff0c;包括商品的标题、描述、图片&#xff0c;销量&#xff0c;sku信息等信息。在电商平台的开发中&#xff0c;商品属性接口API是非常常用的 API&#x…

Lnton羚通算法算力云平台【PyTorch】教程:torch.nn.Softsign

torch.nn.Softsign 原型 CLASS torch.nn.Softsign() 图 代码 import torch import torch.nn as nnm nn.Softsign() input torch.randn(4) output m(input)print("input: ", input) print("output: ", output)# input: tensor([ 0.0046, -0.4135, -2…

智慧健康杂志智慧健康杂志社智慧健康编辑部2023年第15期目录

智慧医疗 医疗信息化 提高病案首页填写质量&#xff0c;体现病案信息利用价值 张明芳; 1-4 经支气管镜检查联合针吸活检术在肺癌诊断中的临床应用价值 邱洪亮; 5-8 高频超声对距腓前韧带损伤的诊断价值 梁劲松;叶绮婷;曹肖维; 9-12《智慧健康》投稿邮箱&#xff1a…

学习笔记 --- RabbitMQ

简介 RabbitMQ是一款开源的消息队列中间件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;标准。作为一个消息代理&#xff0c;RabbitMQ可以在应用程序之间可靠地传递和存储消息&#xff0c;并支持多种消息传递模式。 基本概念和特性 消息&#xff1a;在R…

分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测

分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测 目录 分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.Matlab实现WOA-CNN-BiGRU-Attention多特征分类预测&#xff0c;多特征输入模型&…

MemSeg:一种差异和共性来检测图像表面缺陷的半监督方法

目录 1、摘要 2、Method 2.1 模拟异常样本 2.2 Memory Module 2.3 空间注意模块 2.4 多尺度特征融合模块 2.5 损失函数设置 2.6 Decoder模块 1、摘要 本文认为人为创建类内差异和保持类内共性可以帮助模型实现更好的缺陷检测能力&#xff0c;从而更好地区分非正常图像。如…

分布式核心知识以及常见微服务框架

分布式中的远程调用 在微服务架构中&#xff0c;通常存在多个服务之间的远程调用的需求。远程调用通常包含两个部分&#xff1a;序列化和通信协议。常见的序列化协议包括json、xml、 hession、 protobuf、thrift、text、 bytes等&#xff0c;目前主流的远程调用技术有基于HTTP…