3.7 分布式协议
分布式系统涉及的协议很多,例如租约,复制协议,一致性协议,其中以两阶段提交协议和Paxos协议最具有代表性。两阶段提交协议用于保证跨多个节点操作的原子性,也就是说,跨多个节点的操作要么在所有节点上全部执行成功,要么全部失败。Paxos协议用于确保多个节点对某个投票(例如哪个节点为主节点)达成一致。本节介绍这两个分布式协议。
3.7.1 两阶段提交协议
两阶段提交协议(Two-phase Commit,2PC)经常用来实现分布式事务,在两阶段协议中,系统一般包含两类节点:一类为协调者(coordinator),通常一个系统中只有一个;另一类为事务参与者(participants,cohorts或workers),一般包含多个。协议中假设每个节点都会记录操作日志并持久化到非易失性存储介质,即使节点发生故障日志也不会丢失。顾名思义,两阶段提交协议由两个阶段组成。在正常的执行过程中,这两个阶段的执行过程如下所述:
●阶段1:请求阶段(Prepare Phase)。在请求阶段,协调者通知事务参与者准备提交或者取消事务,然后进入表决过程。在表决过程中,参与者将告知协调者自己的决策:同意(事务参与者本地执行成功)或者取消(事务参与者本地执行失败)。
●阶段2:提交阶段(Commit Phase)。在提交阶段,协调者将基于第一个阶段的投票结果进行决策:提交或者取消。当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者通知所有的参与者取消事务。参与者在接收到协调者发来的消息后将执行相应的操作。
例如,A组织B、C和D三个人去爬长城:如果所有人都同意去爬长城,那么活动将举行;如果有一人不同意去爬长城,那么活动将取消。用2PC算法解决该问题的过程如下:
1)首先A将成为该活动的协调者,B、C和D将成为该活动的参与者。
2)准备阶段:A发邮件给B、C和D,提出下周三去爬山,问是否同意。那么此时A需要等待B、C和D的回复。B、C和D分别查看自己的日程安排表。B、C发现自己在当日没有活动安排,则发邮件告诉A他们同意下周三去爬长城。由于某种原因,D白天没有查看邮件。那么此时A、B和C均需要等待。到晚上的时候,D发现了A的邮件,然后查看日程安排,发现下周三当天已经有别的安排,那么D回复A说活动取消吧。
3)此时A收到了所有活动参与者的邮件,并且A发现D下周三不能去爬山。那么A将发邮件通知B、C和D,下周三爬长城活动取消。此时B、C回复A“太可惜了”,D回复A“不好意思”。至此该事务终止。
通过该例子可以发现,2PC协议存在明显的问题。假如D一直不能回复邮件,那么A、B和C将不得不处于一直等待的状态。并且B和C所持有的资源一直不能释放,即下周三不能安排其他活动。当然,A可以发邮件告诉D如果晚上六点之前不回复活动就自动取消,通过引入事务的超时机制防止资源一直不能释放的情况。更为严重的是,假如A发完邮件后生病住院了,即使B、C和D都发邮件告诉A同意下周三去爬长城,如果A没有备份,事务将被阻塞,B、C和D下周三都不能安排其他活动。
两阶段提交协议可能面临两种故障:
●事务参与者发生故障。给每个事务设置一个超时时间,如果某个事务参与者一直不响应,到达超时时间后整个事务失败。
●协调者发生故障。协调者需要将事务相关信息记录到操作日志并同步到备用协调者,假如协调者发生故障,备用协调者可以接替它完成后续的工作。如果没有备用协调者,协调者又发生了永久性故障,事务参与者将无法完成事务而一直等待下去。
总而言之,两阶段提交协议是阻塞协议,执行过程中需要锁住其他更新,且不能容错,大多数分布式存储系统都采用敬而远之的做法,放弃对分布式事务的支持。