Zookeeper 崩溃选举之后的数据同步过程详解

文章目录

    • 概述
    • ZAB协议
      • 两个保证
    • 重要的数据结构介绍
    • 崩溃选举
    • 数据同步过程
      • leading过程
      • following过程
      • 数据同步细节

概述

在写本篇博客之前,我看了大量关于zookeeper崩溃选举之后的数据同步问题,但是大多数博客都解释的非常浅显,有些甚至有错误,根本没有深入的解释数据同步过程。所以我结合一些博客查看了zookeeper的源码,对数据同步过程有了详细的了解。

在看博客的过程中,始终有几个问题困惑着我,一直没有得到解释。

  1. zookeeper崩溃选举投票时,使用的是事务日志中的最大zxid还是应用到内存中的最大zxid?
  2. zookeeper数据同步时,follower发送给leader的数据包中的zxid,是follower事务日志中的最大zxid还是应用到内存中的最大zxid?
  3. zookeeper数据同步时,leader针对follower人发来的follower_zxid和自己的lead_zxid进行比较,从而确定followe落后情况,leader_zxid是事务日志中的最大zxid还是应用到内存中的最大zxid?
  4. zookeeper崩溃选举后,新leader如何处理只在旧leader上提交,而其他机器均没有提交的事务(即旧leader在发出commit消息之前宕机)?

回答:

  1. zookeeper崩溃选举投票时,使用的是应用到内存中的最大zxid,即lastProcessedZxid。
  2. zookeeper数据同步时,follower发送给leader的数据包中的zxid是应用到内存中的最大zxid,即lastProcessedZxid。
  3. zookeeper数据同步时,与followe_zxid进行比较的是应用到内存中的zxid,即lastProcessedZxid以及commitProposal队列(此队列保存最近提交到内存中的事务zxid)。
  4. 新leader会将旧leader未将提交的事务重新生成proposal,发送到follower节点 。目前未知

ZAB协议

Zab协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议 ,是Zookeeper保证数据一致性的核心算法。Zab借鉴了Paxos算法,但又不像Paxos那样,是一种通用的分布式一致性算法。**它是特别为Zookeeper设计的支持崩溃恢复的原子广播协议。**其核心内容即为崩溃选举和原子广播。

在Zookeeper中主要依赖Zab协议来实现数据一致性,基于该协议,zk实现了一种主备模型(即Leader和Follower模型)的系统架构来保证集群中各个副本之间数据的一致性。这里的主备系统架构模型,就是指只有一台客户端(Leader)负责处理外部的写事务请求,然后Leader客户端将数据同步到其他Follower节点。

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

两个保证

  • ZAB协议需要保证那些已经在Leader服务器上提交的事务,最终会被所有服务器提交。
  • ZAB协议需要保证丢弃那些只在leader服务器上被提出的事务。

重要的数据结构介绍

  • long lastProcessedZxid:最后一次commit的事务请求的zxid
  • LinkedList committedLog:ZooKeeper会保存最近一段时间内执行的事务请求议案,个数限制默认为500个议案。maxCommittedLog表示最大议案的zxid,minCommittedLog表示committedLog中最小议案的zxid。
  • ConcurrentMap outstandingProposals:Leader类拥有的属性,每当提出一个议案,都会将该议案存放至outstandingProposals,一旦议案被过半认同了,就要提交该议案,则从outstandingProposals中删除该议案
  • ConcurrentLinkedQueue toBeApplied:Leader类拥有的属性,每当准备提交一个议案,就会将该议案存放至该列表中,一旦议案应用到ZooKeeper的内存树中了,然后就可以将该议案从toBeApplied中删除

对于上述几个参数,整个Broadcast的处理过程可以描述为:

  • leader针对客户端的事务请求(leader为该请求分配了zxid),创建出一个议案,并将zxid和该议案存放至leader的outstandingProposals中
  • leader开始向所有的follower发送该议案,如果过半的follower回复OK的话,则leader认为可以提交该议案,则将该议案从outstandingProposals中删除,然后存放到toBeApplied中
  • leader对该议案进行提交,会向所有的follower发送提交该议案的命令,leader自己也开始执行提交过程,会将该请求的内容应用到ZooKeeper的内存树中,然后更新lastProcessedZxid为该请求的zxid,同时将该请求的议案存放到上述committedLog,同时更新maxCommittedLog和minCommittedLog
  • leader就开始向客户端进行回复,然后就会将该议案从toBeApplied中删除

崩溃选举

zookeeper崩溃选举的过程就不在此叙述了,其主要思想就是选取集群中zxid(lastProcessedZxid)最大的节点称为leader,如果zxid相同,则比较myid。
FastLeaderElection 更新选票:
Zookeeper 崩溃选举之后的数据同步过程详解_第1张图片
Zookeeper 崩溃选举之后的数据同步过程详解_第2张图片
Zookeeper 崩溃选举之后的数据同步过程详解_第3张图片
Zookeeper 崩溃选举之后的数据同步过程详解_第4张图片
所以由上述函数调用可知,使用的是lastProcessedZxid。

崩溃选举源代码分析:
https://blog.csdn.net/MuErHuoXu/article/details/85864535

数据同步过程

