前言

   

  在上两篇博文(分布式事务与Seate框架(1)——分布式事务理论分布式事务与Seate框架(2)——Seata实践)中已经介绍并实践过Seata AT模式,这里一些例子与概念来自这两篇(特别是第一篇理论部分),如果有不懂的小伙伴可以先看看,这里主要是讲解Seata AT模式的实现原理。

  又好久没有记录博文了,这篇其实是很早之前就记录好了的,但是一直没时间去写出来,今天发出来算是再次对Seata分布式有个加深!

  


一、AT模式介绍

  同样地,还是得先复习下分布式事务的相关理论部分:AT模式是Seata最主推的分布式事务且基于XA演进而来的解决方案,主要有三个角色:TM、RM和TC,其中TM和RM作为Seata的客户端和业务集成,TC作为Seata服务器独立部署。TM向TC注册一个全局事务,并生成全局唯一的XID;在AT模式下,数据库资源被当做RM,访问RM时,Seata会对请求进行拦截;每个本地事务提交时,RM会向TC(Transaction Coordinator,事务协调器)注册一个分支事务。

  从三个角色TM、RM和TC的角度来记录具体的流程的话,可以总结如下:

  • TM向TC注册全局事务,并生成全局唯一XID;
  • RM向TC注册分支事务,并将其纳入到该XID对应的全局事务范围。
  • RM向TC汇报资源的准备状态
  • TC汇总所有事务参与者的执行状态,决定分布式事务全部回滚还是提交
  • TC通知所有的RM提交/回滚事务

 从具体的微服务角度总结,假设分别有三个:MicroService-1, MicroService-2, MicroService-3,流程图如下:

  

二、Seata AT模式的实现原理

1. AT模式的第一阶段实现

  解析业务SQL,更新业务数据,保存更新前后镜像到undo_log。在业务操作数据库流程中,Seata会基于数据源代理(0.9以后支持自动代理)对原执行SQL进行解析。之后通过本地事务的ACID特性,将这两步操作(保存业务数据前后镜像到undo_log, 更新业务数据)在本地事务中进行提交

    

比如(引用第二篇博文中的例子),我们对库存表库存进行减一,执行: 

UPDATE repo SET amount=amount-1 WHERE id=1

则第一阶段需要做的步骤:

(1)通过DataSourceProxy对业务SQL进行解析,得到SQL的表、WHEER条件等,之后通过查询修改之前的数据: 

SELECT id, name, amount, price FROM repo WHERE id=1;

这样就得到了修改之前的镜像,此时amount=100;

(2)执行更新业务:

即执行update语句,此时amount=99;

(3)查询修改之后的数据镜像,此时是通过第二步获取到的主键查询到修改之后的数据的

SELECT id, name, amount, price FROM repo WHERE id=1;

这样就有了修改之后的数据镜像了。

(4)插入回滚日志

有了修改前后的业务镜像数据之后,可以将业务镜像数据与业务相关的SQL信息构造成一条undo_log记录,插入undo_log表中:

    

  (如果要看到undo_log记录,则需要在debug模式下或者日志打印输出,否则事物回结束后会删除该记录)

5)向TC注册分支事务,并且申请关于id=1记录的全局锁

6)本地事务开始提交,将undo_log数据插入与更新业务数据一并提交(只有释放全局锁)

(7)将本地事务提交的结果告诉TC。

从AT模式的第一阶段来看,不同于XA模式的主要有以下几点(或者说优势):

  • 分支事务在第一阶段提交完成之后就马上释放本地事务锁定的资源。而XA模式一般是在锁定资源的持续到第二阶段的提交或者回滚后才释放资源。
  • AT模式第一阶段就释放了资源,这样就会让AT模式提升了分布式事务处理效率
  • 之所以在第一阶段就释放了资源,这是因为AT模式下,在第一阶段就记录了undo_log回滚日志,所以不怕第二阶段出现异常

2.AT模式第二阶段的原理分析

TC服务接收到事务分支的事务状态汇报之后,决定对全局事务进行提交或者回滚,这就是第二阶段。

