ZooKeeper的工做原理

 ZooKeeper是一个分布式的应用程序协调服务php

 

2 ZooKeeper的工做原理

Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫作Zab(Zookeeper Atomic Broadcast)协议。Zab协议有两种模式,它们分别是恢复模式(recovery选主) 广播模式(broadcast同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了leader状态同步以 后,恢复模式就结束了。状态同步保证了leaderServer具备相同的系统状态node

 

 1ZooKeeper数据模型算法

相似于一个标准的文件系统具备层次关系的数据结构设计模式

每一个子目录项如NameService都被称做为znode服务器

ZNode根据其自己的特性,能够分为下面两类网络

Regular ZNode: 常规型ZNodesession

Ephemeral ZNode: (ɪ'fem(ə)r(ə)l)(临时的)类型的目录节点不能有子节点目录。数据结构

Zookeeper的客户端和服务器通讯采用长链接方式,每一个客户 端和服务器经过心跳来保持链接,这个链接状态称为session,若是znode是临时节点,这个session失效,znode也就删除了。(3s/一次,200)异步

若是Client由于TimeoutZookeeper Server失去链接,client处在CONNECTING状态,会自动尝试再去链接Server,若是在session有效期内再次成功链接到某个Server,则回到CONNECTED状态。分布式

 

2ZooKeeper Watch

 

    Zookeeper从设计模式的角度来看,是一个基于观察者设计模式设计的。简单来讲就是

 Client能够在某个ZNode上设置一个Watcher,来WatchZNode上的变化。若是该ZNode上有相应的变化,就会触发这个Watcher,把相应的事件通知给设置WatcherClient。须要注意的是,ZooKeeper中的Watcher是一次性的,即触发一次就会被取消,若是想继续Watch的话,须要客户端从新设置Watcher

 

三、 ZooKeeper特性 

 

   读、写(更新)模式

 

  ZooKeeper集群中,读能够从任意一个ZooKeeper Server写的请求会先ForwarderLeader,而后由Leader来经过ZooKeeper中的原子广播协议,将请求广播给全部的FollowerLeader收到一半以上的写成功的消息后,就认为该写成功了,就会将该写进行持久化,并告诉客户端写成功了。

 

   FIFO
对于每个ZooKeeper客户端而言,全部的操做都是遵循FIFO顺序的,这一特性是由下面两个基本特性来保证的:一是ZooKeeper ClientServer之间的网络通讯是基于TCPTCP保证了Client/Server之间传输包的顺序;二是ZooKeeper Server执行客户端请求也是严格按照FIFO顺序的。

了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。全部的提议(proposal)都在被提出的时候加上了 zxid。实现中zxid是一个64位的数字,它高32位是 用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新 的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

 

 ZooKeeper典型应用场景

  1. 名字服务(NameService) 

每一个ZNode均可以由其路径惟一标识,路径自己也比较简洁直观,另外ZNode上还能够存储少许数据,这些都是实现统一的NameService的基础。经过简单的名字,访问对应的服务器集群。

 

  1. 配置管理(Configuration Management) 

 

 

 

:分布式互斥锁 

在传统的应用程序中,线程、进程的同步,均可以经过操做系统提供的机制来完成。可是在分布式系统中,多个进程之间的同步,操做系统层面就无能为力了。

zookeeper中,并无JAVA里同样有Synchronized或者是ReentrantLock机制来实现锁机制,可是在zookeeper中,实现起来更简单:咱们能够讲将zk的一个数据节点表明一个锁,当多个客户端同时调用create()节点建立节点的时候,zookeeper会保证只会有一个客户端建立成功,那么咱们就可让这个建立成功的客户端让其持有锁,而其它的客户端则注册Watcher监听当持有锁的客户端释放锁后,监听的客户端就会收到Watcher通知,而后再去试图获取锁,这样反复便可。

Zookeeper的三种角色:

1.leaderfollower 

 

      ZooKeeper须要在全部的服务(能够理解为服务器)中选举出一个Leader,而后让这个Leader来负责管理集群。此时,集群中的其它服务器则 成为此LeaderFollower。而且,当Leader故障的时候,须要ZooKeeper可以快速地在Follower中选举出下一个 Leader。这就是ZooKeeperLeader机制,下面咱们将简单介绍在ZooKeeper中,Leader选举(Leader Election)是如何实现的。 

此操做实现的核心思想是:首先建立一个EPHEMERAL目录节点,例如“/election”。而后。每个ZooKeeper服务器在此目录 下建立一个SEQUENCE|EPHEMERAL类型的节点,例如“/election/n_”。在SEQUENCE标志下,ZooKeeper将自动地 为每个ZooKeeper服务器分配一个比前一个分配的序号要大的序号。此时建立节点的ZooKeeper服务器中拥有最小序号编号的服务器将成为 Leader

在实际的操做中,还须要保障:当Leader服务器发生故障的时候,系统可以快速地选出下一个ZooKeeper服务器做为Leader。一个简 单的解决方案是,让全部的follower监视leader所对应的节点。当Leader发生故障时,Leader所对应的临时节点将会自动地被删除,此 操做将会触发全部监视Leader的服务器的watch。这样这些服务器将会收到Leader故障的消息,并进而进行下一次的Leader选举操做。但 是,这种操做将会致使从众效应的发生,尤为当集群中服务器众多而且带宽延迟比较大的时候,此种状况更为明显。

Zookeeper中,为了不从众效应的发生,它是这样来实现的:每个followerfollower集群中对应的比本身节点序号小一 号的节点(也就是全部序号比本身小的节点中的序号最大的节点)设置一个watch。只有当follower所设置的watch被触发的时候,它才进行 Leader选举操做,通常状况下它将成为集群中的下一个Leader。很明显,此Leader选举操做的速度是很快的。由于,每一次Leader选举几 乎只涉及单个follower的操做

2.Observer

      observer的行为在大多数状况下与follower彻底一致, 可是他们不参加选举和投票, 而仅仅接受(observing)选举和投票的结果.

Zookeeper集群,选举机制

 

 

zookeeper选举机制

FastLeaderElection算法经过异步的通讯方式来收集其它节点的选票,同时在分析选票时又根据投票者的当前状态来做不一样的处理,以加快Leader的选举进程。    
    每一个在zookeeper服务器启动先读取当前保存在磁盘的数据,zookeeper中的每份数据都有一个对应的id值,这个值是依次递增的;换言之,越新的数据,对应的ID值就越大。 
    在读取数据完毕以后,每一个zookeeper服务器发送本身选举的leader,这个协议中包含了如下几部分的数据: 
1)、所选举leader的id(就是配置文件中写好的每一个服务器的id) ,在初始阶段,每台服务器的这个值都是本身服务器的id,也就是它们都选举本身为leader。 
2)、服务器最大数据的id,这个值大的服务器,说明存放了更新的数据。 
3)、逻辑时钟的值,这个值从0开始递增,每次选举对应一个值,也就是说:若是在同一次选举中,那么这个值应该是一致的,逻辑时钟值越大,说明这一次选举leader的进程更新。 
4)、本机在当前选举过程当中的状态,有如下几种:LOOKING,FOLLOWING,OBSERVING,LEADING 

    每台服务器将本身服务器的以上数据发送到集群中的其余服务器以后,一样的也须要接收来自其余服务器的数据,它将作如下的处理: 
