原文地址:《一致性协议之三阶段提交》
在上一篇文章《一致性协议之二阶段提交》中介绍了二阶段提交协议的设计和原理,也了解了在实际运行过程中可能存在的一些问题,因此研究者在二阶段提交协议的基础上进行了改进,提出了三阶段提交协议。
协议说明
3PC,是Three-Phase Commit的缩写,即三阶段提交,是2PC的改进版,将二阶段提交协议的“提交事务请求”过程分为二步,形成了CanCommit、PreCommit和doCommit三个阶段组成的事务下得协议,协议设计如下图:
下面我们来看一下协议的详细说明。
阶段一:CanCommit
-
事务询问
协调者向所有参与者发送一个包含事务内容的canCommit请求,询问是否可以执行事务提交操作,并进入等待各参与者响应状态。
-
参与者响应
参与者接收到协调者的canCommit请求后,如果认为可以顺利执行事务则反馈Yes响应,并进入预备状态,否则反馈No响应。
阶段二:PreCommit
在阶段二中,协调者会根据各参与者的响应来决定是否进行事务的PreCommit操作,阶段二中会包含以下两种可能。
执行事务预提交
如果协调者从所有参与者获得的反馈都是Yes响应,那么会执行预提交。
-
发送预提交请求
协调者向所有参与者发送preCommit请求,并进入Prepared阶段。
-
事务预提交
参与者收到preCommit请求后,会执行事务操作,并将Undo和Redo信息记录到事务日志中。
-
向协调者反馈事务执行响应
如果参与者成功执行了事务操作,反馈给协调者Ack响应,并进入等待最终指令状态中,最终指令包括提交(commit)或终止(abort)。
中断事务
如果任何一个参与者反馈了No响应,或在协调者等待所有参与者反馈时发生了超时,那么就会中断事务。
-
发送中断请求
协调者向所有参与者发送abort请求。
-
中断事务
参与者如果接收到了协调者的abort请求,或者在等待协调者请求过程中出现超时,参与者都会中断事务。
阶段三:doCommit
该阶段会对事务进行真正的提交,也会存在下面两种情况。
执行提交
如果在第二阶段协调者接收到了所有参与者的Ack响应,那么协调者就从预提交状态转换到提交状态,并向所有参与者发出doCommit请求。
-
发送提交请求
向所有参与者发送commit请求。
-
事务提交
参与者接收到doCommit请求后,会正式执行事务提交操作,并在提交成功后释放事务执行期间占用的事务资源。向协调者发送Ack消息。
-
完成事务
协调者接收到所有参与者反馈的Ack消息后,完成事务。
中断事务
如果在阶段二中,协调者接收到了参与者的No响应,或者在等待参与者响应时发生了超时,就会中断事务。
-
发送中断请求
协调者向所有参与者发送abort请求。
-
事务回滚
参与者接收到abort请求后,会利用阶段二中记录的Undo信息来执行事务回滚操作,并在回滚成功后释放所有事务执行期间占用的事务资源。向协调者发送Ack消息。
-
中断事务
协调者接收到所有参与者反馈的Ack消息后,中断事务。
这里有一点需要注意,当进入阶段三后,如果协调者出现问题或协调者与参与者通信出现问题。这两种情况都会导致参与者无法及时收到协调者的commit或abort请求,针对这种问题参与者会在等待超时后自动进行事务的提交。
三阶段提交协议的设计描述比较多,为了便于理解,将上述的描述内容整理了一个表格和流程图可以方便大家的理解。
优缺点
优点:相比于二阶段提交协议,三阶段提交协议最大的优点就是降低了参与者的阻塞范围,并且能够在出现单点故障后继续达成一致。
缺点:数据的不一致,在阶段三中,如果参与者接收到了preCommit消息后,出现了不能与协调者正常通信的问题,在这种情况下,参与者依然会进行事务的提交,这就出现了数据的不一致性。