本文主要讲述Zookeeper的内部原理以及ZAB协议,Zookeeper算是大数据中的一个协做框架,比较简单,本文应该是Zookeeper部分的最后一篇文章。关注专栏《破茧成蝶——大数据篇》,查看更多相关的内容~html
目录node
1.1 节点类型服务器
1.3 监听器session
2、ZAB协议异步
2.1 ZAB协议是什么分布式
1、Zookeeper的内部原理
1.1 节点类型
Zookeeper的节点类型能够分为两种:持久型和短暂型。持久型指当客户端与服务器断开链接后,该节点不会删除;短暂型指当客户端与服务器断开链接后,该节点也会随之删除。
1.2 Stat结构体
Stat结构体在《二11、Zookeeper的命令行操做》中已经有提到过了,可是这里得再次不厌其烦的说一下。
(1)cZxid:建立节点的事务zxid。每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。事务ID是ZooKeeper中全部修改总的次序。每一个修改都有惟一的zxid,若是zxid1小于zxid2,那么zxid1在zxid2以前发生。
(2)ctime:znode被建立的毫秒数(从1970年开始)。
(3)mZxid:znode最后更新的事务zxid。
(4)mtime:znode最后修改的毫秒数(从1970年开始)。
(5)pZxid:znode最后更新的子节点zxid。
(6)cversion:znode子节点变化号,znode子节点修改次数。
(7)dataVersion:znode数据变化号。
(8)aclVersion:znode访问控制列表的变化号。
(9)ephemeralOwner:若是是临时节点,这个是znode拥有者的session id。若是不是临时节点则是0。
(10)dataLength:znode的数据长度。
(11)numChildren:znode子节点数量。
1.3 监听器
一、首先在main()线程中建立Zookeeper客户端,这时会同时建立两个线程:一个用于网络链接通讯(A),一个用于监听(B)。
二、经过A线程将注册的监听事件发送个Zookeeper,这时Zookeeper会将注册的监听事件添加到注册监听器列表。
三、Zookeeper监听到有数据或者路径等等的变化,就会将这个消息发送给B线程。
1.4 写数据流程
一、客户端向Zookeeper的服务器上写数据,首先会发送一个写请求。
二、若是接收到该请求的服务器(A)不是Leader服务器,那么它会将这个请求转发给Leader服务器,这时Leader服务器会将请求广播给集群内的其余服务器。各个服务器会将写请求加入待写队列,并向Leader服务器发送成功的信息。
三、当Leader服务器收到半数以上的Follower服务器的成功信息后,说明该写操做能够执行。这是Leader会向各个Follower发送提交信息,各个Follower收到信息后,会落实队列里面的写请求,此时写入成功。
四、服务器A通知客户端数据写入成功。
1.5 Zookeeper的选举机制
选举机制遵循半数机制,即:集群中半数以上机器存活,集群就是可用状态,因此Zookeeper适合安装奇数台服务器。Zookeeper虽然在配置文件中并无指定Master和Slave。可是,Zookeeper工做时,是有一个节点为Leader,其余则为Follower,Leader是经过内部的选举机制临时产生的。例若有五台服务器(A-E)组成的Zookeeper集群,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是同样的。假设这些服务器依次启动,那么会发生下面的状况:
一、服务器A启动,发起一次选举。服务器A投本身一票。此时服务器A票数一票,不够半数以上(3票),选举没法完成,服务器A状态保持为LOOKING。
二、服务器B启动,再发起一次选举。服务器A和B分别投本身一票并交换选票信息:此时服务器A发现服务器B的ID比本身目前投票推举的(服务器A)大,更改选票为推举服务器B。此时服务器A票数0票,服务器B票数2票,没有半数以上结果,选举没法完成,服务器A、B状态保持LOOKING。
三、服务器C启动,发起一次选举。此时服务器A和B都会更改选票为服务器C。这次投票结果:服务器A为0票,服务器B为0票,服务器C为3票。此时服务器C的票数已经超过半数,服务器C当选Leader。服务器A、B更改状态为FOLLOWING,服务器C更改状态为LEADING。
四、服务器D启动,发起一次选举。此时服务器A、B、C已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器C为3票,服务器D为1票。此时服务器D服从多数,更改选票信息为服务器C,并更改状态为FOLLOWING。
五、服务器E启动,过程同4。
2、ZAB协议
2.1 ZAB协议是什么
ZAB协议的全称是Zookeeper Atomic Broadcast(Zookeeper原子广播)。Zookeeper是经过ZAB协议来保证分布式事务的最终一致性。ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议,是Zookeeper保证数据一致性的核心算法。ZAB借鉴了Paxos算法,但又不像Paxos算法那样,是一种通用的分布式一致性算法。它是特别为Zookeeper设计的支持崩溃恢复的原子广播协议。
在Zookeeper中主要依赖ZAB协议来实现数据一致性,基于该协议,Zookeeper实现了一种主备模型(即Leader和Follower模型)的系统架构来保证集群中各个副本之间数据的一致性。这里的主备系统架构模型,就是指只有一台客户端(Leader)负责处理外部的写事务请求,而后Leader客户端将数据同步到其余Follower节点。Zookeeper客户端会随机的连接到Zookeeper集群中的一个节点,若是是读请求,就直接从当前节点中读取数据;若是是写请求,那么节点就会向Leader提交事务,Leader接收到事务提交,会广播该事务,只要超过半数节点写入成功,该事务就会被提交。
ZAB协议的特性:
一、ZAB协议须要确保那些已经在Leader服务器上提交的事务最终被全部的服务器提交。
二、ZAB协议须要确保丢弃那些只在Leader上被提出而没有被提交的事务。
2.2 ZAB协议的做用
一、当主进程出现异常的时候,整个Zookeeper集群依旧可以正常工做。
二、使用一个Leader来接收并处理客户端的事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变动以事务proposal(事务提议)的形式广播到全部的Follower进程上去。
三、保证一个全局的变动序列被顺序引用。Zookeeper是一个树形结构,不少操做都要先检查才能肯定是否能够执行,为了保证这一点,ZAB要保证同一个Leader发起的事务要按顺序被请求,同时还要保证只有先前Leader的事务被请求以后,新选举出来的Leader才能再次发起事务。
2.3 ZAB协议的原理
ZAB协议要求每一个Leader都要经历三个阶段:发现、同步、广播。
发现阶段要求Zookeeper集群必须选举出一个Leader,同时Leader会维护一个Follower可用客户端列表。未来客户端能够和这些Follower节点进行通讯。同步阶段Leader要负责将自己的数据与Follower完成同步,作到多副本存储。Follower将队列中未处理完的请求消费完成后,写入本地事务日志中。广播阶段Leader能够接受客户端新的事务Proposal请求,将新的Proposal请求广播给全部的Follower。
ZAB协议定义了事务请求的处理方式:全部的事务请求必须由一个全局惟一的服务器来协调处理,这样的服务器被叫作Leader服务器。其余剩余的服务器则是Follower服务器。Leader服务器负责将一个客户端事务请求,转换成一个事务Proposal,并将该Proposal分发给集群中全部的Follower服务器,也就是向全部 Follower节点发送数据广播请求。分发以后Leader服务器须要等待全部Follower服务器的反馈,在ZAB协议中,只要超过半数的Follower服务器进行了正确的反馈后,那么Leader就会再次向全部的Follower服务器发送Commit消息,要求其将上一个事务proposal进行提交。这也就是上文中1.4提到的写数据流程。
2.4 ZAB协议的工做
当整个集群启动过程当中,或者当Leader服务器出现网络中弄断、崩溃退出或重启等异常时,ZAB协议就会进入崩溃恢复模式,选举产生新的Leader。当选举产生了新的Leader,同时集群中有过半的机器与该Leader服务器完成了状态同步(即数据同步)以后,ZAB协议就会退出崩溃恢复模式,进入消息广播模式。这时,若是有一台遵照ZAB协议的服务器加入集群,由于此时集群中已经存在一个Leader服务器在广播消息,那么该新加入的服务器自动进入恢复模式:找到Leader服务器,而且完成数据同步。同步完成后,做为新的Follower一块儿参与到消息广播流程中。
当Leader出现崩溃退出或者机器重启,亦或是集群中不存在超过半数的服务器与Leader保存正常通讯,ZAB协议就会再一次进入崩溃恢复,发起新一轮Leader选举并实现数据同步。同步完成后又会进入消息广播模式,接收事务请求。在整个消息广播中,Leader会将每个事务请求转换成对应的proposal来进行广播,而且在广播事务Proposal以前,Leader服务器会首先为这个事务Proposal分配一个全局单递增的惟一ID,称之为事务ID(即zxid),因为ZAB协议须要保证每个消息的严格的顺序关系,所以必须将每个proposal按照其zxid的前后顺序进行排序和处理。
2.4.1 消息广播
消息广播的步骤以下:
一、客户端发起一个写操做请求。
二、Leader服务器将客户端的请求转化为事务Proposal提案,同时为每一个Proposal分配一个全局的ID,即zxid。
三、Leader服务器为每一个Follower服务器分配一个单独的队列,而后将须要广播的Proposal依次放到队列中去,而且根据FIFO策略进行消息发送。
四、Follower接收到Proposal后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向Leader反馈一个Ack响应消息。
五、Leader接收到超过半数以上Follower的Ack响应消息后,即认为消息发送成功,能够发送commit消息。
六、Leader向全部Follower广播commit消息,同时自身也会完成事务提交。Follower接收到commit消息后,会将上一条事务提交。
Zookeeper采用ZAB协议的核心,就是只要有一台服务器提交了Proposal,就要确保全部的服务器最终都能正确提交Proposal。Leader服务器与每个Follower服务器之间都维护了一个单独的FIFO消息队列进行收发消息,使用队列消息能够作到异步解耦。Leader和Follower之间只须要往队列中发消息便可。若是使用同步的方式会引发阻塞,性能要降低不少。
2.4.2 崩溃恢复
一旦Leader服务器出现崩溃或者因为网络缘由致使Leader服务器失去了与过半Follower的联系,那么就会进入崩溃恢复模式。在ZAB协议中,为了保证程序的正确运行,整个恢复过程结束后须要选举出一个新的Leader服务器。
ZAB协议崩溃恢复要求知足两个要求:一、确保已经被Leader提交的Proposal必须最终被全部的Follower服务器提交。二、确保丢弃已经被Leader提出的可是没有被提交的Proposal。根据上述要求ZAB协议须要保证选举出来的Leader知足如下条件:一、新选举出来的Leader不能包含未提交的Proposal。即新选举的Leader必须都是已经提交了Proposal的Follower服务器节点。二、新选举的Leader节点中含有最大的zxid。
2.5 ZAB数据同步
一、完成Leader选举后新的Leader具备最高的zxid,在正式开始工做以前(接收事务请求,而后提出新的Proposal),Leader服务器会首先确认事务日志中的全部的Proposal是否已经被集群中过半的服务器Commit。
二、Leader服务器须要确保全部的Follower服务器可以接收到每一条事务的Proposal,而且能将全部已经提交的事务Proposal应用到内存数据中。等到Follower将全部还没有同步的事务Proposal都从Leader服务器上同步过来而且应用到内存数据中之后,Leader才会把该Follower加入到真正可用的Follower列表中。
在ZAB的事务编号zxid设计中,zxid是一个64位的数字。其中低32位能够当作一个简单的单增计数器,针对客户端每个事务请求,Leader在产生新的Proposal事务时,都会对该计数器加1。而高32位则表明了Leader周期的epoch编号。epoch编号能够理解为当前集群所处的年代或者周期。每次Leader变动以后都会在epoch的基础上加1,这样旧的Leader崩溃恢复以后,其余Follower也不会听它的,由于Follower只服从epoch最高的Leader命令。每当选举产生一个新的Leader,就会从这个Leader服务器上取出本地事务日志中最大编号Proposal的zxid,并从zxid中解析获得对应的epoch编号,而后再对其加1,以后该编号就做为新的epoch值,并将低32位数字归零,由0开始从新生成zxid。ZAB协议经过epoch编号来区分Leader变化周期,可以有效避免不一样的Leader错误的使用了相同的zxid编号提出了不同的Proposal的异常状况。基于以上策略当一个包含了上一个Leader周期中还没有提交过的事务Proposal的服务器启动时,当这台机器加入集群中,以Follower角色连上Leader服务器后,Leader服务器会根据本身服务器上最后提交的Proposal来和Follower服务器的Proposal进行比对,比对的结果确定是Leader要求Follower进行一个回退操做,回退到一个确实已经被集群中过半机器Commit的最新Proposal。
到这本文基本上接近尾声了,这篇文章理论描述居多,可能会比较枯燥,大家有什么问题,欢迎留言,让我看看大家都有哪些问题~