0
点赞
收藏
分享

微信扫一扫

【快速全面掌握 WAMPServer】07.整明白 MySQL 和 MariaDB

343d85639154 2024-01-05 阅读 8

解决分布式事务的方案有很多,但实现起来都比较复杂,因此我们一般会使用开源的框架来解决分布式事务问题

在众多的开源分布式事务框架中,功能最完善、使用最多的就是阿里巴巴在2019年开源的Seata了。 

1. 初识Seata

Seata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。

Seata 可能给是目前已知最可靠的分布式事务解决方案。

官网地址:Seata | Seata,其中的文档、播客中提供了大量的使用说明、源码分析。

2. Seata的架构

其实分布式事务产生的一个重要原因,就是参与事务的多个分支事务互相无感知,不知道彼此的执行状态,因此解决分布式事务的思想非常简单:

  • 就是找一个统一的事务协调者,与多个分支事务通信,检测每个分支事务的执行状态,保证全局事务下的每一个分支事务同时成功或失败接口,大多数的分布式事务框架都是基于这个理论来实现的。 
  • Seata的开发者坚定认为:一个分布式事务是由若干个本地事务组成的。

Seata也不例外,在Seata的事务管理中有三个重要的角色:

作为一个分布式事务,它肯定也会有一个入口方法,在这个入口方法当中,一定会去调用多个其它的微服务,每调一个微服务,这个微服务不就是一个分支事务,因此将来调了多少个微服务,将来我们这个全局事务就包含多少个分支事务,因此在这个入口方法里就定义了全局事务的范围了,而TM就会去监控这个入口的方法或者说是代理这个入口方法,这样一来,TM就知道了全局事务里面总共有多少个分支事务,整个范围就确定下来了,当入口方法被执行时,TM会首先拦截当前的这个执行,会去向TC发起一个请求,去注册全局事务,接下来,就可以去执行这个入口的业务逻辑了,去调用每一个微服务,到了微服务里面每个分支事务就要开始执行了,此时RM就排上用场了。。。 

Seata的工作架构如图所示: 

其中,TC 为单独部署的 Server 服务端,TC服务则是事务协调中心,是一个独立的微服务,是一个独立的JVM进程,里面不包含任何业务代码,需要单独部署;TM RM 为嵌入到应用中的 Client 客户端,引入到参与事务的微服务依赖中即可,将来TMRM就会协助微服务,实现本地分支事务与TC之间交互,实现事务的提交或回滚。 

在 Seata 中,一个分布式事务的生命周期如下: 

微服务集成Seata

  • 参与分布式事务的每一个微服务都需要集成Seata,为了方便各个微服务集成Seata,我们需要把Seata配置共享到Nacos,因此模块不仅仅要引入Seata依赖,还要引入Nacos依赖。

<!--统一配置管理-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <!--读取bootstrap文件-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
  </dependency>
  <!--seata-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  </dependency>
  <!--sentinel-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  </dependency>
  • 由于TC服务将来有可能搞集群,所以将来微服务肯定是要去注册中心获取TC服务地址。 

将原来的@Transactional注解改为Seata提供的@GlobalTransactional注解@GlobalTransactional注解就是在标记事务的起点,将来TM就会基于这个方法判断全局事务范围,初始化全局事务。 

Seata是如何解决分布式事务的? 

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

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

3. XA模式(性能最差):强一致性的事务

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

XA是规范,目前主流数据库都实现了这种规范,实现的原理都是基于两阶段提交。  

  • 两阶段提交协议(2PC)和三阶段提交协议(3PC)是一种用于实现强一致性的分布式事务协议。

两阶段提交 - Two-phaseCommit - 2PC - 两阶段提交协议

Seata的XA模型

  • Seata对原始的XA模式做了简单的封装和改造(大差不差),以适应自己的事务模型,基本架构如图:

XA模式的优缺点? 

  • 由两阶段提交可能会出现的各个问题衍生出三阶段提交

三阶段提交 - 3PC - 三阶段提交协议

由于三阶段提交协议3PC非常难实现,目前市面主流的分布式事务解决方案都是2PC协议。 

Seata实现XA模式

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

4. AT模式

  • AT模式同样也是分阶段提交的事务模型,不过却弥补了XA模型中资源锁定周期过长的缺陷。 
  • AT模式也是一种无侵入的分布式事务解决方案,阿里的Seata框架,实现了该模式。 

在AT模式下,用户只需关注自己的"业务SQL",用户的"业务SQL"作为一阶段,Seata框架会自动生成事务的二阶段提交和回滚操作。

