分布式事务

YangeIT大约 32 分钟高级服务框架分布式事务CAP定理BASE理论SeataXA模式AT模式TCC模式SAGA模式高可用架构模型

分布式事务

目标

  • 分布式事务
    • CAP定理 ❤️ 🍐
    • BASE理论 ❤️ 🍐
  • Seata
    • XA模式🍐 ✏️
    • AT模式 ❤️ ✏️
    • TCC模式 ❤️ ✏️
    • SAGA模式🍐 ✏️
  • 高可用架构模型 🍐 ✏️

1.分布式事务问题 🍐

1.1.本地事务Vs分布式事务

本地事务Vs分布式事务

本地事务,也就是传统的单机事务。在传统数据库事务中,必须要满足四个原则:

image-20210724165045186
image-20210724165045186
  • 原子性(Atomicity):本地事务是原子的,要么全部成功,要么全部失败。如果在事务执行过程中发生错误,会回滚事务,以确保不会留下不一致的状态。

  • 一致性(Consistency):本地事务保证了数据库或资源的一致性。在事务开始和结束时,数据应该遵循事务的完整性规则,确保数据的状态在事务之前和之后没有不一致。

  • 隔离性(Isolation):事务之间应该是隔离的,即一个事务的执行不应影响其他事务。本地事务通常使用锁和事务隔离级别来确保不同事务的数据互相隔离。

  • 读未提交(Read Uncommitted):最低的隔离级别。允许一个事务读取另一个事务尚未提交的数据。可能导致脏读、不可重复读和幻影读。
  • 读已提交(Read Committed):允许一个事务只能读取已经提交的数据,而不能读取其他事务尚未提交的数据。防止脏读,但仍可能发生不可重复读和幻影读。
  • 可重复读(Repeatable Read):保证一个事务在读取数据时不会被其他事务所修改。防止脏读和不可重复读,但仍可能发生幻影读。
  • 串行化(Serializable):最高的隔离级别。保证事务之间的完全隔离,不会发生脏读、不可重复读和幻影读。通常会带来最高的性能开销,因为它需要强制顺序执行事务
  • 持久性(Durability):一旦事务被提交,其结果应该在系统故障或崩溃后仍然保持持久。这通常涉及将事务更改写入持久性存储(如磁盘)。

  • 单一资源:本地事务仅涉及单个资源或数据库,没有涉及分布式事务或多个不同的资源。这意味着所有操作都在一个数据库上执行,而不涉及多个数据库或外部系统。

  • 较低的复杂性:与分布式事务相比,本地事务通常更简单,因为它们不需要协调多个参与者或解决分布式一致性问题。

  • 较高的性能:由于本地事务的较低复杂性和较少的协调开销,它们通常具有更高的性能,因为不需要处理网络通信和分布式系统中的复杂协议。

演示分布式事务问题,代码操作

我们通过一个案例来演示分布式事务的问题:

  1. 创建数据库,名为seata_demo,然后导入课前资料提供的SQL文件:
image-20210724165634571
image-20210724165634571
导入步骤
导入步骤
  1. 导入课前资料提供的微服务:
image-20210724165709994
image-20210724165709994

微服务结构如下:

第一次导入可能maven要下载,兄弟们,等待一下 导入

image-20210724165729273
image-20210724165729273

其中:

  • seata-demo:父工程,负责管理项目依赖
  • account-service:账户服务,负责管理用户的资金账户。提供扣减余额的接口
  • storage-service:库存服务,负责管理商品库存。提供扣减库存的接口
  • order-service:订单服务,负责管理订单。创建订单时,需要调用account-servicestorage-service

3)启动nacos、所有微服务

  1. 启动nacos
image
image
  1. 修改各个微服务的application.yml的数据库密码 image

  2. 启动各个微服务 image

2.理论基础 ❤️ 🍐

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

2.1.CAP定理 ❤️ 🍐

CAP定理

1998年,加州大学的计算机科学家 Eric Brewer【埃里克·布鲁尔】 提出,分布式系统有三个指标。

  • Consistency(一致性) [kənˈsɪstənsi]
  • Availability(可用性) [əˌveɪləˈbɪləti]
  • Partition tolerance (分区容错性)[pɑrˈtɪʃ(ə)n] [ˈtɑlərəns]
image
image

它们的第一个字母分别是 C、A、P。

Eric Brewer【埃里克·布鲁尔】 说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理。

CAP 定理解释:👇

Consistency(一致性):用户访问分布式系统中的任意节点,得到的数据必须一致。

比如现在包含两个节点,其中的初始数据是一致的:

image-20210724170704694
image-20210724170704694

