前言

   

  在上两篇博文(分布式事务与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. 还不懂 redis 持久化?看看这个

    Redis 是一个内存数据库,为了保证数据不丢失,必须把数据保存到磁盘,这就叫做持久化. Redis 有两种持久化方法: RDB 方式以及 AOF 方式 RDB 持久化 前言 RDB持久化把内存中的数 ...

  2. Java安全之Fastjson反序列化漏洞分析

    Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...

  3. Think on 小黄衫

    忙忙碌碌的大三下,抽空写一篇这样的感想,感觉也是蛮不错的. 首先,还是要非常感谢课程组的认可与鼓励,能够得到这样的一件"小黄衫",确实是一段非常宝贵的体验. 博客作业感想 三次博客 ...

  4. FROM-4-TO-6!!!!!!!!! - OO第二单元总结

    电梯的这三次作业是对并发编程的一次管窥,感觉收获还是蛮多的.在设计上有好的地方也有不足,这里简单回顾总结一下 设计总述 电梯这个问题由于比较贴近真实生活,所以需求还是很好理解的.总的来说,我的数据处理 ...

  5. Go快速入门(二)

    提示:本系列文章适合有其他语音基础并对Go有持续冲动的读者 一.package介绍 ​ Go语言的代码是通过package来组织的,package的概念和你知道的其它语言 里的libraries或者m ...

  6. docker容器与容器的关联

    可以通过docker run -it -d --link 容器id 镜像id   方式关联 例如,将springboot项目容器与mysql容器相互关联,让springboot容器可以访问到mysql ...

  7. rpm -ql BackupPC |grep etc

    # rpm -ql BackupPC |grep etc/etc/BackupPC/etc/BackupPC/config.pl/etc/BackupPC/hosts/etc/httpd/conf.d ...

  8. MyBatis 模糊查询的 4 种实现方式

    引言 MyBatis 有 4 种方式可以实现模糊查询. 员工信息表 ( tb_employee ) 如下: id name sex email birthday address 001 张一凡 男 z ...

  9. python程序打包成exe(使用pyinstaller)

    pyinstaller下载地址:https://github.com/pyinstaller/pyinstaller/ (这个文件能够自动安装依赖项,其他版本的貌似还要自己安装依赖项) 下载之后解压到 ...

  10. 【C++】禁用/启用笔记本键盘工具(含源码)

    目录 前言 简单介绍注册表 (1)根键 (2)子键 (3)键值项 操作注册表的几个API函数 (1)打开一个键 (2)查询某一个键值 (3)设置一个键值 (4)新建指定键 (5)删除注册表指定键下的值 ...