ZOOKEEPER核心原理解析

ZAB协议简介

       Zookeeper并没有采用完全的Paxos算法,而是采用了一种称为Zookeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)。ZAB协议是专门为Zookeeper设计的一种崩溃恢复的原子协议。Zookeeper中使用leader节点来处理集群中所有的事务请求,并采用ZAB的原子广播协议将数据同步到所有的follower节点中,完成数据的同步过程。ZK的客户端会随机连接到ZK集群的一个节点上,如果是读请求则当前节点能够自己处理这个请求,如果是事务请求(增删改)且当前节点不是leader节点那么这个请求需要路由到leader节点来处理,leader节点采用类型2PC提交的方式来完成事务请求,leader 提交事务和广播事务,只要有超过半数节点写入成功,该写请求就会被提交(类 2PC 协议)。

ZAB协议需要解决的几个问题
       主从架构下(leader和多个follower),leader 崩溃的时候,数据一致性怎么保证?选举 leader 的时候,整个集群无法处理写请求的,如何快速进行 leader 选举?所以ZAB协议重要的就是:

  1. 消息广播协议(leader向其他节点广播事务)
  2. leader选举(快速选举过程fastleaderelection,集群刚启动时,leader崩溃或leader与集群中超过一半的节点断连后)
  3. leader重新选举后,如何进行数据同步到一致状态。

2PC提交理论

        2PC即为两阶段提交协议,是计算网络中尤其是数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务性处理操作的过程中能够保持原子性和一致性而设计的一种算法。通常两阶段提交协议被认为是一种强一致性的协议。
阶段一:

       1、事务询问:事务协调者向所有的参与者发送事务内容,询问参与者是否能够执行事务的提交操作
       2、事务执行:各个参与者节点执行事务操作(未提及到数据库),并将Undo和Redo信息记入事务日志中
       3、各个参与者向协调者返回事务询问的响应结果:如果参与者能够成功执行事务操作那么就返回yes,如果不能正确执行则返回NO。
阶段二:事务提交阶段
       执行事务提交,假设协调者从所有的参与者都收到yes的返回,那么就会执行事务提交。
       1、发送commit请求:协调者向所有的参与者发送commit提交事务请求
       2、事务提交:参与者接受到commit请求后,会正式执行事务操作,并完成提交之后释放在整个分布式事务执行期间占用的资源。
       3、反馈事务提交结果:参与者反馈事务提交的执行结果,向协调者返回ACK
       4、完成事务:协调者接受到所有参与者反馈的ACK消息后,完成事务
中断事务
       假设任何一个参与者向协调者发送No的响应,或者在等待超时期间没有收到任何的反馈数据,那么就会中断事务。
       1、发送事务回滚:协调者向所有的参与者节点发送rollback请求。
       2、事务回滚:参与者收到rollback请求后,会利用其在阶段一中的undo日志进行回滚,并在完成回滚之后释放资源。
       3、反馈事务回滚结果:参与者在完成事务回滚后,向协调者发送ACK消息
       4、中断事务:协调者收到所有参与者反馈的ACK消息后,完成事务的中断
在这里插入图片描述
在这里插入图片描述
2PC提交的优缺点:
       优点:原理简单、实现方便
       缺点:同步阻塞、单点问题、脑裂和太过保守
同步阻塞: 2PC提交存在的最明显的缺点就是同步阻塞,他极大的限制了分布式系统的性能。在二阶段提交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,也就是说,各个参与者在等待其他参与者响应的过程中,将无法进行其他任何操作。
单点问题: 协调者的角色在整个二阶段提交协议中起到了非常重要的作用,。一旦协调者出现问题,那么整个二阶段提交流程将无法运转。如果协调者在二阶段提交中出现异常,那么其他参与者将会一直处于锁定事务资源的状态中,无法继续完成事务操作。
数据不一致: 在二阶段提交协议的阶段二中,即执行事务提交的时候,当协调者向所有的参与者发送commit请求之后,发生局部网络异常或者是协调者尚未发送完commit之前发送自身崩溃的情况,导致最终只有部分参与者接收到commit命令,于是收到commit请求的的参与者进行了事务提交操作,其他没有收到commit请求的参与者无法进行事务的提交,这个时候整个集群就出现了数据不一致的情况。
太过保守: 二阶段提交协议没有设计容错机制,任何一个节点的异常都有可能造成整个事务的失败。

事务ID的概念

       在ZAB协议中有一个事务编号ZXID的概念,ZXID是一个64位的数字其中低32位是一个递增的计数器,针对客户端的每一个事务请求,计数器加一。高32位则代表leader的epoch值,每一次新选举出一个leader节点,就从leader节点中读取最新的ZXID,解析出epoch的值然后加一作为最新的epoch值,低32部分从0开始计数。

ZAB协议的两种基本模式:崩溃恢复和消息广播

       当系统启动的时候或leader服务器异常的时候,就需要进入故障恢复,将会开启新一轮的leader选举,新的leader节点需要与过半的follower节点(n+1个节点)进行数据同步,数据同步完成则推出恢复模式。

消息广播

       当集群中已经有过半的follower与leader服务器完成了状态同步,那么整个zk集群就可以进入消息广播模式了。如果集群中的其他节点收到客户端地事务请求,那么这些非leader服务器会首先将这个事务请求转发给leader服务器。
