ZooKeeper是一个分布式的应用程序协调服务。
2 ZooKeeper的工作原理
Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab(Zookeeper Atomic Broadcast)协议。Zab协议有两种模式,它们分别是恢复模式(recovery选主)和 广播模式(broadcast同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以 后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
1、ZooKeeper数据模型:
类似于一个标准的文件系统,具有层次关系的数据结构
每个子目录项如NameService都被称作为znode。
ZNode根据其本身的特性,可以分为下面两类:
Regular ZNode: 常规型ZNode,
Ephemeral ZNode: (ɪ'fem(ə)r(ə)l)(临时的)类型的目录节点不能有子节点目录。
Zookeeper的客户端和服务器通信采用长连接方式,每个客户 端和服务器通过心跳来保持连接,这个连接状态称为session,如果znode是临时节点,这个session失效,znode也就删除了。(3s/一次,200次)。
如果Client因为Timeout和Zookeeper Server失去连接,client处在CONNECTING状态,会自动尝试再去连接Server,如果在session有效期内再次成功连接到某个Server,则回到CONNECTED状态。
2、ZooKeeper Watch:
Zookeeper从设计模式的角度来看,是一个基于观察者设计模式设计的。简单来说就是
Client可以在某个ZNode上设置一个Watcher,来Watch该ZNode上的变化。如果该ZNode上有相应的变化,就会触发这个Watcher,把相应的事件通知给设置Watcher的Client。需要注意的是,ZooKeeper中的Watcher是一次性的,即触发一次就会被取消,如果想继续Watch的话,需要客户端重新设置Watcher。
3、 ZooKeeper特性 :
读、写(更新)模式:
在ZooKeeper集群中,读可以从任意一个ZooKeeper Server读。写的请求会先Forwarder到Leader,然后由Leader来通过ZooKeeper中的原子广播协议,将请求广播给所有的Follower,Leader收到一半以上的写成功的消息后,就认为该写成功了,就会将该写进行持久化,并告诉客户端写成功了。
FIFO
对于每一个ZooKeeper客户端而言,所有的操作都是遵循FIFO顺序的,这一特性是由下面两个基本特性来保证的:一是ZooKeeper Client与Server之间的网络通信是基于TCP,TCP保证了Client/Server之间传输包的顺序;二是ZooKeeper Server执行客户端请求也是严格按照FIFO顺序的。
为 了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了 zxid。实现中zxid是一个64位的数字,它高32位是 用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新 的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
ZooKeeper典型应用场景
- 名字服务(NameService) :
每个ZNode都可以由其路径唯一标识,路径本身也比较简洁直观,另外ZNode上还可以存储少量数据,这些都是实现统一的NameService的基础。通过简单的名字,访问对应的服务器集群。
- 配置管理(Configuration Management) :
一:分布式互斥锁
在传统的应用程序中,线程、进程的同步,都可以通过操作系统提供的机制来完成。但是在分布式系统中,多个进程之间的同步,操作系统层面就无能为力了。
zookeeper中,并没有像JAVA里一样有Synchronized或者是ReentrantLock机制来实现锁机制,但是在zookeeper中,实现起来更简单:我们可以讲将zk的一个数据节点代表一个锁,当多个客户端同时调用create()节点创建节点的时候,zookeeper会保证只会有一个客户端创建成功,那么我们就可以让这个创建成功的客户端让其持有锁,而其它的客户端则注册Watcher监听当持有锁的客户端释放锁后,监听的客户端就会收到Watcher通知,然后再去试图获取锁,这样反复即可。
Zookeeper的三种角色:
1.leader和follower
ZooKeeper需要在所有的服务(可以理解为服务器)中选举出一个Leader,然后让这个Leader来负责管理集群。此时,集群中的其它服务器则 成为此Leader的Follower。并且,当Leader故障的时候,需要ZooKeeper能够快速地在Follower中选举出下一个 Leader。这就是ZooKeeper的Leader机制,下面我们将简单介绍在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中,为了避免从众效应的发生,它是这样来实现的:每一个follower对follower集群中对应的比自己节点序号小一 号的节点(也就是所有序号比自己小的节点中的序号最大的节点)设置一个watch。只有当follower所设置的watch被触发的时候,它才进行 Leader选举操作,一般情况下它将成为集群中的下一个Leader。很明显,此Leader选举操作的速度是很快的。因为,每一次Leader选举几 乎只涉及单个follower的操作。
2.Observer
observer的行为在大多数情况下与follower完全一致, 但是他们不参加选举和投票, 而仅仅接受(observing)选举和投票的结果.
Zookeeper集群,选举机制
zookeeper选举机制
FastLeaderElection算法通过异步的通信方式来收集其它节点的选票,同时在分析选票时又根据投票者的当前状态来作不同的处理,以加快Leader的选举进程。 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();
|