seata框架的工作原理:

1.分布式事务问题

1.本地事务
在传统数据库事务中,必须要满足四个原则:
image.png
2.分布式事务
分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务,例如:

  • 跨数据源的分布式事务
  • 跨服务的分布式事务
  • 综合情况

    2.理论基础

    分布式系统有三个指标。

  • Consistency(一致性)

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

这三个指标不可能同时做到。这个结论就叫做 CAP 定理。
BASE理论
BASE理论是对CAP的一种解决思路,包含三个思想:

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

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

  • AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。(柔性事务)
  • CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。(刚性事务)

但不管是哪一种模式,都需要在子系统事务之间互相通讯,协调事务状态,也就是需要一个事务协调者(TC)
image.png
这里的子系统事务,称为分支事务;有关联的各个分支事务在一起称为全局事务

3.Seata

http://seata.io/

3.1Seata的架构

Seata事务管理中有三个重要的角色:

  • TC (Transaction Coordinator) -事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) -事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) -资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

image.png
Seata基于上述架构提供了四种不同的分布式事务解决方案:

  • XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
  • TCC模式:最终一致的分阶段事务模式,有业务侵入
  • AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
  • SAGA模式:长事务模式,有业务侵入

无论哪种方案,都离不开TC,也就是事务的协调者。

3.2.部署TC服务

3.3.1.引入依赖

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

  1. <!--seata-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  5. <exclusions>
  6. <!--版本较低,1.3.0,因此排除-->
  7. <exclusion>
  8. <artifactId>seata-spring-boot-starter</artifactId>
  9. <groupId>io.seata</groupId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>
  13. <dependency>
  14. <groupId>io.seata</groupId>
  15. <artifactId>seata-spring-boot-starter</artifactId>
  16. <!--seata starter 采用1.4.2版本-->
  17. <version>${seata.version}</version>
  18. </dependency>

3.3.2.配置TC地址

在order-service中的application.yml中,配置TC服务信息,通过注册中心nacos,结合服务名称获取TC地址:

seata:
  registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
    type: nacos # 注册中心类型 nacos
    nacos:
      server-addr: 127.0.0.1:8848 # nacos地址
      namespace: "" # namespace,默认为空
      group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
      application: seata-tc-server # seata服务名称
      username: nacos
      password: nacos
  tx-service-group: seata-demo # 事务组名称
  service:
    vgroup-mapping: # 事务组与cluster的映射关系
      seata-demo: SH

3.3.3添加@GlobalTransactional注解:

给发起全局事务的入口方法添加@GlobalTransactional注解:
本例中是OrderServiceImpl中的create方法.image.png

4.动手实践

4.1.XA模式

4.1.1.两阶段提交

XA是规范,目前主流数据库都实现了这种规范,实现的原理都是基于两阶段提交。
正常情况:
image.png
异常情况:
image.png
一阶段:

  • 事务协调者通知每个事物参与者执行本地事务
  • 本地事务执行完成后报告事务执行状态给事务协调者,此时事务不提交,继续持有数据库锁

二阶段:

  • 事务协调者基于一阶段的报告来判断下一步操作
    • 如果一阶段都成功,则通知所有事务参与者,提交事务
    • 如果一阶段任意一个参与者失败,则通知所有事务参与者回滚事务


4.1.2.Seata的XA模型

Seata对原始的XA模式做了简单的封装和改造,以适应自己的事务模型,基本架构如图:
image.png
RM一阶段的工作:
① 注册分支事务到TC
② 执行分支业务sql但不提交
③ 报告执行状态到TC
TC二阶段的工作:

  • TC检测各分支事务执行状态a.如果都成功,通知所有RM提交事务b.如果有失败,通知所有RM回滚事务

RM二阶段的工作:

  • 接收TC指令,提交或回滚事务


4.1.3.优缺点

XA模式的优点是什么?

  • 事务的强一致性,满足ACID原则。
  • 常用数据库都支持,实现简单,并且没有代码侵入

XA模式的缺点是什么?

  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
  • 依赖关系型数据库实现事务


4.1.4.实现XA模式

Seata的starter已经完成了XA模式的自动装配,实现非常简单,步骤如下:
1)修改application.yml文件(每个参与事务的微服务都要修改),开启XA模式:

seata:
  data-source-proxy-mode: XA


2)给发起全局事务的入口方法添加@GlobalTransactional注解:
本例中是OrderServiceImpl中的create方法.image.png
3)重启服务并测试
重启order-service,再次测试,发现无论怎样,三个微服务都能成功回滚。

4.2.AT模式

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

4.2.1.Seata的AT模型

基本流程图:
image.png
阶段一RM的工作:

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

阶段二提交时RM的工作:

  • 删除undo-log即可

阶段二回滚时RM的工作:

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

流程图:
image.png

4.2.3.AT与XA的区别

简述AT模式与XA模式最大的区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
  • XA模式强一致;AT模式最终一致

    4.2.4.脏写问题

    在多线程并发访问AT模式的分布式事务时,有可能出现脏写问题,如图:
    image.png
    解决思路就是引入了全局锁的概念。在释放DB锁之前,先拿到全局锁。避免同一时刻有另外一个事务来操作当前数据。
    image.png

    4.2.5.优缺点

    AT模式的优点:

  • 一阶段完成直接提交事务,释放数据库资源,性能比较好

  • 利用全局锁实现读写隔离
  • 没有代码侵入,框架自动完成回滚和提交