ZAB协议的消息广播过程使用的是一个原子性协议,类似2PC协议(2PC协议前面已经介绍了),针对每一个客户端的事务性请求(增删改),leader节点会生成一个事务Proposal(事务投票),并将其发送给集群中其他节点,然后再收集各个节点的投票反馈数据。如下图所示ZAB协议的消息广播过程示意图。
在这里插入图片描述
流程步骤:
       1、Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,称为ZXID。
       2、Leader节点通过有FIFO特性的TCP协议来向各个follower节点来发送Proposal。
       3、当follower服务器接收到这个事务Proposal后,会先将其以事务日志的形式固化到磁盘中,再成功写入磁盘后会返回一个ACK给leader节点。
       4、当leader节点收到超过半数的ack后(ZK节点一般是2n+1个节点,超时半数就是n+1个节点,这里也是和2PC提交协议的不同点)就会广播一个commit请求到各个follower,通知各个follower提交事务。假设当个是3个节点,leader节点像两个follower节点发送Proposal后,leader本身也会将Proposal写入磁盘,其实我们只需要一个follower节点返回ACK就可以广播commit。
       5、Follower节点收到commit后完成事务的提交。

       ZAB协议和2PC协议最大的区别在于ZAB协议移除了中断逻辑,follower要么返回ACK给leader要么丢弃leader。

崩溃恢复

       ZK集群在什么情况下进入崩溃恢复状态:leader服务器崩溃;网络原因造成leader节点和过半的follower节点失去联系。
       已经提交的Proposal不丢失?
       ZAB协议规定了如果一个事务Proposal在一台机器上执行成功,那么在超过半数的机器上执行成功,哪怕是出现了异常。ZAB协议需要确保那些已经在leader上执行成功的事务最终被所有的服务器都提交成功。假设一个事务已经有超过半数的机器上执行成功,并且得到超过半数的ACK,但是在commit消息发送成功前,leader机器挂掉了,如下图所示
在这里插入图片描述
       假设在leader将commit成功发送到server2,server3没有接受到commit,那么在崩溃恢复完成后server2将最新的数据同步到server3上面,达到数据的一致性。
ZAB协议的恢复策略:
       1、leader的选择算法会选择server2为leader节点(后面的选举算法会详细介绍为什么选择server2作为leader)。
       2、新的leader将自己事务中最高的事务信息同步到follower节点
已经丢弃的Proposal不能再出现
       当leader生成proposal后就挂了其他的follower都没有收到这个proposal,因此在重新选举leader后这条消息被跳过了,此时刚刚挂掉的leader节点有恢复了重新注册成follower, 他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,需要将其删除。Zab 通过巧妙的设计 zxid 来实现这一目的。一个 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选择算法

ZK集群启动的时候leader选举

       ZK集群在执行leader选举的前提条件是是集群的机器数量至少两台。常规条件下,ZK的机器有三台机器。每一个机器上myid从1开始编码,myid=1称为机器1。当机器1启动的时候是无法完成选择的,当机器2启动的时候就可以开始进行leader的选举。
       1、每个机器都发出一个投票,出事情况下,每个机器都选择自己作为leader,并将投票信息发送到整个集群中,发送的数据有myid和ZXID。此时机器1的投票信息为(1,0)机器2的投票信息为(2,0)
       2、介绍集群中各个服务器的投票信息。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
       3、处理投票信息:处理投票的规则如下:先检查ZXID将ZXID较大的值选举为leader节点;如果ZXID相同就比较myid,myid的值越大优先级越高。对于机器1来说接受到投票消息是(2,0),显然ZXID都等于0,2>1那么机器1更新自己的投票信息为(2,0)然后重更投票,机器2上收到的投票为(1,0)限制机器2不需要更改自己的投票信息,仅仅只需要像集群中发送上一次的投票信息(2,0)
       4、统计投票数据。果有机器获得了过半的票数,此时便认为已经选举出了leader节点。
       5、改变机器的状态:确定了leader后,每一个机器都是更新自己的状态,如果是follower那么就变更为following,如果是leadern那么就变更为leading。
       一般ZK机器选举出leader节点后就不会变化,如前面叙述的状态,机器3加进来的时候作为一个follower节点,不会再去选举leader。

服务器运行时期的Leader选举

       在Zookeeper运行期间,Leader与非Leader服务器各司其职,即便当有非Leader服务器宕机或新加入,此时也不会影响Leader,但是一旦Leader服务器挂了,那么整个集群将暂停对外服务,进入新一轮Leader选举,其过程和启动时期的Leader选举过程基本一致。假设正在运行的有Server1、Server2、Server3三台服务器,当前Leader是Server2,若某一时刻Leader挂了,此时便开始Leader选举。选举过程如下
  (1) 变更状态。Leader挂后,余下的非Observer服务器都会讲自己的服务器状态变更为LOOKING,然后开始进入Leader选举过程。
  (2) 每个Server会发出一个投票。在运行期间,每个服务器上的ZXID可能不同,此时假定Server1的ZXID为123,Server3的ZXID为122;在第一轮投票中,Server1和Server3都会投自己,产生投票(1, 123),(3, 122),然后各自将投票发送给集群中所有机器。
  (3) 接收来自各个服务器的投票。与启动时过程相同。
  (4) 处理投票。与启动时过程相同,此时,Server1将会成为Leader。
  (5) 统计投票。与启动时过程相同。
(6) 改变服务器的状态。与启动时过程相同。
以上所有内容来自于从《Paxos到Zookeeper分布式一致性原理与实践》。这里只是将相关知识点整理在一起

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值