.6 两阶段提交协议
两阶段提交协议是一种经典的强一致性中心化副本控制协议。虽然在工程中该协议有较多的问题,但研究该协议能很好的理解分布式系统的几个典型问题。
流程描述
两阶段提交协议是一种典型的“中心化副本控制”协议。在该协议中,参与的节点分为两类:一个中心化协调者节点(coordinator)和N 个参与者节点(participant)。每个参与者节点即上文背景介绍中的管理数据库副本的节点。
两阶段提交的思路比较简单,在第一阶段,协调者询问所有的参与者是否可以提交事务(请参与者投票),所有参与者向协调者投票。
在第二阶段,协调者根据所有参与者的投票结果做出是否事务可以全局提交的决定,并通知所有的参与者执行该决定。在一个两阶段提交流程中,参与者不能改变自己的投票结果。
两阶段提交协议的可以全局提交的前提是所有的参与者都同意提交事务,只要有一个参与者投票选择放弃(abort)事务,则事务必须被放弃。
流程:两阶段提交协调者流程
-
写本地日志“begin_commit”,并进入WAIT 状态;
-
向所有参与者发送“prepare 消息”;
-
等待并接收参与者发送的对“prepare 消息”的响应;3.1 若收到任何一个参与者发送的“vote-abort 消息”;3.1.1 写本地“global-abort”日志,进入ABORT;3.1.2 向所有的参与者发送“global-abort 消息”;3.1.3 进入ABORT 状态;3.2 若收到所有参与者发送的“vote-commit”消息;3.2.1 写本地“global-commit”日志,进入COMMIT 状态;3.1.2 向所有的参与者发送“global-commit 消息”;
-
等待并接收参与者发送的对“global-abort 消息”或“global-commit 消息”的确认响应消息,一旦收到所有参与者的确认消息,写本地“end_transaction” 日志流程结束。
流程:两阶段提交协调者流程
-
写本地日志“init”记录,进入INIT 状态
-
等待并接受协调者发送的“prepare 消息”,收到后 2.1 若参与者可以提交本次事务 2.1.1 写本地日志“ready”,进入READY 状态 2.1.2 向协调者发送“vote-commit”消息 2.1.4 等待协调者的消息2.1.4.1 若收到协调者的“global-abort”消息2.1.4.1.1 写本地日志“abort”,进入ABORT 状态2.1.4.1.2 向协调者发送对“global-abort”的确认消息 2.1.4.2 若收到协调者的“global-commit”消息2.1.4.1.1 写本地日志“commit”,进入COMMIT 状态 2.1.4.1.2 向协调者发送对“global-commit”的确认消息 2.2 若参与者无法提交本次事务 2.2.1 写本地日志“abort”,进入ABORT 状态 2.2.2 向协调者发送“vote-abort”消息 2.2.3 流程对该参与者结束 2.2.4 若后续收到协调者的“global-abort”消息可以响应
-
即使流程结束,但任何时候收到协调者发送的“global-abort”消息或“global-commit”消息也都要发送一个对应的确认消息。
异常处理
宕机恢复
-
协调者宕机恢复 协调者宕机恢复后,首先通过日志查找到宕机前的状态。如果日志中最后是“begin_commit”记录,说明宕机前协调者处于WAIT 状态,协调者可能已经发送过“prepare 消息”也可能还没发送,但协调者一定还没有发送过“global-commit 消息”或“global-abort 消息”,即事务的全局状态还没有确定。此时,协调者可以重新发送“prepare 消息” 继续两阶段提交流程,即使参与者已经发送过对“prepare 消息”的响应,也不过是再次重传之前的响应而不会影响协议的一致性。如果日志中最后是“global-commit”或“global-abort”记录,说明宕机前协调者处于COMMIT 或ABORT 状态。此时协调者只需重新向所有的参与者发送“global-commit 消息”或“global-abort 消息”就可以继续两阶段提交流程。
-
参与者宕机恢复参与者宕机恢复后,首先通过日志查找宕机前的状态。如果日志中最后是“init”记录,说明参与者处于INIT 状态,还没有对本次事务做出投票选择,参与者可以继续流程等待协调者发送的“prepare 消息”。如果日志中最后是“ready”记录,说明参与者处于REDAY 状态,此时说明参与者已经就本次 事务做出了投票选择,但宕机前参与者是否已经向协调者发送“vote-commit”消息并不可知。所以此时参与者可以向协调者重发“vote-commit”,并继续协议流程。如果日志中最后是“commit”或“abort”记录,说明参与者已经收到过协调者的“global-commit 消息”(处于COMMIT 状态)或者“global-abort 消息”(处于ABORT 状态)。至于是否向协调者发 送过对“global-commit”或“global-abort”的确认消息则未知。但即使没有发送过确认消息,由于协调者会不断重发“global-commit”或“global-abort”,只需在收到这些消息时发送确认消息既可,不影响协议的全局一致性。
协议分析
两阶段提交协议在工程实践中真正使用的较少,主要原因有以下几点:
-
两阶段提交协议的容错能力较差。从上文的分析可以看出,两阶段提交协议在某些情况下存在流程无法执行下去的情况,且也无法判断流程状态。在工程中好的分布式协议往往总是可以在即使发生异常的情况下也能执行下去。例如,回忆Lease 机制(2.3 ),一旦lease 发出,无论出现任何异常,Lease 服务器节点总是可以通过时间判定出Lease 是否有效,也可以用等待Lease 超时的方法收回Lease 权限,整个Lease 协议的流程不存在任何流程被阻塞而无法执行下去的情况。与Lease 机制的简单有效相比,两阶段提交的协议显得较为复杂且容错能力差。
-
两阶段提交协议的性能较差。一次成功的两阶段提交协议流程中,协调者与每个参与者 之间至少需要两轮交互4 个消息“prepare”、“vote-commit”、“global-commit”、“确认global-commit”。过多的交互次数会降低性能。另一方面,协调者需要等待所有的参与者的投票结果,一旦存在较慢的参与者,会影响全局流程执行速度。
虽然存在一些改进的两阶段提交协议可以提高容错能力和性能,然而这类协议依旧是在工程中使用较少的一类协议,其理论价值大于实践意义。
2.7 MVCC
MVCC(Multi-version Cocurrent Control,多版本并发控制)技术。MVCC 技术最初也是在数据库系统中被提出,但这种思想并不局限于单机的分布式系统,在分布式系统中同样有效。
MVCC 即多个不同版本的数据实现并发控制的技术,其基本思想是为每次事务生成 一个新版本的数据,在读数据时选择不同版本的数据即可以实现对事务结果的完整性读取。在使用MVCC 时,每个事务都是基于一个已生效的基础版本进行更新,事务可以并行进行,从而可以产生一种图状结构。

(编辑:广安站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|