浅谈ZAB协议及ZooKeeper选举机制

浅谈ZAB协议及ZooKeeper选举机制

​ 众所周知,世界上只有一种分布式一致性协议,那就是Paxos,那么我们今天为什么要讨论Zab协议呢,ZAB协议又是什么呢。

​ Google公司有一个大名鼎鼎的分布式锁服务,名叫Chubby,GFS和Big Table都使用它进行分布式协作,其底层的一致性实现就是以Paxos算法为基础。但是Chubby不是开源的,因此雅虎的开发者们,也以Paxos算法为基础,实现了另一种协议,就是我们今天要讨论的ZAB协议。而ZooKeeper也可以说是Chubby的开源实现。

​ ZAB协议,全称是ZooKeeper Atomic Broadcast,即原子消息广播协议。它是专门为ZooKeeper设计的一套崩溃恢复的原子消息广播算法。大家都知道,ZooKeeper集群是没有主从节点的概念区分,而是提供了Leader和Flower两种角色(其实还有Observer,但是它不参与选举过程,也不参与事务过程,只处理读请求,所以可以忽略)。Leader和Flower就是专门为ZAB协议设计的。ZAB协议定义了所有的事务请求必须由一个全局唯一的服务器进行处理,而这台服务器就是Leader。当Flower收到事务请求时,也只是转发该请求至Leader处。Leader服务器负责将事务请求封装为一个Proposal,然后分发给所有的Flower,当超过半数的Flower反馈正确的请求后,Leader就会发生一个commit请求,要求各Flower将前一个Proposal提交。

​ 怎么样,这里的描述是不是和Paxos算法有点类似。但是ZAB协议不止这点东西。ZAB协议主要包含了两种基本模式。崩溃恢复消息广播。下面我们分别讲述一下

崩溃恢复

​ 当ZooKeeper在启动过程中,或者Leader服务器出现网络中断,崩溃退出,重启等异常情况,此时就会进入恢复模式,同时也会选举出新的Leader服务器。然后各Flower从Leader同步数据,当有半数以上的机器同步完成,便退出该模式。

​ 咋一看崩溃恢复的过程十分简单,但是我们需要保证一旦一个Proposal在一台机器上提交成功,就要在所有的机器上成功这种情况,就需要一个有效且可以快速选举的算法。这就是我们说的ZooKeeper选举机制。

ZooKeeper选举机制

​ 我们知道ZAB协议是基于Paxos协议,Paxos协议中每次发出提议,都会伴随一个全局唯一且递增的id,那么自然,ZAB协议中也会有这样一个Id,它就是ZXID,但是ZXID不同于Paxos协议中的id,其主要组成为2个部分,高32位是Leader的标志id,也是一个递增的Id,低32位是每次提交Proposal的id。那么这个id在Leader选举中有什么用呢。

​ 假如说,现在有3个节点,节点A是Leader,B和C都是Flower,当前的ZXID为0000 0001(假设前4位为Leader标志,后4位为当前时期提交的Proposal的id),这时按顺序来了3个事务请求p1、p2、p3。按假设情况进行处理

  1. A节点先处理p1,处理完成后,B、C节点也都提交完成,ZXID变为0000 0002。

  2. A节点继续处理p2,发送至B节点,和C节点,均返回正常,所以就A节点发出commit请求。

  3. B节点收到commit请求,开始进行提交,之后,A节点网络故障。但是整个系统由于还有2个节点可用,所以就发起了选举。

  4. 各存活节点,开始发起广播,告知自己节点的ZXID,按照上述情况,B节点完成了commit请求,所以他的ZXID是0000 0003,而其余节点均为0000 0002。

  5. 相比之下,各个节点都知道了谁是最大的节点,最大Id的节点就成为了新的Leader。然后新的Leader就会生成一个新的标志id,同时低32位id会置0。此时新的ZXID就是0001 0000。大家可以把高32位理解朝代(比如:唐宋元明清)。低32位理解为每朝的奏折。新朝代自然不用处理前朝的奏折。

  6. 选举完成后,由Leader向Flower发送消息,按照自身的已提交的Proposal,一个Proposal一个Commit进行发送。当Flower接收到新的Proposal时就会进行同步处理。

  7. 如果此时旧的Leader节点A又重新连接了,那么他还是会发送未完成的事务请求,但是由于已经是一个新的朝代了(旧事物的ZXID依旧是上一个朝代的id),所以其他节点不会处理这些事务请求,自然而然就将其废弃。

    在ZooKeeper中ZXID都会有一个事务日志保存,大家比较也是比较事务日志里最大的id。ZXID的高32位的官方叫法是epoch值,也是从事务日志中解析出来的,低32位就是一个单调递增的id值。搭配起来,可以理解为朝代+奏折,选举理解为新朝代建立,新朝代怎么会处理上一个朝代的奏折呢,所以上一个Leader的事务都会被废弃。

继续回到崩溃恢复,选举完成后,便按照选举中的5,6,7步进行相应的处理了,数据同步时 ,Leader节点需要保证每个Flower节点都收到Proposal,所以会为每一个Flower建立一个相应的队列进行数据发送。

消息广播

​ 当整个集群有超过一半的节点可正常提供服务时,便会进入消息广播模式。

​ 其过程类似我们之前讲的Paxos算法,是一个二阶段的提交过程,与其不同的事,移除了中断处理逻辑,Flower只会对Leader的事务请求做成功反馈或者抛弃处理,这也使得ZooKeeper在得到半数以上Flower同意时,不必立即等待,而是直接发起commit请求。

​ 另外,整个广播过程是基于FIFO的TCP协议进行完成的,同时在前文中有提到,每次事务请求都会有一个全局唯一且递增的ZXID伴随其左右,所以,ZooKeeper能够严格保证每次事务请求的顺序

你可能感兴趣的:(分布式服务相关)