1、引言
事务是指程序在做一件事情的时候,要么成功完成,要么完不成。把满足ACID特征事务的称为刚性事务,即具有非常强的一致性要求。随着分布式系统的不断普及,分布式事务方案不断涌现出来,本文将学习总结下当前比较流行的分布式事务框架,目的是学习前人解决问题的思路,以备实际开发中可以借鉴。
2、2PC方案
考虑这样一个需求:用户A想要去某地旅行,为了避免繁琐的购票环节,通过一家旅行社安排行程。旅行社要做的事情为:订一张火车票和目的地的酒店,如果订购火车票失败,就不会定酒店,行程自然失败;同样的如果火车票订购成功但是酒店订购失败,行程也将失败。即订购火车票和订酒店这两个动作只要有一个失败,行程都将失败,如图1所示。
图1 旅行社订票示意图
上述的过程其实就是一个分布式事务解决方案:2PC(Two-Phase Commit,两阶段提交)。2PC中引入了参与者(Participant)与协调者(Coordinator)的概念。参与者是指参与执行具体功能业务的服务节点,上述例子中,订票的12306和订酒店的携程就是这次活动中的参与者。协调者是指接收服务请求后向将对应服务指派给对应参与者并询问执行结果的角色,比如上述的旅行社就是协调者,在订车票和订酒店时,都有两个步骤:
1)锁定:先下单锁定票,但是不支付 ;
2)支付:火车票和酒店都锁定成功后,再统一发起支付。
锁定票阶段,每个参与者(12306、携程)会告知旅行社(协调者),是否已经锁定成功,如果都已经锁定成功,则旅行社将发起第二步统一支付,支付完后才能代表本次行程安排成功。
当然,如果有一个参与者没有锁定成功,比如没有锁定到还有空房间的酒店,旅行社将在12306中取消支付(回滚),并告知用户本次包办的任务失败。
在定义上,2PC将分布式事务过程分为两个阶段:
投票阶段(voting phase):参与者将操作结果告知协调者; 提交阶段(commit phase):协调者收到参与者的通知后,根据反馈的结果(成功or失败)决定各个参与者是提交还是回滚。
实际上,2PC是XA规范的一种衍生实现,XA规范是指:
X/Open 组织(即现在的 Open Group )定义的分布式事务处理(DTP)模型。 X/Open DTP 模型包括应用程序( AP )、事务管理器( TM )、资源管理器( RM )、通信资源管理器( CRM )四部分。通常,事务管理器( TM )是指交易中间件,资源管理器( RM )是数据库,通信资源管理器( CRM )是消息中间件。
以MySQL为例,它的事务就是通过XA规范的2PC实现的,MySQL的两阶段为:
第一阶段:发送prepare消息,这一步完成SQL语句操作,但是事务未提交; 第二阶段:如果第一阶段prepare失败/成功,协调者通知所有库回滚/提交.
如图2所示:
图2 MySQL两阶段过程
假设12306或携程没有支付超时后释放锁定的机制,可能会遇到这样一些麻烦:
1)12306或携程锁定资源过程中,旅行社要等每个参与者返回锁定结果,这个过程是同步阻塞的,用户会觉得太慢了,体验不佳;
2)12306和携程锁定资源成功,但旅行社由于只有1个人A,通知结果被遗漏处理,就会导致锁定的资源一直锁定着无法释放,这就是旅行社(协调者)单点问题导致的参与者资源一直被锁定着;
假设旅行社增加了1个人B,现在2个人以换班的方式处理,A和B换班后,B是不知道哪些已经支付过,哪些支付失败了的,也就是导致了协调者切换过程中的事务状态丢失。
3)如果在确认支付的时候,12306收到了确认支付请求并成功完成了支付,但是发送给携程支付的请求丢失了,此时参与者之间会将存在数据不一致。即预期应该是12306和携程中的状态都是已支付状态,实际上携程中状态是未支付或支付失败。该问题也叫脑裂。
以上麻烦就是典型的2PC的四种缺陷:同步阻塞、协调者单点问题、事务状态丢失、数据不一致。
为了解决2PC的上述三种问题,业界引入了3PC分布式解决方案。
3、3PC方案
3PC(Three-Phase Commit)即三阶段提交,它是将2CP第一阶段分为了两个阶段:能提交和准备提交,最后形成三阶段提交,同时在RM中引入超时机制:当RM超时未收到协调者的确认提交消息,会自动提交以释放资源,比如12306中超时未支付,系统自动给你支付了(实际上不会)。
第一阶段:发送CanCommit请求,确认数据库环境正常; 第二阶段:发送PreCommit请求,完成SQL操作,但是未提交; 第三阶段:发送DoCommit请求,通知所有数据库提交/回滚。
如图3所示:
图3 3PC过程示意图
考虑这样一种情况:我本来是要取消12306支付的,命令发出去之后,由于网络原因,12306超时都未收到我发送的取消支付指令,就主动给我支付了,这显然不合理,这就是3PC的数据不一致性问题,即:
由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
以上就是2PC和3PC的基本介绍,后续文章将继续总结和介绍其他的分布式思想。