一阶段:

  • 在一阶段,Seata(RM)会拦截"业务SQL",首先解析SQL语义,找到"业务SQL"要更新的业务数据,在业务数据被更新前,将其保存成"before image"原快照,然后执行"业务SQL"更新业务数据,在业务数据更新完成之后,再将其保存成"after image"新快照  =>  记录undo_log数据快照,最后生成行锁,以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性;
  • 各个本地事务申请全局锁,申请成功则提交本地事务  =>  提交异步化,非常快速的完成;

AT模式的脏写问题 

一阶段本地事务提交前,需要确保先拿到全局锁:

  • 拿不到全局锁,不能提交本地事务 => 这是为了解决在多线程并发访问AT模式的分布式事务时,有可能出现的脏写问题,先拿到全局锁,避免同一时刻有另外一个事务来操作当前数据

全局锁的作用?

  • 基于锁的原理,对于同一个行数据,一个时刻只能有一个分布式事务执行,提供互斥的作用

为什么全局锁不在本地事务开始时直接加锁?

  • 为了提高性能,减少全局锁对数据库的占用时间。 

全局锁带来的性能问题?

  • 因为有全局锁的存在,所有的分布式事务只能串行执行,不能并发的操作数据库当中的数据。

二阶段:

第二阶段根据阶段一的结果来判断 

二阶段提交:大多数情况下全局事务都是执行成功 

  • 如果每一个分支事务都成功,则二阶段提交  =>  二阶段如果是提交的话,因为"业务SQL"在一阶段已经提交至数据库,事务已经结束,所以Seata框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。 

二阶段回滚:回滚通过一阶段的回滚日志进行反向补偿 

  • 如果有任意分支事务失败,则二阶段回滚 => 二阶段如果是回滚的话,Seata就需要回滚一阶段已经执行的"业务SQL",还原业务数据,回滚方式便是用"before image"还原业务数据,根据快照恢复到更新前数据,然后删除快照;
  • 但在还原前要首先要数据校验 - 校验脏写,对比"数据库当前业务数据"和"after image",如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写(说明数据被当前全局之外的动作做了修改)=>  出现丢失更新,出现脏写就需要转人工处理。 
  • 分支事务提交后,遇到异常回滚时,其它的本地事务修改了数据,此时Seata会默认抛出异常

事务1在等事务2释放数据库锁,事务二在等事务一释放全局锁,它两互相等待,产生了死锁:

本地事务为什么在一阶段提交? 

AT模式的隔离级别?

AT模式的优缺点: 

5. AT模式与XA模式的区别? 

6. TCC模式

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

TCC模式,全称Try-Confirm-Cancel,通过名称也能看出来其流程主要有三个步骤 - 两个阶段,TCC实际上是服务化的两阶段提交协议:

  • 事务发起方在一阶段执行Try方法,在二阶段提交执行Confirm方法,二阶段回滚执行Cacel方法。    

TCC三个方法描述: 

TCC执行流程: 

分支事务成功的情况:

分支事务失败的情况 :

TM事务管理器  

TCC模式  VS  AT模式

TCC 的实践经验 

蚂蚁金服TCC实践,总结以下注意事项:

➢ 业务模型分2阶段设计
➢ 并发控制
➢ 允许空回滚
➢ 防悬挂控制
➢ 幂等控制

1. TCC设计 - 业务阶段分2阶段设计

2. TCC 设计 - 允许空回滚: 

3. TCC 设计 - 防悬挂控制(拒绝业务悬挂): 

4. TCC 设计 - 幂等控制: 

声明TCC接口

  • TCC的Try、Confirm、Cancel方法都需要在接口中基于注解来声明:@LocalTCC、@TwoPhaseBusinessAction。

7. Saga模式

Saga模式是Seata提供的长事务解决方案,由蚂蚁金服主要贡献,也分为两个阶段:

如图:T1~T3都是正向的业务流程,都对应着一个冲正逆向操作C1~C3
  • 一阶段:直接提交本地事务
  • 二阶段:成功则什么都不做;失败则通过编写反向补偿业务来执行逆向回滚操作 

Saga和TCC分布式事务的区别?

  • Sage和TCC有些类似,都是补偿型事务,与TCC不同的是,Saga不需要Try,而是直接进行Confirm、Cancel操作。

Saga模式的优缺点:

8. 四种模式对比

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

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

  • 隔离性:事务之间的隔离性如何?

  • 代码侵入:是否需要对业务代码改造?

  • 性能:有无性能损耗?

  • 场景:常见的业务场景

9. Seata的高可用异地容灾架构模型 

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

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

但集群并不能确保100%安全,万一集群所在机房故障怎么办?

  • 所以如果要求较高,一般都会做异地多机房容灾,比如一个TC集群在上海,另一个TC集群在杭州。
举报

相关推荐

0 条评论