什么场景下会产生分布式事务?
在支付异步回调的情况下,支付宝发送http请求给第三方平台,第三方平台需要更改支付状态以及订单状态,在此场景下,第三方平台更改本地支付数据库的支付状态后,通知订单服务更改订单的状态,在此程序后,如果代码出现异常,由于有声明式事务的存在,本地支付服务的数据库会进行回滚,变成未支付状态,但是订单服务的状态却无法回滚,订单服务的订单的状态变成已支付状态,这就出现了订单数据库和支付数据库数据不一致的情况,这便是分布式事务产生的场景之一。
什么是分布式事务?
分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
分布式事务的理论
1、cap理论
1)数据一致性(consistency)
如果系统对一个写操作返回成功,那么之后的读请求都必须读到这个新数据;如果返回失败,那么所有读操作都不能读到这个数据,对调用者而言数据具有强一致性(strong consistency) (又叫原子性 atomic、线性一致性 linearizable consistency)
一致性指"all nodes see the same data at the same time",即更新操作成功并返回客户端完成后,所有节点在统一时间的数据完全一致。分布式的一致性,对于一致性,可以分为从客户端和服务端两个不通的视角。 从客户端来看,一致性主要指的是多并发访问更新过的数据如何获取的问题。 从服务端来看,则是更新如何复制发布到整个系统,以保证数据的一致性。 一致性是因为有并发读写才有的问题,因此在理解一致性的问题时,一定要注意结合考虑并发读写的场景。从客户端角度,多进程并发访问时,更新过的数据在不同进程如何获取的不同策略,决定了不同的一致性。对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。如果能容忍后续的部分或者全部访问不到,则是弱一致性。如果经过一段时间后要求能访问到更新后的数据,则是最终一致性。
2)可用性(availability)
可用性指所有读写请求在一定时间内得到响应,可终止、不会一直等待。
可用性指的是"Reads and writes always succeed",即服务一直可用,而且是正常的响应时间。对于一个可用性的分布式系统,每一个非故障节点必须对每一个请求做出响应。也就是,该系统使用的任何算法必须最终终止。当同时要求分区容忍性时,这是一个很强的定义:即使是严重的网络错误,每个请求必须终止。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。可用性通常情况下可用性和分布式数据冗余,负载均衡等有着很大的关联。
3)分区容错性(partition-tolerance)
分区容错性是指在网络分区的情况下,被分隔的节点仍能正常对外服务。
分区容错性指“the system continues to operate despite arbitrary message loss or failure of part of the system”,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性 和可用性的服务。 分区容错性和扩展性紧密相关。在分布式应用中,可能因为一些分布式的原因导致系统无法正常运转。好的分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的整体。比如 现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,或者是机器之间有网络异常,将分布式系统分隔未独立的几个部分,各个部分还能维持分布式系统的运作,这样就具有好的分区容错性。
base理论的三个属性不能同时存在,只能认选其二。
2、Base理论
BASE理论是指,Basically Available(基本可用)、Soft-state( 软状态/柔性事务)、Eventual Consistency(最终一致性)。是基于CAP定理演化而来,是对CAP中一致性和可用性权衡的结果。核心思想:即使无法做到强一致性,但每个业务根据自身的特点,采用适当的方式来使系统达到最终一致性。
1、基本可用:指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用。但不等价于不可用。比如:搜索引擎0.5秒返回查询结果,但由于故障,2秒响应查询结果;网页访问过大时,部分用户提供降级服务,等。
2、软状态:软状态是指允许系统存在中间状态,并且该中间状态不会影响系统整体可用性。即允许系统在不同节点间副本同步的时候存在延时。
3、最终一致性:
系统中的所有数据副本经过一定时间后,最终能够达到一致的状态,不需要实时保证系统数据的强一致性。最终一致性是弱一致性的一种特殊情况。BASE理论面向的是大型高可用可扩展的分布式系统,通过牺牲强一致性来获得可用性。ACID是传统数据库常用的概念设计,追求强一致性模型。
ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
Base理论为柔性事务
3、柔性事务和刚性事务
柔性事务满足BASE理论(基本可用,最终一致)
刚性事务满足ACID理论
柔性事务分为
1.两阶段型
2.补偿型
3.异步确保型
4.最大努力通知型几种。 由于支付宝整个架构是SOA架构,因此传统单机环境下数据库的ACID事务满足了分布式环境下的业务需要,以上几种事务类似就是针对分布式环境下业务需要设定的。
分布式事务解决方案
1、常见的分布式事务解决方案
1)2pc两端提交协议
2)3pc三段提交协议
3) tcc
4)MQ(补偿和重试机制)
5)其他补偿方式(如:支付宝异步回调)
2、2pc(两端提交协议)
了解2pc之前必须了解下XA接口
1)什么是XA接口?(分布式事务协调者)
XA–eXtended Architecture 在事务中意为分布式事务 XA由协调者(coordinator,一般为transaction manager)和参与者(participants,一般在各个资源上有各自的resource manager)共同完成。在MySQL中,XA事务有两种。
2)2pc两端提交协议
所谓的两个阶段是指:第一阶段:准备阶段(投票阶段)和第二阶段:提交阶段(执行阶段)。
XA一般由两阶段完成,称为two-phase commit(2PC)。
阶段一为准备阶段,即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager汇报自己已经准备好。
阶段二为提交阶段。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。
如下图所示:
3)详细流程
第一阶段(投票阶段):
1、协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。
2、参与者节点执行询问发起为止的所有的事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)
3、各个参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则返回一个"同意"消息,如果参与者节点的事务操作实际执行失败,则他返回一个"终止"消息。
第二阶段(提交执行阶段):
当协调者节点从所有参与者节点获得的相应消息都为"同意"时:
1、协调者节点向所有参与者节点发出"正式提交"的请求。
2、参与者节点正式完成操作,并释放在整个事务期间占用的资源。
3、参与者节点向协调者节点发送"完成"消息。
4、协调者节点受到所有参与者节点反馈的"完成"消息后,完成事务。
如果其中任一参与者节点在第一阶段返回的响应消息为"中止",或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点响应消息时:
1、协调者节点向所有参与者节点发出"回滚操作"的请求。
2、参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源
3、参与者节点向协调者节点发送"回滚完成"的消息
4、协调者节点受到所有参与者节点反馈的"回滚完成"消息后,取消事务。
不管结果如何,第二阶段都会结束当前事务
4)2pc两端提交协议的缺点
1、执行过程中,所有的参与节点都时事务阻塞型的。当参与者节点占用公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
2、参与者发生故障。协调者需要给每个参与者额外制定超时机制,超时后,整个事务失败(没有容错机制)
3、协调者发生故障,参与者会一直阻塞下去。需要额外的备机进行容错。
4、二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
5)XA性能问题
XA的性能很低。一个数据库的事务和多个数据库间的XA事务性能对比可发现,性能差10倍左右。因此要尽量避免XA事务,例如可以将数据写入本地,用高性能的消息系统分发数据。或使用数据库复制等技术。
3、3PC(三段提交协议)
1)与2pc不同的是,三阶段提交有两个改动点。
1、引入超时机制,同时在协调者和参与者中都加入了超时机制。
2、在第一阶段和第二阶段中插入了一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。
2)3pc流程
1、CanCommit阶段
①事务询问
协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后等待参与者的响应
②响应反馈
参与者街道CanCommit请求后,正常情况下,如果其自身认为可以顺利提交事务,则返回yes响应, 并进入预备状态。否则反馈No
2、PreCommit阶段
协调者根据参与者的反应情况来决定是否可以进行事务的PreCommit操作,根据响应情况,有一下两种可能。假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
1、发送预提交请求
协调者向参与者发送PreCommit请求,并进入PrePared阶段。
2、事务预提交
参与者接收到了PreCommit请求后,会执行事务操作,并将undo和redo事务信息记录到事务日志中。
3、响应反馈
如果参与者成果的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
1、发送中断请求
协调者向所有的参与者发送abort请求。
2、中断事务
参与者收到来自协调者的abort请求后(或超时之后,仍未收到协调者的请求),执行事务的中断。
3、doCommit阶段
该阶段进行真正的事务提交,也可以分为一下两种情况。
3.1 执行提交事务
1、发送提交请求
协调者接收到参与者发送的ACK响应,那么他将从预提交状态进入提交状态。
2、事务提交
参与者接收到doCommit请求之后,执行正式的事务提交,并在完成事务提交后释放所有的事务资源。
3、响应反馈
事务提交完成之后,向协调者发送ack响应。
4、完成事务
协调者接收到所有参与者的ack响应之后,完成事务。
3.2 中断事务
协调者没有接收到参与者发送ack响应(可能是接受者发送的不是ack响应,也可能超时),那么就会执行中断事务。
1、发送中断请求
协调者向所有参与者发送abort请求。
2、事务回滚
参与者接受到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
3、反馈结果
参与者完成事务回滚后,向协调者发送ack消息
4、中断事务
协调者接收到参与者反馈的ack消息之后,执行事务的中断。
未完待续。。