AT模式的缺点:

  • 两阶段之间属于软状态,属于最终一致
  • 框架的快照功能会影响性能,但比XA模式要好很多


4.3.TCC模式

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

  • Try:资源的检测和预留;
  • Confirm:完成资源操作业务;要求 Try 成功 Confirm 一定要能成功。
  • Cancel:预留资源释放,可以理解为try的反向操作。

    4.3.3.优缺点

    TCC模式的每个阶段是做什么的?

  • Try:资源检查和预留

  • Confirm:业务执行和提交
  • Cancel:预留资源的释放

TCC的优点是什么?

  • 一阶段完成直接提交事务,释放数据库资源,性能好
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库

TCC的缺点是什么?

  • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
  • 软状态,事务是最终一致
  • 需要考虑Confirm和Cancel的失败情况,做好幂等处理

4.4.SAGA模式

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

4.4.1.原理

在 Saga 模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作。
分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会去退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。
image.png
Saga也分为两个阶段:

  • 一阶段:直接提交本地事务
  • 二阶段:成功则什么都不做;失败则通过编写补偿业务来回滚

    4.4.2.优缺点

    优点:

  • 事务参与者可以基于事件驱动实现异步调用,吞吐高

  • 一阶段直接提交事务,无锁,性能好
  • 不用编写TCC中的三个阶段,实现简单

缺点:

  • 软状态持续时间不确定,时效性差
  • 没有锁,没有事务隔离,会有脏写

    4.5.四种模式对比

    我们从以下几个方面来对比四种实现:

  • 一致性:能否保证事务的一致性?强一致还是最终一致?

  • 隔离性:事务之间的隔离性如何?
  • 代码侵入:是否需要对业务代码改造?
  • 性能:有无性能损耗?
  • 场景:常见的业务场景

image.png

面试题:

什么是分布式事务?

事务:将一系列的操作,看做一个整体,要么全部执行,要么全部回滚。

分布式事务:在分布式架构中,实务操作,可能会横跨多个微服务,多个数据源,传统的事务注解无法解决分布式的事务。

什么是CAP理论?

C 一致性
A 可用性
P 分区容错性

CAP理论: 在分布式架构中,CAP不可能同时满足,只能3选2, P必须满足,所以我们的架构要么 是AP,要么是CP。

什么是BASE理论?

BASE:要保证核心服务可用(BA),允许出现数据不一致(soft)成为软状态,需要达成最终一致性(E)。

常见的分布式事务解决方案?

刚性事务(CP):
XA :一致性强, 代码侵入性低,但是性能差,可用性差。
柔性事务(AP)
AT : 最终一致性,代码侵入性低,性能适中。

TCC : try confirm cancel 性能好,代码侵入性高
用代码来实现事务的操作,不依赖于数据库,也就没有了全局锁的概念,性能好,但是代码侵入性高,比较麻烦。

SAGA : 原方法,回滚方法 性能好,无隔离性会出现脏写, 适用于长事务场景

       MQ+本地消息表  :性能非常好,一致性差,代码侵入性高。

简单介绍一下seata框架?

Seata解决分布式事务的框架

alibaba开源的事务框架,提供了多种事务模式:XA,AT,TCC,SAGA

如何使用seata解决分布式事务?

TC:事务协调器 TM:事务管理器 RM:资源管理器

TC端需要单独部署,(seata server服务端):管理全局事务

微服务继承Seata:
1.引入seata依赖

    2.配置seata服务端的连接

     3.在需要管理分布式事务的方法上,添加注解@GlobalTransactional

介绍一下seata AT模式的工作原理?

采用两阶段提交的方式:

第一阶段:开启全局事务,执行每一个分支事务
1.开启分支事务
2.解析要执行的sql语句,得到where,表,操作(update,insert)
3.根据where条件,查询操作前的数据(前镜像)
4.执行业务sql语句
5.根据where条件,查询操作后的数据(后镜像)
6.将前后镜像内容+xid+branchID插入到undolog日志中
7.(获取全局锁)上报分支事务处理状态

第二阶段:根据第一阶段的执行结果,决定提交或回滚
提交:直接根据xid(全局事务的id)和branchId(分支事务的id)删除undolog日志即可。
回滚:直接根据xid和branchId查询undolog日志,基于日志回滚数据。
首先判断数据库中的数据,是否和后镜像一致:
一致:根据前镜像的内容回滚数据
不一致:无法回滚,会根据配置的策略进行重试回滚

请详细说明一下AT模式具体是如何实现事务回滚的?

结合官网上的案例进行说明

seataAT模式是否有脏读问题,如何解决?

AT模式默认的隔离级别是 读未提交, 所以会出现脏读。

如何解决: select + from update
相当于将隔离级别改为读已提交。(基于全局锁)
//当它读一条数据的时候,需要首先获取全局锁然后才会执行,如果没有获取到全局锁,它会进行重试。

seataAT模式是否有脏写问题,如何解决?

AT模式,不会出现脏写问题。因为在提交修改数据的时候,都要先获取全局锁,通过全局锁来保证。

seataAT模式的优缺点?

优点:
代码侵入性低
性能好
保证事务要么全成功,要么全失败
缺点:
局限性:必须使用关系型数据库,项目必须是java项目,使用JDBC去操作数据库
脏读问题:
基于undolog日志存回滚数据,基于全局锁保证数据一致,在高并发时,性能会受到 影响。

项目中的实际业务场景?