当我们修改其中一个节点的数据时,两者的数据产生了差异:

image-20210724170735847
image-20210724170735847

要想保住一致性,就必须实现node01 到 node02的数据 同步:

image-20210724170834855
image-20210724170834855

总结

  • 解释CAP定理是什么?

答案: CAP定理是由计算机科学家Eric Brewer提出的,它指出在分布式系统中,无法同时满足三个属性:一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)。根据CAP定理,分布式系统只能满足其中两个属性中的任意两个,但无法同时满足所有三个。

  • 分布式系统节点通过网络连接,一定会出现分区问题(P)
  • 当分区出现时,系统的一致性(C)和可用性(A)就无法同时满足

2.2.BASE理论 ❤️ 🍐

BASE理论

image
image

BASE理论是对CAP的一种解决思路,包含三个思想:

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

解决分布式事务的思路:🍐

image
image

分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴CAP定理BASE理论,有两种解决思路:

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

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

思考:为什么P都要存在?

但不管是哪一种模式,都需要在子系统事务之间互相通讯,协调事务状态,也就是需要一个事务协调者(TC)

image-20210724172123567
image-20210724172123567

这里的子系统事务,称为分支事务;有关联的各个分支事务在一起称为全局事务

总结

  1. 简述BASE理论三个思想:
  • 基本可用
  • 软状态
  • 最终一致
  1. 解决分布式事务的思想和模型:
  • 全局事务:整个分布式事务
  • 分支事务:分布式事务中包含的每个子系统的事务
  • 最终一致思想:各分支事务分别执行并提交,如果有不一致的情况,再想办法恢复数据
  • 强一致思想:各分支事务执行完业务不要提交,等待彼此结果。而后统一提交或回滚

3.初识Seata ❤️ 🍐

初识Seata

imageSeata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。致力于提供高性能和简单易用的分布式事务服务,为用户打造一站式的分布式解决方案。

官网地址:http://seata.io/open in new window
其中的文档、播客中提供了大量的使用说明、源码分析。 image

代码操作

3.3.1.引入依赖

首先,在order-service中引入依赖:

<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <!--版本较低,1.3.0,因此排除--> 
        <exclusion>
            <artifactId>seata-spring-boot-starter</artifactId>
            <groupId>io.seata</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <!--seata starter 采用1.4.2版本-->
    <version>${seata.version}</version>
</dependency>

总结

  • nacos服务名称组成包括?
    • namespace + group + serviceName + cluster
      • 如:public@DEFAULT_GROUP@seata-tc-server@SH
  • seata客户端获取tc的cluster名称方式?
    • tx-group-service[事务组]的值为key到vgroupMapping[映射]中查找

4.动手实践

下面我们就一起学习下Seata中的四种不同的事务模式。

4.1.XA模式 🍐 ❤️

XA模式

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

实现XA模式-代码操作

Seata的starter起步依赖已经完成了XA模式的自动装配,实现非常简单,步骤如下:

1)修改application.yml文件每个参与事务的微服务,开启XA模式:

seata: # 顶格写
  data-source-proxy-mode: XA

修改配置文件,开启xa,开启数据源代理模式,让代码中发起的事务被seata,也就是RM拦截下来,调用内部的xa接口(数据库支持),从而实现XA模式

总结

XA模式的优点是什么?

  • 事务的强一致性,满足ACID原则。
  • 常用数据库都支持,实现简单,并且没有代码侵入 XA模式的缺点是什么?
  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
  • 依赖关系型数据库实现事务

4.2.AT模式

AT模式

AT模式同样是分阶段提交的事务模型,不过缺弥补了XA模型中资源锁定周期过长的缺陷。

1.Seata的AT模型

基本流程图:

image-20210724175327511
image-20210724175327511

阶段一RM的工作:

  • 注册分支事务
  • 记录undo-log(数据快照)
  • 执行业务sql并提交
  • 报告事务状态

阶段二提交时RM的工作:

  • 删除undo-log即可

阶段二回滚时RM的工作:

  • 根据undo-log恢复数据到更新前

实现AT模式-代码操作

AT模式中的快照生成、回滚等动作都是由框架自动完成,没有任何代码侵入,因此实现非常简单。

只不过,AT模式需要一个表来记录全局锁lock_table表、另一张表来记录数据快照undo_logundo_log表。✏️

1)导入数据库表,记录全局锁

导入课前资料提供的Sql文件:seata-at.sql,其中:

  • lock_table导入到TC服务关联的数据库,
  • undo_log表导入到微服务关联的数据库:
image-20210724182217272
image-20210724182217272

2)修改application.yml文件,将事务模式修改为AT模式即可每个服务都要改

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

