首页 > 其他分享 >分布式事务的Seata AT模式原理

分布式事务的Seata AT模式原理

时间:2024-08-22 16:49:42浏览次数:8  
标签:回滚 Seata seata 事务 代理 提交 执行 分布式

Seata

官网地址:https://seata.apache.org/zh-cn/

AT模式

优点:无侵入式代码,只需要添加注解,底层采用Seata代理的数据源DataSourceProxy
缺点:依赖于数据库,目前只适用于postgresql、oracle、mysql、polardb-x、sqlserver、达梦数据库等数据库,比如业务逻辑中含有redis、es等操作需要控制事务,无法实现,可以使用TCC模式

客户端

<dependency>
	<groupId>io.seata</groupId>
	<artifactId>seata-spring-boot-starter</artifactId>
	<version>2.0.0</version>
</dependency>

首先从源码查起,自动配置首先可以看到这两个,是比较核心的,SeataAutoConfiguration负责扫描@GlobalTransactional注解以及@GlobalLock注解,生成代理类,SeataDataSourceAutoConfiguration主要生成DataSourceProxy代理类以及PreparedStatementProxy或StatementProxy都使用的是Seata的代理类
io.seata.spring.boot.autoconfigure.SeataAutoConfiguration,
io.seata.spring.boot.autoconfigure.SeataDataSourceAutoConfiguration,
GlobalTransactionScanner类会首先扫描带@GlobalTransactional注解的类,其次在bean注入完成后 注册TM以及RM,主要逻辑还是生成GlobalTransactional注解的代理方法

首先会在postProcessAfterInitialization初始化之后wrapIfNecessary也就是包装一层,这个方法所有bean都会执行一遍,为了过滤会进行一次初步筛选

会对包名判断以及去除Configuration类,然后会判断是否存在GlobalTransactional或GlobalLock注解,代理最重要的MethodInterceptor,所有的处理逻辑都将会在这个拦截器执行,只不过这里大概封装了三四层,因为TCC需要走不同的逻辑,

这里以官网例子举例,当调用purchase方法时会执行GlobalTransactionalInterceptorHandler#doInvoke方法

然后执行TransactionalTemplate#execute,首先判断事务的传播机制,默认为REQUIRED,会创建新的事务,以下为代理方法的核心逻辑,创建分布式事务,提交事务以及回滚事务

beginTransaction表示开启事务,第一次与服务端交互,拿到全局锁,返回一个xid,
第二步business.execute表示执行真正执行purchase方法,但是执行的过程中务必会有数据库的操作,所以先看DataSource的代理逻辑

DataSource方法代理

同上,继承了AbstractAutoProxyCreator,如果判断bean类型为DataSource,生成代理类之后放入DataSourceProxyHolder,类型为<origin, proxy>的缓存当中,

当调用DataSource方法的时候,再从DataSourceProxyHolder取出来,这样实际调用的就是代理类的方法,
其中DataSourceProxy中Connection以及Statement均用的seata的代理类
这里以更新为例,扣减库存数量,库存-2

最终执行executeUpdate方法,在获取Connection的时候获取到的是代理之后的ConnectionProxy

一阶段

ExecuteTemplate#execute方法会判断执行sql类型,以UpdateExecutor为例,下面再执行sql的时候添加了额外的逻辑,这也是AT模式可以回滚的关键,

statementCallback.execute会在执行业务sql的前后添加镜像,首先看beforeImage,还是以update为例,beforeImage记录更新之前的数据,在更新之前会先查询表结构,获得当前事务表的所有列及索引,
但是这里查询结构不是通过information_schema.tables,以stock_tbl 为例执行的sql为SELECT * FROM stock_tbl LIMIT 1,再通过ResultSetMetaData以及DatabaseMetaData可以获得当前表的所有列及索引,当然这不是每次执行都必须的,只有第一次会查询limit 1语句,后续会放入本地缓存caffeine中,然后根据where条件以及索引来生成查询语句,执行查询得到记录生成beforeImage
SELECT id, count FROM stock_tbl WHERE commodity_code = ? FOR UPDATE
然后执行业务代码,执行完成之后生成afterImage,通过beforeImage和afterImage生成undolog

然后执行代理类的事务提交,在提交的时候也大有来头,首先向TM注入分支,

然后会插入undo_log,这个Insert会加入当前事务,可以通过 select * from performance_schema.data_locks 查看当前锁

如果在commit当前本地事务的时候发生异常,会上报给TM,会立马进行回滚本地事务,

二阶段—提交

当所有一阶段执行完成之后,由TM开始提交全局事务,TransactionalTemplate#execute

