之前梳理了什么是事务;https://blog.youkuaiyun.com/u010530712/article/details/84949864
现在来梳理下,分布式事务的解决方案
首先对于分布式事务,一般来说要基于CAP(Consistency :一致性,Availability :可用性,Partition Tolerance:分区容错性)中的两个,要么CP(一致性 + 分区容忍性),要么AP (可用性 + 分区容忍性),理论上是不可能选择CA(一致性+可用性)。
然而,CAP里的Consistency 是强一致性(忽略延迟),但是在实际的应用中,几乎没有系统能完全做到CP(因为总会有那么几毫秒的数据复制延迟在),因此我们追求的是“最终一致性”,即系统中的数据允许经过一定的时间后,最终达到一致的状态,这里的一定时间根据不同的业务需要,时间长短也不同。对于支付类的业务,用户关注,要求秒级别甚至毫秒级别达到一致性,而对于一些发帖子之类的论坛业务,数据复制延迟个10分钟,对于看的用户来说是无感知的。
说完了主要的一致性问题。下面正式介绍几种分布式事务解决方案
2PC(two-phase-commit,二阶段提交)方案
该方案将事务的提交扶持分为两个阶段:准备阶段和提交阶段,事务的发起方叫“协调者”,事务的执行方叫“参与者”
阶段 1:准备阶段
准备阶段有如下三个步骤:
-
协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待所有参与者答复。
-
各参与者执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)。
-
如参与者执行成功,给协调者反馈 yes,即可以提交;如执行失败,给协调者反馈 no,即不可提交。
阶段 2:提交阶段
如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(rollback)消息;否则,发送提交(commit)消息。
参与者根据协调者的指令执行提交或者回滚操作,注意!是最后释放所有事务处理过程中使用的锁资源(也就是从执行事务开始到协调者给予commit/rollback指令期间,一直是阻塞状态)。
2PC总结
-
性能问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈。
-
可靠性问题:如果协调者存在单点故障问题,如果协调者出现故障,参与者将一直处于锁定状态。
-
数据一致性问题:在阶段 2 中,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。
3PC(three-phase-commit,三阶段提交)方案
三阶段提交相较二阶段提交,引入了超时机制(无论协调者还是参与者,在向对方发送请求后,若长时间未收到回应则做出相应处理)
三阶段将之前二阶段的准备阶段拆成2个阶段(cancommit:确认是否能执行,precommit:执行事务不提交)
阶段 1:canCommit
-
协调者向所有参与者发出包含事务内容的 canCommit 请求,询问是否可以提交事务,并等待所有参与者答复。
-
参与者收到 canCommit 请求后,如果认为可以执行事务操作,则反馈 yes 并进入预备状态,否则反馈 no。
阶段 2:preCommit
协调者根据阶段 1 canCommit 参与者的反应情况来决定是否可以进行基于事务的 preCommit 操作,如下表
情况 1 | 阶段 1 所有参与者均反馈 yes,参与者预执行事务:
|
情况 2 | 阶段 1 任何一个参与者反馈 no,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务,如上图:
|
阶段 3:do Commit
注意:进入阶段 3 后,无论协调者出现问题,或者协调者与参与者网络出现问题,都会导致参与者无法接收到协调者发出的 do Commit 请求或 abort 请求。此时,参与者都会在等待超时之后,继续执行事务提交。
情况 1:阶段 2 所有参与者均反馈 ack 响应,执行真正的事务提交 |
|
情况 2:阶段 2 任何一个参与者反馈 no,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务 |
|
3PC总结
优点:相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。避免了协调者单点问题,阶段 3 中协调者出现问题时,参与者会继续提交事务。
缺点:数据不一致问题依然存在,当在参与者收到 preCommit 请求后等待 do commite 指令时,此时如果协调者请求中断事务,而协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。
TCC(try-confirm-cancel)方案
tcc其操作也是分为2个阶段,其中try是第一阶段,confirm、camcel是第二阶段,tcc的整个流程其实可以看成我们编程是的加锁逻辑:
第一阶段
-
Try ,负责资源的检查和预留。(加锁,锁住资源)
第二阶段,根据第一阶段的结果,决定是执行confirm还是cancel
-
Confirm 执行真正的业务。(执行业务,释放锁)
-
Cancel 是预留资源的取消。(出问题,释放锁)
以电商为例,用户购买业务涉及到库存、订单两个服务(不同服务器),需要减库存+创建订单;
现在有库存10,这时用户购买了2份
Try阶段
,
confirm/cancel阶段
TCC总结
TCC 事务机制相对于传统事务机制(X/Open XA),TCC 事务机制相比于上面介绍的 XA 事务机制
优点:
-
性能提升:具体业务来实现控制资源锁的粒度变小,不会锁定整个资源。
-
数据最终一致性:基于 Confirm 和 Cancel 的幂等性,保证事务最终完成确认或者取消,保证数据的一致性。
-
可靠性:解决了 XA 协议的协调者单点故障问题,由主业务方发起并控制整个业务活动,业务活动管理器也变成多点,引入集群。
缺点: TCC 的 Try、Confirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开发成本。
MQ 事务方案
MQ事务的方案和ebay提出的本地消息表的理念是很相近的,(本地消息表用MQ来实现),他们的核心思想就是将分布式事务拆成本地事务来处理,利用本地事务的事物特性来保证数据最终一致性。
总的流程如下:服务A基于 MQ 通信通知服务B处理事务,服务B基于 MQ 返回处理结果。
如果服务B消费消息异常,需要不断重试,业务处理逻辑需要保证幂等。
如果是服务B业务上的处理失败,可以通过 MQ 通知服务A进行补偿或者事务回滚
服务A中一般正常流程如图
异常情况:如果出现了断网等
MQ总结
优点是:
-
消息数据独立存储 ,降低业务系统与消息系统之间的耦合。
缺点是:
-
一次消息发送需要两次网络请求(half 消息 + commit/rollback 消息) 。
-
业务处理服务需要实现消息状态回查接口。