1、背景
在分布式系统中往往存在分布式一致性的问题;针对该问题,之前有大神研究出了两阶段提交协议,三阶段提交协议、Paxos算法等,zookeeper就是应用的Paxos算法的优化版;下边主要说下两阶段协议与三阶段提交协议。
2、两阶段提交协议
阶段一:
a.事物协调者向事物参与者发送消息询问,各个参与者是否可以执行相应的事物提交操作;
b.各个事物参与者节点执行相应的事物提交,并将Undo和Redo信息记录在事物日志中;
c.各个事物参与者向事物协调者反馈结果,如果成功执行了事物的操作,则返回给事物协调者YES,表示事物可以执行;如果没有成功执行事物操作,则返回给事物协调者NO,表示事物不可以执行;
阶段二:
1:
a.如果事物参与者向事物协调者发送的都是YES,则将执行事物提交操作,事物协调者向所有事物参与者发出commit请求;
b.当事物参与者接收到commit请求后,正式的执行事物提交操作,并在完成提交后释放执行事物期间所占用的事物资源,并向事物协调者发送Ack信息;
c.完成事物
2:
a.如果有一个参与者返回NO,或者在等待超时后,协调者没有接收到所有参与者的响应,那么就会中断事物,协调者向所有参与者发送Rollback请求;
b.参与者在接收到Rollback请求后,会应用阶段一的Undo事务日志信息来执行事物回滚操作;完成回滚后释放执行事物期间占用的事物资源;并向事物协调者发送Ack信息;
c.完成事物中断;
优点:简单好用,实现方便。
缺点:同步阻塞,单点问题,还是会有数据不一致的情况出现。
同步阻塞:在二阶段提交事务的过程中,所有参与该事务操作的逻辑都处于阻塞状态,各个参与者在等待其他参与者的响应过程中,无法做其他的操作。
单点问题:在二阶段提交协议中,协调者这个角色是很重要的,一旦协调者挂掉,将导致整个提交流程无法运转,若是在第二阶段协调者挂掉,参与者将一直处于锁定事务资源的状态,无法继续完成事务操作。(两阶段提交协议中只有协调者有超时机制,参与者没有)
数据不一致:若是在第二阶段,协调者在向所有参与者发送commit请求时,由于局部网络的故障,只有部分参与者受到commit请求,提交事务,这样没有受到commit请求的就没有提交事务,出现了数据不一致的情况。
2、三阶段提交协议
1)三个阶段的执行
1.CanCommit阶段
3PC的CanCommit阶段其实和2PC的准备阶段很像。
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
2.PreCommit阶段
Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作。
根据响应情况,有以下两种可能。
A.假如Coordinator从所有的Cohort获得的反馈都是Yes响应,那么就会进行事务的预执行:
发送预提交请求。Coordinator向Cohort发送PreCommit请求,并进入Prepared阶段。
事务预提交。Cohort接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
响应反馈。如果Cohort成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
B.假如有任何一个Cohort向Coordinator发送了No响应,或者等待超时之后,Coordinator都没有接到Cohort的响应,那么就中断事务:
发送中断请求。Coordinator向所有Cohort发送abort请求。
中断事务。Cohort收到来自Coordinator的abort请求之后(或超时之后,仍未收到Cohort的请求),执行事务的中断。
3.DoCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况:
执行提交
A.发送提交请求。Coordinator接收到Cohort发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有Cohort发送doCommit请求。
B.事务提交。Cohort接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
C.响应反馈。事务提交完之后,向Coordinator发送ACK响应。
D.完成事务。Coordinator接收到所有Cohort的ACK响应之后,完成事务。
中断事务
Coordinator没有接收到Cohort发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
(2)三阶段提交协议和两阶段提交协议的不同
对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)。
在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段。
PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。
(2)三阶段提交协议的缺点
如果进入PreCommit后,Coordinator发出的是abort请求,假设只有一个Cohort收到并进行了abort操作,
而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发生不一致性。
三阶段提交是“非阻塞”协议。
三阶段提交在两阶段提交的第一阶段与第二阶段之间插入了一个准备阶段,
使得原先在两阶段提交中,参与者在投票之后,由于协调者发生崩溃或错误,
而导致参与者处于无法知晓是否提交或者中止的“不确定状态”所产生的可能相当长的延时的问题得以解决。 举例来说,假设有一个决策小组由一个主持人负责与多位组员以电话联络方式协调是否通过一个提案,以两阶段提交来说,主持人收到一个提案请求,打电话跟每个组员询问是否通过并统计回复,然后将最后决定打电话通知各组员。
要是主持人在跟第一位组员通完电话后失忆,而第一位组员在得知结果并执行后老人痴呆,那么即使重新选出主持人,也没人知道最后的提案决定是什么,也许是通过,也许是驳回,不管大家选择哪一种决定,都有可能与第一位组员已执行过的真实决定不一致,老板就会不开心认为决策小组沟通有问题而解雇。
三阶段提交即是引入了另一个步骤,主持人打电话跟组员通知请准备通过提案,以避免没人知道真实决定而造成决定不一致的失业危机。
为什么能够解决二阶段提交的问题呢?
回到刚刚提到的状况,在主持人通知完第一位组员请准备通过后两人意外失忆,即使没人知道全体在第一阶段的决定为何,全体决策组员仍可以重新协调过程或直接否决,不会有不一致决定而失业。
那么当主持人通知完全体组员请准备通过并得到大家的再次确定后进入第三阶段,
当主持人通知第一位组员请通过提案后两人意外失忆,这时候其他组员再重新选出主持人后,
仍可以知道目前至少是处于准备通过提案阶段,表示第一阶段大家都已经决定要通过了,此时便可以直接通过。