02、分布式事务 实战 - XA协议和N阶段提交

XA

在维基百科中解释道:在计算技术上,XA规范是开放群组关于分布式事务处理 (DTP)的规范。规范描述了全局的事务管理器与局部的资源管理器之间的接口。XA规范的目的是允许多个资源(如数据库,应用服务器,消息队列,等等)在同一事务中访问,这样可以使ACID属性跨越应用程序而保持有效。XA使用两阶段提交来保证所有资源同时提交或回滚任何特定的事务。XA规范描述了资源管理器要支持事务性访问所必需做的事情。遵守该规范的资源管理器被称为XA compliant。

XA使用两阶段提交或三阶段提交来保证所有资源同时提交或回滚任何特定的事务

二阶段提交(Two-phase Commit)

在计算机网络以及数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法。通常,二阶段提交也被称为是一种协议(Protocol)。在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为: 参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

二阶段提交算法成立的假设

1、 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Participants)且节点之间可以进行网络通信;
2、 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失;
3、 所有节点不会永久性损坏,即使损坏后仍然可以恢复;

算法实现步骤

 

第一阶段(提交请求阶段)

协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。
参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。
各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个"同意"消息;如果参与者节点的事务操作实际执行失败,则它返回一个"中止"消息。
有时候,第一阶段也被称作投票阶段,即各参与者投票是否要继续接下来的提交操作。

第二阶段(提交执行阶段)

如果成功

当协调者节点从所有参与者节点获得的相应消息都为"同意"时:
协调者节点向所有参与者节点发出"正式提交"的请求。
参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
参与者节点向协调者节点发送"完成"消息。
协调者节点收到所有参与者节点反馈的"完成"消息后,完成事务。

如果失败

如果任一参与者节点在第一阶段返回的响应消息为"终止",或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:
协调者节点向所有参与者节点发出"回滚操作"的请求。
参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
参与者节点向协调者节点发送"回滚完成"消息。
协调者节点收到所有参与者节点反馈的"回滚完成"消息后,取消事务。
有时候,第二阶段也被称作完成阶段,因为无论结果怎样,协调者都必须在此阶段结束当前事务。

二阶段提交看起来确实能够提供原子性的操作,但是不幸的事,二阶段提交问题:

1、 同步阻塞问题执行过程中,所有参与节点都是事务阻塞型的当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态;
2、 单点故障由于协调者的重要性,一旦协调者发生故障参与者会一直阻塞下去尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题);
3、 数据不一致在第二个阶段中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这会导致只有一部分参与者接受到了commit请求而在这部分参与者接到commit请求之后就会执行commit操作但是其他部分未接到commit请求的机器则无法执行事务提交于是整个分布式系统便出现了数据部一致性的现象;
4、 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交;

三阶段提交(Three-phase commit)

也叫三阶段提交协议(Three-phase commit protocol),是二阶段提交(2PC)的改进版本。

与两阶段提交不同的是,三阶段提交是“非阻塞”协议。三阶段提交在两阶段提交的第一阶段与第二阶段之间插入了一个准备阶段,使得原先在两阶段提交中,参与者在投票之后,由于协调者发生崩溃或错误,而导致参与者处于无法知晓是否提交或者中止的“不确定状态”所产生的可能相当长的延时的问题得以解决。

核心2个改动点:

1、 引入超时机制同时在协调者和参与者中都引入超时机制;
2、 在第一阶段和第二阶段中插入一个准备阶段保证了在最后提交阶段之前各参与节点的状态是一致的;

三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

 

CanCommit阶段

3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

1、 事务询问协调者向参与者发送CanCommit请求询问是否可以执行事务提交操作然后开始等待参与者的响应;
2、 响应反馈参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态否则反馈No;

PreCommit阶段

协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。

假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。

1、 发送预提交请求协调者向参与者发送PreCommit请求,并进入Prepared阶段;
2、 事务预提交参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中;
3、 响应反馈如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令;

假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。

1、 发送中断请求协调者向所有参与者发送abort请求;
2、 中断事务参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断;

doCommit阶段

该阶段进行真正的事务提交,也可以分为以下两种情况。

执行提交

1、 发送提交请求协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态并向所有参与者发送doCommit请求;
2、 事务提交参与者接收到doCommit请求之后,执行正式的事务提交并在完成事务提交之后释放所有事务资源;
3、 响应反馈事务提交完之后,向协调者发送Ack响应;
4、 完成事务协调者接收到所有参与者的ack响应之后,完成事务;

中断事务:协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。

1、 发送中断请求协调者向所有参与者发送abort请求;
2、 事务回滚参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源;
3、 反馈结果参与者完成事务回滚之后,向协调者发送ACK消息;
4、 中断事务协调者接收到参与者反馈的ACK消息之后,执行事务的中断;

2PC与3PC的区别

相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。

举例

假设有一个决策小组由一个主持人负责与多位组员以电话联络方式协调是否通过一个提案。
以两阶段提交来说,主持人收到一个提案请求,打电话跟每个组员询问是否通过并统计回复,然后将最后决定打电话通知各组员。要是主持人在跟第一位组员通完电话后失忆,而第一位组员在得知结果并执行后老人痴呆,那么即使重新选出主持人,也没人知道最后的提案决定是什么,也许是通过,也许是驳回,不管大家选择哪一种决定,都有可能与第一位组员已执行过的真实决定不一致,老板就会不开心认为决策小组沟通有问题而解雇

三阶段提交即是引入了另一个步骤,主持人打电话跟组员通知请准备通过提案,以避免没人知道真实决定而造成决定不一致的失业危机。为什么能够解决二阶段提交的问题呢?回到刚刚提到的状况,在主持人通知完第一位组员请准备通过后两人意外失忆,即使没人知道全体在第一阶段的决定为何,全体决策组员仍可以重新协调过程或直接否决,不会有不一致决定而失业。那么当主持人通知完全体组员请准备通过并得到大家的再次确定后进入第三阶段,当主持人通知第一位组员请通过提案后两人意外失忆,这时候其他组员再重新选出主持人后,仍可以知道目前至少是处于准备通过提案阶段,表示第一阶段大家都已经决定要通过了,此时便可以直接通过。

2PC和3PC之后,我们可以发现,无论是二阶段提交还是三阶段提交都无法彻底解决分布式的一致性问题。