2.1.事务提交

如果在第一阶段所有的分支事务已经提交,则TC决定全局事务提交,此时只需要清理UNDO_LOG日志即可,相比较XA模式,不需要TC触发所有分支事务的提交

具体的流程为:

(1) 分支事务收到TC的提交请求之后放入异步队列中,马上返回提交成功的结果;这里不需要同步返回的原因是:TC不需要知道分支事务的结果,因为仅仅只是一步删除UNDO_LOG记录的操作,即使不成功也不会结果造成影响,所以采用异步是有效的方式

(2) 从异步队列中执行分支提交请求,清理undo_log日志,这里并不需要分支事务的提交了,因为第一阶段中已经提交过了

理解起来就是:AT模式下的全局事务的提交只需要清理UNDO_LOG记录就行,不需要管分支(本地)事务的提交结果!

2.2.事务回滚

在第一阶段的分支事务中任何一个分支事务执行失败,都会进入全局事务回滚流程,显而易见全局事务的回滚主要是依赖UNDO_LOG中的记录进行补偿的

具体的流程如下:

接收到TC的回滚请求后,开启本地事务用来执行回滚操作

(1)本地事务分支开始进行对查找UNDO_LOG记录

通过XID+branch ID查到UNDO_LOG记录;

(2)数据校验(对比更新后镜像数据与当前数据)

拿到rollback_for中afterImage镜像数据与当前业务表中数据比较,不同的话,比如afterImage镜像数据拿出的amount理论上为99,但是实际上amount=98,则说明已经被当前全局事务外的某个操作做了修改(实际上由于全局锁的存在,并不会存在其他全局事务对业务数据进行更新),那么事务不进行回滚。

(3)第二步中对比结果是相等的话,就采用beforeImage和SQL的相关信息进行回滚,即:

UPDATE rep SET acoumt=100 WHERE id=1

(4)删除UNDO_LOG记录

(5)提交本地事务

(6)将本地事务的回滚执行结果报告给TC

3.AT模式下事务的隔离性保证

在AT模式下,多个全局事务操作同一张表时,它的事务隔离性保证是基于全局锁来实现的

(1)写隔离

  在第一阶段本地事务提交之前,必须确保拿到全局锁,如果拿不到全局锁则一直等待尝试,超出最大尝试次数则放弃全局锁的获取,并回滚释放本地锁(在本地事务开始之前就获到本地锁,这里的本地锁概念是数据库锁,比如对某行记录的行锁)

(2)读隔离

  数据库不设置事务隔离级别下发生三种情况(相当于复习下数据库隔离级别相关理论知识):

  脏读:脏读是指一个事务在处理数据的过程中,读取到另一个未提交事务的数据。

  不可重复读:不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。

  幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻读。也就是第一个事务读取的时候发现其他事务插入(或删除)的事务,就跟幻觉一样。

  幻读跟不可重复读都是读取了另一个事务提交的结果,而不可重复读的重点是修改,幻读的重点在于新增或者删除

  在数据库本地事务隔离级别为RR或者以上时,Seata AT事务模式的默认全局隔离级别是Read Uncommit,在这种隔离级别下,所有事务都可以看到其它未提交事物的执行结果产生脏读,这在最终一致性的事务模型是被允许的,并且大部分是分布式事务是接受脏读的