leading过程

  • 当新leader选举成功之后,其会进行leading状态,调用Leader.lead()函数。
  • Leader从快照和事务日志中加载数据。zk.loadData();其会判断内存数据库是否已经加载:zkDb.isInitialized(),如果已经加载,不进行二次加载。否则调用zkDb.loadDataBase(),将磁盘上的快照文件加载入内存中,并且执行事务日志中所有大于快照文件中的zxid的事务(注意:此处是不需要重新加载内存数据库的,但是对于宕机重启的节点,其会调用loadDataBase()恢复数据,此过程会执行事务日志的所有记录,尽管有些日志并没有被commit!!这是比较重要的一个点)。
  • leader创建一个线程,接收Follower/Observer的连接。阻塞等待超过一半的(Follower和Observer)连接,并接收类型为Leader.FOLLOWERINFOLeader.OBSERVERINFO的数据包。解析old_epoch,生成new_epoch(所有old_epoch中最大的一个加1)。创建类型为Leader.LEADERINFO的数据包,将new_epoch发送给Follower/Observer。
  • 等待超过一半的(Follower和Observer)获取了new_epoch,并且返回了类型为Leader.ACKEPOCH的数据包,设置当前新的朝代epoch,解析获得Follower或Observer的lastProcessedZxid,进行数据同步(数据同步细节见下节)
  • 。数据同步完成之后,创建类型为Leader.NEWLEADER数据包,发送给Follower/Observer。
  • 等待超过一半的(Follower或Observer)返回类型为Leader.ACK的数据包,说明数据同步成功。创建类型为Leader.UPTODATE的数据包,发给 follower/Observer,告知其可以对外提供服务了。
  • 启动对外服务;

following过程

  • 当选举完成后,follower会进入FOLLOWING 状态,其会调用Follower.followLeader()函数。
  • follower寻找leader地址,并与其建立连接。
  • follower获取内存中最后执行的zxid,即lastProcessedZxid,创建类型为Leader.FOLLOWERINFO的数据包(这里说的是Follower,所以是Leader.FOLLOWERINFO),发送给leader。
  • 等待读取leader传输的请求包,该请求包的类型为Leader.LEADERINFO,从请求包中解析出新的epoch。创建请类型为Leader.ACKEPOCH的数据包,并且传输处lastProcessedZxid,准备进行数据同步。
  • 数据同步完成后,读取到Leader.NEWLEADER,说明数据同步完毕。本地生成新的数据快照。向Leader传输一个请求包,包的类型为Leader.ACK,表示数据已同步完毕。
  • 读取到类型为Leader.UPTODATE的数据包,说明已经可对外提供服务。向Leader传输一个请求包,包的类型为Leader.ACK。表示Follower启动对外服务。

数据同步细节

数据同步源代码分析:
https://blog.csdn.net/dk243553650/article/details/104099503
https://blog.csdn.net/weixin_33826609/article/details/91389764
数据同步细节上述博客都有较好分析,但是都忽略了old leader的未提交事务的处理情况

Leader对于已经提交的事务的同步

  1. 由于崩溃选举是,使用lastProcessedZxid进行比较,所以新leader必然拥有最大的lastProcessedZxid,所以拥有最新的提交事务。
  2. 在LearnerHandler中获取follower或者observer的lastProcessedZxid与leader的minCommittedLog和maxCommittedLog进行比较(也会和leader的lastProcessedZxid进行比较)。
  3. 如果follower或者observer的lastProcessedZxid和leader的lastProcessedZxid相同,则两个节点的数据状态相同,则发送空的DIFF指令(发送DIFF之后,不发送proposal和commit)。
  4. 如果follower或者observer的lastProcessedZxid在leader的minCommittedLog和maxCommittedLog之间。发送DIFF指令,在将从follower或者observer的lastProcessedZxid开始到maxCommittedLog结束的这部分事务,生成proposal和commit,发送给follower或者observer。
  5. 上述可能存在一个问题:即follower或者observer的lastProcessedZxid虽然在CommittedLog之间,但是在CommittedLog中没有找到follower或者observer的lastProcessedZxid对应的事务,即这个zxid是leader所没有的。这是先发送TRUNC指令,对事务进行回滚,再按照4进行处理。
  6. 如果follower或者observer的lastProcessedZxid大于maxCommittedLog,则发送TRUNC指令,对事务进行回滚。
  7. 如果follower或者observer的lastProcessedZxid小于minCommittedLog,则发送SNAP指令,则直接采用快照的方式来恢复。

Leader对于未提交的事务进行同步

上述的过程在很多博客中都能见到详细解释,但是对于新Leader中的未提交事务(只写入事务日志,但是并没有提交至内存)进行同步却没有说明。

由上面的数据结构内容可知,outstandingProposals数据结构储存的是propose后还未commit的事务,toBeApplied储存的是commit了但是还未真正执行的事务。所以对这两个数据结构中的数据进行同步。

  1. 从leader的toBeApplied数据中将大于follower或者observer的lastProcessedZxid的事务进行propose和commit(toBeApplied是已经被确认为提交的)
  2. 从leader的outstandingProposals中将大于follower或者observer的lastProcessedZxid的事务进行propose,但是不commit(outstandingProposals是还没被被确认为提交的)

经过思考之后,我觉得Leader对于未提交的事务进行同步似乎有问题,因为崩溃选举之后,follower转变成leader时outstandingProposals和toBeApplied数据结构为空,所以上述过程是针对Leader正常允许状态下,有新follower加入进行数据同步的过程。

看到一些博客(http://www.jasongj.com/zookeeper/fastleaderelection/)说崩溃选举的新Leader会根据未提交事务的proposal是否存在于过半节点的中来决定是否commit此事务,但是我在源代码中没有找到响应的代码,不知道对的还是错的,若有人知道,请指点!

参考博客:
https://yq.aliyun.com/articles/62555

你可能感兴趣的:(zookeeper)