Zab(Zookeeper Atomic Broadcast)协议

目录

一、什么是 Zab协议

二、消息广播模式

三、崩溃恢复模式

四、数据同步

五、ZAB协议原理


一、什么是 Zab协议


ZabZookeeper Atomic BroadcastZookeeper原子广播)Zookeeper 是通过 Zab 协议保证分布式事务的最终一致性
【1】Zab协议是为分布式协调服务 Zookeeper专门设计的一种 支持崩溃恢复原子广播协议 ,是 Zookeeper保证数据一致性的核心算法。Zab借鉴了 Paxos算法,但又不像 Paxos那样,是一种通用的分布式一致性算法。它是特别为 Zookeeper设计的支持崩溃恢复的原子广播协议。
【2】在 Zookeeper中主要依赖 Zab协议来实现数据一致性,基于该协议,zk实现了一种主备模型(即 Leader Follower模型)的系统架构来保证集群中各个副本之间数据的一致性。这里的主备系统架构模型,就是指只有一台客户端(Leader)负责处理外部的写事务请求,然后 Leader客户端将数据同步到其他 Follower节点。

Zookeeper 客户端会随机的连接到 Zookeeper 集群中的一个节点,如果是读请求,就直接从当前节点中读取数据;如果是写请求,那么节点就会向 Leader 提交事务,Leader 接收到事务提交,会广播该事务,只要超过半数节点写入成功,该事务就会被提交
Zab(Zookeeper Atomic Broadcast)协议Zab(Zookeeper Atomic Broadcast)协议

就这样,客户端发送来的写请求,全部给 Leader,然后 Leader再转给 Follower。这时候需要解决两个问题:
【1】Leader服务器是如何把数据更新到所有的 Follower的;
【2】Leader服务器突然间失效了,怎么办?
因此 ZAB协议为了解决上面两个问题,设计了两种模式:
【1】消息广播模式把数据更新到所有的Follower;
【2】崩溃恢复模式Leader发生崩溃时,如何恢复;

二、消息广播模式


在 Zookeeper集群中数据副本的传递策略就是采用消息广播模式。如果你了解 2PC协议[链接]的话,理解起来就简单很多了,消息广播的过程实际上是一个简化版本的二阶段提交过程。与二阶段提交相似但是却又不同。二阶段提交的要求协调者必须等到所有的参与者全部反馈 ACK确认消息后,再发送 commit消息。要求所有的参与者要么全部成功要么全部失败。二阶段提交会产生严重阻塞问题。我们来看一下 ZAP的这个过程:ZAB协议中 Leader等待 Follower的 ACK反馈是指 “只要半数以上的Follower成功反馈即可,不需要收到全部 Follower反馈
Zab(Zookeeper Atomic Broadcast)协议
【1】Leader将客户端的 Request转化成一个 Proposal(提议)。同时为每个 proposal分配一个全局唯一ID,即ZXID
【2】Leader节点再数据写完之后,将向所有的 Follower节点发送数据广播请求(或数据复制),等待所有的 Follower节点反馈。Leader为每一个 Follower准备了一个 FIFO队列,并把 Proposal(带有 zxid的消息)发送到队列上;
【3】Follower从队列中取出消息处理完(写入本地事物日志中将 proposal写到磁盘)后,向 Leader服务器发送 ACK确认。Leader若收到 Follower的半数以上 ACK反馈。Leader就会向所有的 Follower发送 commit。即将 Leader节点上的数据同步到 Follower节点之上;
Zab(Zookeeper Atomic Broadcast)协议

Leader服务器与每个 Follower之间都有一个单独的队列进行收发消息,使用队列消息可以做到异步解耦。Leader和 Follower之间只要往队列中发送了消息即可。如果使用同步方式容易引起阻塞。性能上要下降很多。

三、崩溃恢复模式


当整个集群正在启动时,或者当 Leader节点出现网络中断崩溃等情况时,ZAB协议就会进入恢复模式并选举产生新的 Leader,当 Leader服务器选举出来后,并且集群中有过半的机器和该 Leader节点完成数据同步后(同步指的是数据同步,用来保证集群中过半的机器能够和 Leader服务器的数据状态保持一致),ZAB协议就会退出恢复模式。
当集群中已经有过半的 Follower节点完成了和 Leader状态同步以后,那么整个集群就进入了消息广播模式。这个时候,在Leader节点正常工作时,启动一台新的服务器加入到集群,那这个服务器会直接进入数据恢复模式,和 Leader节点进行数据同步。同步完成后即可正常对外提供非事务请求的处理。
【1】Zookeeper集群中为保证所有进程能够有序的顺序执行,只能是 Leader服务器接受写请求,即使是 Follower服务器接受到客户端的请求,也会转发到 Leader服务器进行处理。
【2】如果 Leader服务器发生崩溃,则 zab协议要求 Zookeeper集群进行崩溃恢复 Leader服务器选举