分布式事务与Seate框架(3)——Seata的AT模式实现原理的更多相关文章

  1. 分布式事务与Seate框架(2)——Seata实践

    前言 在上一篇博文(分布式事务与Seate框架(1)--分布式事务理论)中了解了足够的分布式事务的理论知识后,到了实践部分,在工作中虽然用到了Seata,但是自己却并没有完全实践过,所以自己私下花点时 ...

  2. 分布式事务与Seate框架(1)——分布式事务理论

    前言 虽然在实际工作中,由于公司与项目规模限制,实际上所谓的微服务分布式事务都不会涉及,更别提单独部署构建Seata集群.但是作为需要不断向前看的我,还是有必要记录下相关的分布式事务理论与Seate框 ...

  3. 分布式事务(七)之Seata简介

    在前面的文章中,我们介绍了分布式事务的概念以及一些解决方案.fenSeata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata将为用户提供了AT.TCC.SAGA和 ...

  4. Spring Cloud同步场景分布式事务怎样做?试试Seata

    一.概述 在微服务架构下,虽然我们会尽量避免分布式事务,但是只要业务复杂的情况下这是一个绕不开的问题,如何保证业务数据一致性呢?本文主要介绍同步场景下使用Seata的AT模式来解决一致性问题. Sea ...

  5. 分布式事务解决方案,中间件 Seata 的设计原理详解

    作者:张乘辉 前言 在微服务架构体系下,我们可以按照业务模块分层设计,单独部署,减轻了服务部署压力,也解耦了业务的耦合,避免了应用逐渐变成一个庞然怪物,从而可以轻松扩展,在某些服务出现故障时也不会影响 ...

  6. 开发者说 | 分布式事务中间件 Seata 的设计原理

    导读 微服务架构体系下,我们可以按照业务模块分层设计,单独部署,减轻了服务部署压力,也解耦了业务的耦合,避免了应用逐渐变成一个庞然怪物,从而可以轻松扩展,在某些服务出现故障时也不会影响其它服务的正常运 ...

  7. 微服务痛点-基于Dubbo + Seata的分布式事务(AT)模式

    前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...

  8. 微服务痛点-基于Dubbo + Seata的分布式事务(TCC模式)

    前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...

  9. 浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决

    浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决 ​ 在前几个月时,我们项目出现了分布式事务的问题,那么什么是分布式事务问题呢,简单的说,我们有俩服务A和B,它们对应 ...

随机推荐

  1. MySQL分区表最佳实践

    前言: 分区是一种表的设计模式,通俗地讲表分区是将一大表,根据条件分割成若干个小表.但是对于应用程序来讲,分区的表和没有分区的表是一样的.换句话来讲,分区对于应用是透明的,只是数据库对于数据的重新整理 ...

  2. C++将数值转换为string

    std::to_string string to_string (int val); string to_string (long val); string to_string (long long ...

  3. 3D教育类小图标_三维立体学习类icon图标素材

    3D教育类小图标_三维立体学习类icon图标素材

  4. wmctrl像xmonad那样方便地用快捷键来控制任务窗口的显示

    窗口左右互搏之wmctrl篇 分类: LINUX 2012-10-24 16:34:41   一直有个念头,就是能够像xmonad那样方便地用快捷键来控制任务窗口的显示,今天弄wmctrl,刚好有时间 ...

  5. fprintf函数

    描述 C 库函数 int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中. 声明 下面是 fprintf() 函数的 ...

  6. linux stat函数讲解 -(转自秋水Leo)

    stat函数讲解表头文件:    #include <sys/stat.h>             #include <unistd.h>定义函数:    int stat( ...

  7. Flex里的fx s mx

    笔记是从其他地方整合的,仅供参考 原来flex build 4有三个命名空间fx,mx,s,分别对应一下三个: •xmlns:fx="http://ns.adobe.com/mxml/200 ...

  8. IntelliJ IDEA配置tomcat 教程

    1.点击Run-Edit Configurations... 2.点击左侧"+",选择Tomcat Server--Local 3.在Tomcat Server -> Unn ...

  9. CSS的引入方式和复合选择器

    CSS的引入方式 样式表 优点 缺点 范围 行内样式表 书写方便 结构样式混写 控制一个标签 内部样式表 部分结构和样式相分离 没有彻底 控制一个页面 外部样式表 完全实现结构和样式分离 需要引入 控 ...

  10. 【Dubbo】SPI

    什么是SPI SPI是JDK内置的一种服务提供发现机制.目前市面上很多框架都用它来做服务的扩展发现.简单的说,它是一种动态替换发现的机制. jdk 实现方式 需要在 classpath 下创建一个目录 ...