@[toc]分布式事务,之前我们已经讲过很多次了,网上其实也有很多介绍分布式事务的文章,但是里面涉及的专业术语很多,大家一头雾水,所以有的朋友还是微信问我。那么今天,我就来另一篇文章,跟大家聊一聊这个话题。下面的内容主要围绕阿里的seata来给大家讲解一下。1、什么是反向补偿首先给大家解释一个名词。大家在看分布式事务相关资料的时候,经常会看到一个名词:反向补偿。什么是反向补偿?举个例子:假设我们现在有A、B、C三个微服务,现在在A服务中调用B和C服务,为了保证B和C同时成功或者同时失败,我们需要使用分布式事务。但是根据我们之前对本地事务的理解,B和C中的本地事务,当B服务中的事务完成提交后,现在C服务中的事务出现异常,需要回滚。如何回滚?我们此时说的回滚,其实并不是传统意义上的通过MySQLredolog回滚,而是通过一条updateSQL来恢复B服务中发生变化的数据。这就是我们所说的反向补偿!2.基本概念Seata中有3个核心概念:TC(TransactionCoordinator)——事务协调器:维护全局事务和分支事务的状态,驱动全局事务的提交或回滚。TM(TransactionManager)——事务管理器:定义全局事务的范围,启动全局事务,提交或回滚全局事务。RM(ResourceManager)-资源管理器:管理分支事务的资源(Resource),与TC对话以注册分支事务并报告分支事务的状态,并驱动分支事务的提交或回滚。其中,TC是单独部署的服务器,TM和RM是应用内嵌的客户端。我们看下图:这张图基本上把三个概念解释清楚了。其实不看这张图,我们大概可以猜到分布式事务的实现原理:首先要有一个全局事务协调器(TC),每个本地事务(RM)开始执行,或者在进程中在执行过程中,及时向全局事务协调器报告其状态。全局事务协调器知道每个分支事务当前的执行状态。当他(TC)发现所有本地交易都执行成功后,他会通知大家一起提交。;当他发现这个事务有人执行失败时,他会通知大家一起回滚(当然这个回滚不一定是真正的回滚,而是一种反向补偿)。那么事务什么时候开始和结束呢?即交易的边界在哪里?seata中的分布式事务都是通过@GlobalTransactional注解实现的。也就是说,这个注解应该加在哪里呢?添加这个注解的地方其实就是事务管理器TM。通过上面的介绍,大家应该明白了,用Seata实现分布式事务并没有想象中那么难,原理还是很简单的。Seata涉及四种不同的模式。接下来介绍的四种不同的模式,其实就是在讲本地事务失败时如何回滚?这就是我们后面要讲的四种不同的分布式事务模式。3、什么是两阶段提交我们先看下图:这张图涉及到三个概念:AP:不用多说,AP就是应用程序本身。RM:RM是资源管理器,即事务的参与者。在大多数情况下,它指的是数据库。一个分布式事务往往涉及多个RM。TM:TM是事务管理器,创建分布式事务,协调分布式事务中各个子事务的执行和状态。子事务是指对RM进行的具体操作。那么什么是两阶段(Two-PhaseCommit,简称2PC)提交呢?说白了,两阶段提交很简单。宋大哥给大家举个简单的例子来解释一下两阶段提交:比如下图:我们在Business中分别调用了Storage、Order、Account,这三个里面的操作必须同时成功或者失败同时,但是因为三个点在不同的服务中,所以我们只能让三个服务中的操作分别执行,三个服务中事务的执行是两个阶段中的第一阶段。第一阶段执行完后,不要急于提交,因为这三个服务有可能执行失败。这时候,三个服务都需要向一个事务协调器报告自己第一阶段的执行结果,事务协调器收到消息后,如果三个服务的第一阶段执行成功,那么三个事务就会此时通知单独提交。如果三个服务中的任何一个执行失败,都会分别通知三个事务回滚。这就是所谓的两阶段提交。总结一下:在两阶段提交中,事务分为参与者(如上图中的具体服务)和协调者。参与者将操作的成功或失败通知协调器,然后协调器将根据所有参与者的反馈信息来决定每个参与者。是提交操作还是中止操作,这里的参与者可以理解为RM,协调者可以理解为TM。但是Seata中的各种分布式事务模式基本都是在两阶段提交的基础上演化而来的,所以并不完全相同,需要小伙伴们注意。4、AT模式AT模式是一种全自动的事务回滚模式。总的来说,AT模式是两阶段提交协议的演变:第一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。第二阶段有两种情况:2.1提交是异步的,完成的很快。2.2回滚通过单阶段回滚日志进行反向补偿。大体逻辑如上。下面通过一个具体的案例来看一下AT模式是如何工作的:假设有一个业务表product,如下:现在我们要执行如下更新操作:updateproductsetname='GTS'wherename='TXC';步骤如下:第一阶段:解析SQL:获取SQL类型(UPDATE)、表(product)、条件(wherename='TXC')等相关信息。查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据(找到更新前的数据)。执行上面的更新SQL。后查询镜像:根据前镜像的结果,通过主键定位数据。插入回滚日志:将前后镜像数据和业务SQL相关信息组合成一条回滚日志记录,插入到UNDO_LOG表中。提交前先向TC注册分支:申请product表中主键值等于1的记录的全局锁。本地事务提交:业务数据的更新与前面步骤生成的UNDOLOG一起提交。将本地事务提交结果报告给TC。第二阶段:第二阶段分为两种情况,commit或者rollback。先看回滚步骤:首先,收到TC发来的分支回滚请求,启动本地事务,执行以下操作。通过XID和BranchID找到对应的UNDOLOG记录(这条记录存放的是数据修改前后对应的图片)。数据校验:将UNDOLOG中的后像与当前数据进行对比。如果有差异,则意味着数据已被当前全局事务以外的操作修改。这种情况需要根据配置策略进行处理。根据UNDOLOG中的前像和业务SQL信息生成并执行回滚语句:updateproductsetname='TXC'whereid=1;提交本地交易。并将本地事务的执行结果(即分支事务回滚的结果)报告给TC。再来看提交步骤:收到TC的分支提交请求后,将请求放入一个异步任务队列中,立即将提交成功的结果返回给TC。异步任务阶段的分支提交请求,会异步批量删除对应的UNDOLOG记录。大致就是这么一步,思路也比较清晰,就是当你要更新一条记录的时候,系统会生成一段JSON,记录更新前后的内容,存到undo中log表,以后会回滚,如果没有,则根据undolog中的记录更新数据(反向补偿)。如果以后没有回滚,undolog中的记录会被删除。整个过程中,开发者只需要额外创建一个undolog表,然后在需要处理全局事务的地方加上@GlobalTransactional注解即可。其他的提交和回滚都是全自动的,省事。所以如果你在项目中选择使用seata来处理分布式事务,那么使用AT模式的概率是相当高的。5、TCC模式TCC(Try-Confirm-Cancel)模式有点手动的感觉,也是两阶段的,但和AT不太一样,先来看看流程吧。官网上有TCC的流程图。我们来看一下:可以看到,TCC也分为两个阶段:第一阶段是prepare,主要是做资源检测和预留工作,比如银行转账。第一阶段,检查用户的钱是否足够。如果不够就直接抛出异常。够了就先冻起来。第二阶段是提交或回滚。这主要是等待每个分支事务的第一阶段被执行。执行完成后,各自向TC汇报自己的情况。TC统计后,发现各个分支交易没有异常,会通知大家一起提交;如果TC发现某个分支事务异常,会通知大家回滚。那么小伙伴们可能也发现了,在上面的过程中,涉及到了三个方法,prepare,commit和rollback。这三个方法完全是用户自定义的方法,都需要自己去实现,所以我一开始就说TCC是手动模式。与AT相比,大家发现TCC模式不依赖于底层数据库的事务支持。也就是说,即使你的底层数据库不支持事务也没关系。反正prepare、commit、rollback这三个方法都是开发者提供的。我们自己写的,可以把这三个方法对应的流程理顺。6、XA模式如果朋友们了解了MySQL数据库的XA事务,那么对seata中的XA模式也就一目了然了。XA规范是由X/Open组织定义的分布式事务处理(DTP,DistributedTransactionProcessing)标准。XA规范描述了全局事务管理器和本地资源管理器之间的接口。XA规范的目的是允许在同一个事务中访问多个资源(如数据库、应用服务器、消息队列等),从而使ACID属性可以跨应用程序保持有效。XA规范使用两阶段提交来保证所有资源同时提交或回滚任何特定事务。XA规范是在1990年代初提出的。目前,几乎所有的主流数据库都支持XA规范。XA事务的基础是两阶段提交协议。需要交易协调员来确保所有交易参与者都准备就绪(阶段1)。如果协调器收到所有参与者都准备就绪的消息,它会通知所有事务它们已准备好提交(阶段2)。MySQL在这个XA事务中扮演的是参与者的角色,而不是协调者(事务管理器)。MySQL的XA事务分为内部XA和外部XA。外部XA可以参与外部分布式事务,这需要应用层作为协调者的介入;内部XA事务用于同一实例下的跨引擎事务,Binlog作为协调器。比如存储引擎commit时,需要将提交的信息写入binarylog,这是一个分布式的内部XA事务,但是binarylog的参与者是MySQL本身。MySQL在XA事务中扮演参与者的角色,而不是协调者。也就是说,MySQL通过XA规范自然可以实现分布式事务,但是需要一些外部应用的支持。下面来看看Seata中XA模式的使用流程。先来看一张官方图:可以看到,这也是一个两阶段提交:第一阶段:业务SQL操作在XA分支进行。XA分支完成后,执行XAprepare,RM支持XA协议。保证持久性(即以后发生任何意外都不会造成无法回滚的情况)。第二阶段分为commit或rollback两种情况:branchcommit:执行XA分支的commit分支rollback:执行XA分支的回滚前两种模式的区别在于XA模式下的回滚是seriousRollback就是我们理解的传统意义上的回滚,不是反向补偿。7.Saga模式最后,我们来看看saga模式。这种模式很少用到,理解即可。saga模式是seata提供的长事务解决方案。但是在开发中应该避免长事务,因为它们效率低下,容易造成死锁。这种传奇模式有点像流程引擎。开发者首先自己画一个流程引擎,包括整个交易涉及的所有方法。每个方法有返回值的时候是正常的,返回的是异常的。正常就是继续往下走,如果出现异常,再执行一套流程,也就是我们需要提前准备两套方法,第一套是各种正常情况下的执行流程,第二套是异常发生后的执行流程,类似于如下:绿色的是正常流程,红色的是异常发生后的回滚流程。回滚也是一种反向补偿。8.总结完毕,我来给大家讲解一下分布式事务的4种模式吧~后面会一起练习几个案例!