ZAB协议崩溃恢复要求满足如下2个要求:
【1】已经被处理的消息不能丢失当 Leader收到合法数量 Follower的 ack后,就向各个 Follower广播 commit命令,同时也会在本地执行 commit并向连接的客户端返回「成功」。但是如果各个 Follower在收到 commit命令前 Leader就挂了,导致剩下的服务器并没有执行到这条消息。
Zab(Zookeeper Atomic Broadcast)协议
Leader对事务消息发起 commit操作,该消息在 Follower1上执行了,但是 Follower2还没有收到commit,Leader就已经挂了,而实际上客户端已经收到该事务消息处理成功的回执了。所以在 zab协议下需要保证所有机器都要执行这个事务消息,必须满足已经被处理的消息不能丢失。
【2】被丢弃的消息不能再次出现当 Leader接收到消息请求生成 proposal后就挂了,其他 Follower并没有收到此proposal,因此经过恢复模式重新选了 Leader后,这条消息应跳过。 此时,之前挂了的 Leader重新启动并注册成了 Follower,他保留了被跳过消息的proposal状态,与整个系统的状态是不一致的,需要将其删除。(Leader都换代了,所以以前 Leader的 proposal失效了)。
针对崩溃恢复的两种情况分析:ZAB协议需要满足上面两种情况,就必须要设计一个 Leader选举算法,能够确保已经被 Leader提交的事务Proposal能够提交、同时丢弃已经被跳过的事务proposal。如果 Leader选举算法能够保证新选举出来的 Leader服务器拥有集群中所有机器最大 ZXID编号的事务proposal,那么就可以保证这个新选举出来的 Leader一定具有已经提交的提案。因为所有提案被 commit之前必须有超过半数的 Follower ack,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此只要有合法数量的节点正常工作,就必然有一个节点保存了所有被 commit消息的 proposal状态。
另外一个,zxid是64位,高32位是epoch编号,每经过一次 Leader选举产生一个新的 Leader,新的 Leader会将 epoch号+1,低32位是消息计数器,每接收到一条消息这个值+1,新 Leader选举后这个值重置为0。这样设计的好处在于老的 Leader挂了以后重启,它不会被选举为 Leader,因此此时它的zxid肯定小于当前新的 Leader。当老的 Leader作为 Follower接入新的 Leader后,新的 Leader会让它将所有的拥有旧的 epoch号的未被 commit的 proposal清除。

Leader服务器发生崩溃时分为如下场景:
【1】Leader在提出 proposal时未提交之前崩溃,则经过崩溃恢复之后,新选举的 Leader一定不能是刚才的 Leader。因为这个Leader存在未提交的 proposal;
【2】Leader在发送 commit消息之后,崩溃。即消息已经发送到队列中。经过崩溃恢复之后,参与选举的 Follower服务器(刚才崩溃的 Leader有可能已经恢复运行,也属于 Follower节点范畴)中有的节点已经是消费了队列中所有的 commit消息。即该 Follower节点将会被选举为最新的 Leader。剩下动作就是数据同步过程。

四、数据同步


在 Zookeeper集群中新的 Leader选举成功之后,Leader会将自身的提交的最大 proposal的事务 ZXID发送给其他的 Follower节点。Follower节点会根据 Leader的消息进行回退或者是数据同步操作。最终目的要保证集群中所有节点的数据副本保持一致

数据同步完之后,Zookeeper集群如何保证新选举的 Leader分配的 ZXID是全局唯一呢?这个就要从ZXID的设计谈起。ZXID是一个长度64位的数字,其中低32位是按照数字递增,即每次客户端发起一个proposal,低32位的数字简单加1。高32位是 Leader周期的epoch编号,至于这个编号如何产生(我也没有搞明白),每当选举出一个新的 Leader时,新的 Leader就从本地事物日志中取出ZXID,然后解析出高32位的 epoch编号,进行加1,再将低32位的全部设置为0。这样就保证了每次新选举的 Leader后,保证了ZXID的唯一性而且是保证递增的。
Zab(Zookeeper Atomic Broadcast)协议

五、ZAB协议原理


ZAB协议要求每个 Leader都要经历三个阶段,即发现同步广播
发现即要求 zookeeper集群必须选择出一个 Leader进程,同时 Leader会维护一个 Follower可用列表。客户端可以跟 Follower中的节点进行通信。
同步Leader要负责将本身的数据与 Follower完成同步,做到多副本存储。这样也是体现了 CAP中高可用和分区容错。Follower将队列中未处理完的请求消费完成后,写入本地事物日志中。
广播Leader可以接受客户端新的 proposal请求,将新的 proposal请求广播给所有的 Follower。