本篇主要讲解2PC和3PC以及TCC理论,同时介绍一个解决分布式事务的开源项目saga。
最近看了《从Paxos到zookeeper 分布式一致性原理与实践》以及《分布式服务架构:原理,设计与实战》这本书,结合之前的看到的优秀博客,做一下梳理。
在了解2PC和3PC之前先来了解XA规范。XA是由X/Open组织提出的分布式事务的规范。X/Open DTP模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。事务管理器(TM)是交易中间件,资源管理器(RM)是数据库,通信资源管理器(CRM)是消息中间件。
2PC就是基于XA规范实现的,理解了2PC就理解了XA
2PC
所谓的两个阶段是指:第一阶段:准备阶段(投票阶段)和第二阶段:提交阶段(执行阶段)
准备阶段(投票阶段)
协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应
参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志,但不提交,到达一种“万事俱备,只欠东风”的状态
参与者节点响应协调者节点发起的询问,如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息
提交阶段(执行阶段)
如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,最后释放所有事务处理过程中使用的锁资源
下图展示正常提交和提交中断。
存在问题
同步阻塞问题,执行过程中所有参与节点都是事务阻塞型的,当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态
单点故障,由于协调者的重要性一旦协调者发生故障参与者会一直阻塞下去
数据不一致,在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求,而在这部分参与者接到commit请求之后就会执行commit操作,但是其他部分未接到commit请求的机器则无法执行事务提交,于是整个分布式系统便出现了数据不一致性的现象
太过保守,如果在协调者指示参与者进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应的话,这时协调者只能依靠其自身的超时机制来判断是否需要中断事物,这样的策略显得比较保守。换句话说,二阶段提交协议没有设计较为完善的容错机制,任意一个节点的失败都会导致整个事物的失败。
3PC是解决2PC的问题做的改进
3PC
CanCommit阶段
协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应
参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No
PreCommit阶段
协调者根据参与者的反应情况来决定是否可以进行事务的PreCommit操作。根据响应情况,有以下两种可能:
假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段
事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中
响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令
假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
发送中断请求 协调者向所有参与者发送abort请求
中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断
DoCommit阶段
执行提交
发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求
事务提交 参与者接收到doCommit请求或者无法及时收到来自协调者的信息之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
响应反馈 事务提交完之后,向协调者发送Ack响应
完成事务 协调者接收到所有参与者的ack响应之后,完成事务
中断事务
协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务
发送中断请求 协调者向所有参与者发送abort请求
事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源
反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息
中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断
存在问题
三阶段提交协议在去除阻塞的同时也引入新的问题,在参与者接受到preCommit消息后,如果网络出现分区,此时协调者所在节点和参与者无法正常的网络通信,该参与者依然会在等待超时之后执行了commit操作,这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
2PC与3PC的区别
无论是2PC提交还是3PC提交都无法彻底解决分布式的一致性问题。相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。
TCC
SERVICECOMB-SAGA
参考
http://www.hollischuang.com/archives/681
《从Paxos到zookeeper 分布式一致性原理与实践》
《分布式架构:原理,设计,实战》