然后TC会向RM发起分支提交请求,在AbstractNettyRemoting#processMessage收到消息之后进行分支的提交,在异步任务提交的时候,AsyncWorker#dealWithGroupedContexts 同时会删除undo_log日志,

至此,提交完事务,整个流程就结束了

二阶段-回滚

如果执行过程中发生了满足条件的异常,TM会向TC发送异常回滚的请求,收到TC回滚请求的RM通过XID与branchId查找undoLog
DataSourceManager#branchRollback

会拿到后镜像与当前数据进行做对比,如果一致,说明被当前事务之外的操作做了处理,如果不一致生成回滚sql,并且删除当前undolog,提交事务并将结果上报给TC

标签:回滚,Seata,seata,事务,代理,提交,执行,分布式
From: https://www.cnblogs.com/LiuFqiang/p/18372039

相关文章

  • Java学习笔记3事务的四大特性
      ACID,分别是原子性、一致性、隔离性、持久性。①原子性(Atomiticy)原子性指事务包含的所有操作要么全部执行成功,要么全部失败回滚,因此事务的操作如果成功就必须要全部应用到数据库,如果操作失败则不能对数据库有任何影响。②一致性(Consistency)一致性是指事务必须使数据库从......
  • MYSQL长事务排查
    查看造成等待的事务执行SQLSELECTtmp.waiting_thread'等待线程ID',tmp.waiting_trx_id'等待事务ID',tmp.wating_trx_state等待事务状态,tmp.waiting_query等待语句,case when(tmp.waiting_time-28800)>0then(tmp.waiting_time-28800) elsetmp......
  • 深入探索分布式任务调度框架:MySQL实现高效锁机制
    本文主要介绍项目中怎么使用MySQL实现分布式锁的背景假如我们现在要做一个高性能、可扩展的分布式任务调度框架,要怎么设计呢?下面是我之前自己设计的一个架构图。为了方便后续的分布式锁的设计,我们大致描述下各个角色都做了哪些事情(这不是本篇文章的重点)scheduler-c......
  • Linux下的分布式锁
    一:什么是分布式锁1、定义        在分布式系统中,一个应用部署在多台机器当中,在某些场景下,为了保证数据一致性,要求在同一时刻,同一任务只在一个节点上运行,即保证某个行为在同一时刻只能被一个线程执行;在单机单进程多线程环境,通过锁很容易做到,比如mutex、spinlock、......
  • 分布式事务解决方案
    背景分布式事务,后端开发中比较常见啦。因为在面试的时候,总是有interviewers让我给他普及一下分布式事务,虽然我会的也不多呀但是还是浅浅说一说;今天心血来潮,好好地总结一下分布式事务,希望每一位后端工程师都能彻底理解分布式事务。什么是分布式事务?答:既然是分布式,首先必然是分......
  • 数据库MySQL之事务、索引
    目录1.概述2.事务3.索引3.1索引结构3.2操作语法1.概述场景:假如我们需要解散教学部,那么该部门下的所有员工都需要删除。如果教学部成功删除了,但员工出于某些原因(比如SQL语句写错了等)并没有删除,此时就会出现数据不一致的问题。这时我们可以通过数据库中的事务来解决。......
  • 分布式系列之ID生成器
    背景在分布式系统中,当数据库数据量达到一定量级后,需要进行数据拆分、分库分表操作,传统使用方式的数据库自有的自增特性产生的主键ID已不能满足拆分的需求,它只能保证在单个表中唯一,所以需要一个在分布式环境下都能使用的全局唯一ID。应用场景用户ID、图片ID等各种业务场景分库......
  • 分布式资源管理和调度架构
    概述不管是计算任务还是数据存储都会涉及资源分配,资源包括但不限于硬件资源如CPU、内存、硬盘、网口。在单机环境中,资源管理相对简单;分布式环境中,资源分布相对分散,如何协调资源应对计算任务和数据存储就是亟待解决的问题。资源管理和调度是将计算任务分配到资源的过程,为了处理并......
  • Java中的分布式缓存解决方案:Redis与Ehcache
    在现代企业级应用中,性能和高可用性是两个重要的考量因素。分布式缓存作为解决性能瓶颈的有效手段,能有效减轻数据库的压力并提高系统的响应速度。本文将深入探讨Java中两种常用的分布式缓存解决方案:Redis与Ehcache,并通过代码示例演示它们在实际应用中的使用。分布式缓存的基本......
  • jmeter做分布式压测时的注意事项
    分布式压测注意事项:1、保持Contorller和Agent机器的JDK、jmeter以及插件等配置版本一致;2、如果测试数据有用到CSV或者其他方式进行参数化,需要将data?pools在每台Agent上复制一份,且读取路径必须保持一致;否则会出现取不到数据的情况,造成压测失败;3、确保Contorller和Agent机器在同一......