虽然在实际工作中,由于公司与项目规模限制,实际上所谓的微服务分布式事务都不会涉及,更别提单独部署构建Seata集群。但是作为需要不断向前看的我,还是有必要记录下相关的分布式事务理论与Seate框架,甚至Seate框架的源码分析,先从分布式事务理论开始吧,下一部分将介绍对Seata的应用,最后再对核心的源码进行跟踪分析并学习!
主要参考《Spring Cloud Alibaba 微服务原理与实战》中分布式事务章节,有需要资源的朋友可以评论我!(文中的截图均来自此,由于相对好理解所以没有自己画图)
在介绍相应的分布式事务理论模式前,先放出如下图,对分布式事务常见的解决方案作对比:
最主要的区别就是对一致性的要求:是强一致性还是最终一致性,根据这个核心展开来介绍相关的几种理论介绍
X/Open DTP是由X/Open组织提出的一套分布式事务的标准,这个标准提出使用了2PC(Two-Phase-Commit)来保证分布式事务的完整性。
X/Open DTP包含三种角色:
在分布式环境下,RM代表数据库,可能有多个,所以TM需要管理多个数据库的事务,也就是说TM就是一个全局事务管理器。步骤如下:
需要注意的是:TM与多个RM之间的事务控制,是基于XA协议来完成的,XA协议是X/Open提出分布式事务处理规范。
根据上图可知,2PC具体步骤:
但也有如下的缺点:
三阶段提交协议是两阶段的改良版,利用了超时机制解决了同步阻塞的问题,步骤如下:
第一阶段:CanCommit(询问阶段):事务协调者向参与者发送事务执行请求,询问是否可以完成指令,参与者只需要回答是或者不是,会有超时机制;
第二阶段:PreComiit(准备阶段):事务协调者会根据参与者的反馈结果决定是否继续执行,如果在第一个阶段CanCommit都收到了请求的话,就开始执行写redo和undo日志,并且返回ACK给协调者,这里即是二阶段提交的第一阶段。
第三阶段:DoCommit(提交或回滚阶段):如果在第二阶段PreCommit提交成功以后,那么事务协调者会向所有的参与者发起事务提交指令,如果其中某个参与者返回失败,则执行终止指令回滚事务。
相比较二阶段提交协议,三阶段提交协议有以下不同:
1)增加了CanCommit阶段:可以尽早发现参与者无法执行的情况,及时中断;
2)增加了超时机制:参与者与事务协调者都引入了超时机制,一旦超时,事务协调者和参与者会继续提交事务,并且任务处于成功状态(因为在这种情况下事务默认为成功的可能性比较大),事实上,第三阶段提交协议下仍然可能出现不一致的情况(但是概率很小)
CAP定理,又称布鲁尔定理,简单来说就是指在分布式系统中不可能同时满足一致性(C:Consistency)、可用性(A:Availability)、分区容错性(P: Partition Tolerance)
C:数据在多个副本中保持一致,比如前面说的分布式数据一致性问题
A:系统对外提供的服务必须一直处于可用状态;
P:在分布式中遇到任何网络分区故障,系统仍然能够正常对外提供服务。
CAP定理证明,在分布式系统中,要么满足CP、要么满足AP。不可能实现CAP或者CA,原因是网络通信并不是绝对可靠的。而在分布式系统中即便出现网络故障也需要保证系统仍然能够正常对外提供服务,Partition Tolerance是必然存在的,所以P是一定会有的,只有C与A不能同时兼得。
AP:相当于放弃了强一致性,实现最终的一致性,这是很多解决分布式数据一致性的最终选择。
CP:放弃了高可用性,实现强一致性,之前的2PC与3PC都采用这种方案,可能会导致用户完成某个操作会等待较长时间。
BASE理论是由于CAP中一致性和可用性不可兼得而衍生出来的一种新思想,BASE理论的核心思想通过牺牲数据的强一致性获得高可用性。
Basically Available(基本可用):分布式系统出现故障时,允许损失一部分功能的可用性,保证核心功能的可用。
Soft State(软状态):允许系统中的数据存在中间状态,这个状态不影响系统的可用性,也就是系统中不同节点的数据副本之间的同步存在延时
Eventually Consistent(最终一致性):中间状态的数据经过一段时间之后,会达到最终的数据一致性。
也就是BASE理论并没有要求数据的强一致性,而是允许在一段时间是不一致的,但最终数据会在某个时间点实现一致。比如:用户发起订单支付,不需要同步等待支付的执行结果,系统会返回一个支付处理中的状态到用户界面,最后可以通过订单详情查看到支付处理结果,而对于系统来说,当第三方支付处理成功之后,再更新订单的状态即可。
TCC 是一种比较成熟的分布式数据一致性解决方案,实际上是把一个完整业务拆分为三个步骤:
Try:主要是数据的校验或者资源的预留;
Confirm:确认真正执行的任务,只操作Try阶段预留的资源;
Cancel:取消执行,释放Try阶段预留的资源。
其实TCC是2PC的思想,第一阶段通过Try进行准备工作,第二阶段Confirm/Cancel表示Try阶段操作的确认和回滚。
比如:用户通过账户余额购买一个理财产品,涉及两个事件,对应两个不同的微服务中的方法:账户服务中,对用户账户余额进行扣款;理财产品中,对指定产品可申购金额进行扣减。则需要TCC补偿方案控制:
而需要注意的是,微服务框架宕机或者网络异常导致没法完成Cancel/Confirm请求,TCC事务框架会记录一些分布式事务的操作日志,保存分布式事务运行的各个阶段和状态,之后TCC事务协调器根据日志进行重试,达到数据的最终一致性。
基于可靠消息的一致性是互联网公司比较常用的分布式数据一致性解决方案,比如支付服务于账户服务之间的流程需要MQ:
但是支付服务本地事务到MQ发送消息存在非原子操作问题,如果先执行本地事务,再发送消息到MQ,MQ可能出现超时情况,导致本地事务可能回滚,从而导致数据不一致
如果先发送消息,再执行数据库事务,在这种情况下可能会出现消息发送成功但是本地事务更新失败的情况下,仍然存在数据不一致的问题
针对MQ与服务之间的数据不一致的情况,我们可以采用MQ的事务消息模型,比如RocketMQ为例:
由上我们可知:
所谓的最大努力通知就是在客户端没有返回消息确认时,支付宝会不断地进行重试,知道收到一个消息确认或者达到最大重试次数。
可以参考支付宝支付的例子,如果商户不返回SUCCESS标识,每隔1min、5min…会不断通知商户支付结果,达到最大次数以后就不通知,将会同时提交查询结果,定时任务出发查询。
Seata是致力于微服务架构下提高性能和简易使用的分布式事务,它提供了AT、TCC、Saga和XA事务模式。
AT模式是Seata最主推的分布式事务且基于XA演进而来的解决方案,主要有三个角色:TM、RM和TC,其中TM和RM作为Seata的客户端和业务集成:
在AT模式下,数据库资源被当做RM,访问RM时,Seata会对请求进行拦截;
每个本地事务提交时,RM会向TC(Transaction Coordinator,事务协调器)注册一个
具体步骤如下:
1) TM向TC注册全局事务,并生成全局唯一XID;
2) RM向TC注册分支事务,并将其纳入到该XID对应的全局事务范围。
3) RM向TC汇报资源的准备状态
4) TC汇总所有事务参与者的执行状态,决定分布式事务全部回滚还是提交
5) TC通知所有的RM提交/回滚事务
AT模式和XA类似,也是一个2PC模型,但实际上做了很多优化,后面再介绍
Saga模式又称之为长事务解决方案,核心思想是:把一个业务流程中的长事务拆分成多个本地短事务,业务流程中每个参与者事务执行失败,则通过补偿机制前面已经成功的参与者。
按照Saga的工作模式,一般有两种方式:
1) T1, T2,T3,T4…,Ti,表示所有事务正常运行
2) T1, T2,T3,T4…,Tj, Cj,…,C2,C1:表示执行到Tj事务时出现异常,通过补充操作撤销之前的所有成功的sub-transaction。
另外,提供两种补偿模式:一是向后补偿,即第二种方式,任一子事务执行失败,则把之前的子事务结果逐一撤销。另一种就是向前恢复,都可以出现失败情况,在最坏的情况下只能进行人工干预处理。
(1)Saga优劣势
优势:
劣势:
不提供原子性与隔离性支持,合理性影响性比较大,比如用户赠送了一张优惠券,但是已经把优惠券用完了,无法对这个sub-transaction进行补偿。
Saga的整个过程会涉及一个两种协调模式:
1)事件/编排式
把Saga的决策和执行顺序逻辑分布在Saga的每一个参与者中,它们通过交换事件的方法进行沟通。
即第一个服务执行完本地事务之后,发送一个事件,这个事件会被一个或多个服务监听,监听到该事件的服务本地事务并发布新的事件,此后一直延续这种事件触发模式,直到该业务流程中最后一个服务的本地事务执行结束,才意味着整个分布式长事务也执行结束。
具体步骤如下,可以看出都是由事件发布来驱动事务执行
上述某个步骤如果执行失败,都会发送一个失败事件,每个服务都会监听失败的情况根据实际需要逐一回滚。
2)命令/协同式
把Saga的决策和执行顺序逻辑集中在一个Saga控制类中,它以命令/回复的方式与每项服务进行通信,告诉它们应该执行哪些操作。
命令/协调式的实现步骤如下:
值得注意的是,订单Saga协调器必须需要提前知道“创建订单”的所有流程,并且在某个环节执行失败,都需要每个参与者发送命令撤销之前的事务操作。
在了解完分布式事务理论部分结束后,接下来记录的就是Seata的实践部分,将会抽时间再写一篇博文,加深印象