A、若是所接收数据服务器的状态仍是在选举阶段(LOOKING 状态),那么首先判断逻辑时钟值,又分为如下三种状况: 
a) 若是发送过来的逻辑时钟大于目前的逻辑时钟,那么说明这是更新的一次选举,此时须要更新一下本机的逻辑时钟值,代码以下: 

if (n.epoch > logicalclock) { logicalclock = n.epoch; recvset.clear(); if(totalOrderPredicate(n.leader, n.zxid,getInitId(), getInitLastLoggedZxid())) updateProposal(n.leader, n.zxid); else updateProposal(getInitId(),getInitLastLoggedZxid()); sendNotifications();


其中的totalOrderPredicate函数就是根据发送过来的封包中的leader id,数据id来与本机保存的相应数据进行判断的函数(首先看数据id,数据id大者胜出;其次再判断leader id,leader id大者胜出),返回true则调用updateProposal函数更新数据。 
b) 发送过来数据的逻辑时钟小于本机的逻辑时钟 
说明对方在一个相对较早的选举进程中,这里只须要将本机的数据广播出去 
c) 两边的逻辑时钟相同,此时也只是调用totalOrderPredicate函数判断是否须要更新本机的数据,将最新的选举结果广播出去 


B、若是所接收服务器不在选举状态,也就是在FOLLOWING或者LEADING状态 
a) 若是逻辑时钟相同,将该数据保存到recvset,若是所接收服务器宣称本身是leader,那么将判断是否是有半数以上的服务器选举它,若是是则设置选举状态退出选举过程 
若是逻辑时钟不相同,那么说明在另外一个选举过程当中已经有了选举结果,因而将该选举结果加入到outofelection集合中,再根 据outofelection来判断是否能够结束选举,若是能够也是保存逻辑时钟,设置选举状态,退出选举过程 

以一个简单的例子来讲明整个选举的过程. 
假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是同样的.假设这些服务器依序启动,来看看会发生什么 

1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,因此它的选举状态一直是LOOKING状态  
2) 服务器2启动,它与最开始启动的服务器1进行通讯,互相交换本身的选举结果,因为二者都没有历史数据,因此id值较大的服务器2胜出,可是因为没有达到超 过半数以上的服务器都赞成选举它(这个例子中的半数以上是3),因此服务器1,2仍是继续保持LOOKING状态.  
3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不一样的是,此时有三台服务器选举了它,因此它成为了此次选举的leader.  
4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,可是因为前面已经有半数以上的服务器选举了服务器3,因此它只能接收当小弟的命了.  5) 服务器5启动,同4同样,当小弟

相关文章
相关标签/搜索