4.3.TCC模式 🎯 🍐 ❤️ ✏️

TCC模式

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

  • Try:资源的检测和预留;

  • Confirm:完成资源操作业务;要求 Try 成功 Confirm 一定要能成功。

  • Cancel:预留资源释放,可以理解为try的

TCC模式-代码操作

解决空回滚和业务悬挂问题,必须要记录当前事务状态,是在try、还是cancel? 🍐

1)思路分析

这里我们定义一张表:

CREATE TABLE `account_freeze_tbl` (
  `xid` varchar(128) NOT NULL,
  `user_id` varchar(255) DEFAULT NULL COMMENT '用户id',
  `freeze_money` int(11) unsigned DEFAULT '0' COMMENT '冻结金额',
  `state` int(1) DEFAULT NULL COMMENT '事务状态,0:try,1:confirm,2:cancel',
  PRIMARY KEY (`xid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

其中:

  • xid:是全局事务id
  • freeze_money:用来记录用户冻结金额
  • state:用来记录事务状态

那此时,我们的业务开怎么做呢?

  • Try业务:
    • 记录冻结金额和事务状态到account_freeze表
    • 扣减account表可用金额
  • Confirm业务
    • 根据xid删除account_freeze表的冻结记录
  • Cancel业务
    • 修改account_freeze表,冻结金额为0,state为2
    • 修改account表,恢复可用金额
  • 如何判断是否空回滚?
    • cancel业务中,根据xid查询account_freeze,如果为null则说明try还没做,需要空回滚
  • 如何避免业务悬挂?
    • try业务中,根据xid查询account_freeze ,如果已经存在则证明Cancel已经执行,拒绝执行try业务

接下来,我们改造account-service,利用TCC实现余额扣减功能。🎯

思考:为什么不搞order模块?

总结

  • TCC模式的每个阶段是做什么的?
    • Try:资源检查和预留
    • Confirm:业务执行和提交
    • Cancel:预留资源的释放
  • TCC的优点是什么?
    • 一阶段完成直接提交事务,释放数据库资源,性能好
    • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
    • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库
  • TCC的缺点是什么?
    • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
    • 软状态,事务是最终一致
    • 需要考虑Confirm和Cancel的失败情况,做好幂等处理

4.4.SAGA模式 🍐

SAGA模式

Saga 模式是 Seata 即将开源的长事务解决方案,将由蚂蚁金服主要贡献。

其理论基础是Hector & Kenneth 在1987年发表的论文Sagasopen in new window

Seata官网对于Saga的指南:https://seata.io/zh-cn/docs/user/saga.htmlopen in new window

5.高可用 🍐 ❤️

5.1.高可用架构模型

高可用架构模型

Seata的TC服务作为分布式事务核心,一定要保证集群的高可用性

搭建TC服务集群非常简单,启动多个TC服务,注册到nacos即可。

但集群并不能确保100%安全,万一集群所在机房故障怎么办?所以如果要求较高,一般都会做异地多机房容灾。

比如一个TC集群在上海,另一个TC集群在杭州:

image-20210724185240957
image-20210724185240957

微服务基于事务组(tx-service-group)与TC集群的映射关系,来查找当前应该使用哪个TC集群。当SH集群故障时 ,只需要将vgroup-mapping中的映射关系改成HZ。则所有微服务就会切换到HZ的TC集群了。

代码操作

5.2.实现高可用

参考课前资料提供的文档《 seata的部署和集成.md 》点击跳转到文档

image-20210724172549013
image-20210724172549013

第三章节:

image-20210724185638729
image-20210724185638729

面试题

  • 基础级别:

    • 什么是分布式事务,为什么它在分布式系统中很重要?
    • 解释CAP定理,它对分布式系统设计有何影响?
    • 什么是ACID属性,它们在分布式事务中有什么作用?
    • 为什么传统的本地事务管理在分布式环境中不适用?
    • Seata是什么,它的主要作用是什么?
  • 中级级别:

    • 请描述分布式事务的两阶段提交(2PC)协议,以及它的工作原理。
    • Seata中的三个核心组件分别是什么?分别负责什么任务?
    • 什么是弱一致性,何时可以在分布式事务中接受它?
    • 请讨论Seata如何实现分布式事务的全局事务管理和协调。
    • 什么是分布式事务的悬挂(Hanging)问题,Seata如何解决它?
  • 高级级别:

    • 解释Seata中的AT模式(原子性事务),TCC模式(Try-Confirm-Cancel),和SAGA模式的区别和适用- 场景。
    • 什么是基于消息的分布式事务,Seata中如何实现它?
    • 谈论Seata的分布式存储(UndoLog)如何用于补偿分布式事务。