Hadoop从入门到放弃系列------ZooKeeper

一、ZooKeeper的由来

 ZooKeeper最早起源于雅虎研究院的一个研究小组,其宗旨就是解决分布式系统中的协调问题,并且自身无单点风险。

再说下“ZooKeeper”这个名字由来的趣闻,在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如Pig,Hive等),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家RaghuRamakrishnan开玩笑地说:“在这样下去,我们这儿就变成动物园了!”此话一出,大家纷纷表示就叫动物园管理员吧一一一因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而ZooKeeper正好要用来进行分布式环境的协调一一于是,ZooKeeper的名字也就由此诞生了。

二、ZooKeeper 到底是什么

 ZooKeeper是一个开源的分布式协调服务,最初在“Yahoo!”上构建,是Google Chubby的开源实现。分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、配置维护、分布式同步、分布式锁和分布式队列等功能。

三、ZooKeeper 的一些重要概念

 1、集群角色

ZooKeeper集群包括三种角色:Leader,Follower,Observer,如下图

Hadoop从入门到放弃系列------ZooKeeper

Leader由除Observer外的所有节点选举产生,既可以为客户端提供写服务又能提供读服务。Follower 和 Observer 都只能提供读服务。

Follower 和 Observer 唯一的区别在于 Observer 机器不参与 Leader 的选举过程,也不参与写操作的“过半写成功”策略,因此 Observer 机器可以在不影响写性能的情况下提升集群的读性能。

2、会话

会话(Session)就是一个客户端与服务器之间的一个TCP长连接,客户端和服务器的一切交互都是通过这个长连接进行的;当客户端连接断开时,只要在 SessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。sessionID是会话的全局唯一标识。

3、节点

节点在ZeeKeeper中包含两层含义:

1、集群中的一台机器,我们称为机器节点;

2、ZooKeeper数据模型中的数据单元,我们成为数据节点(ZNode)。

Zookeeper将所有数据存储在内存中,数据模型是一棵树(Znode Tree),由斜杠(/)的进行分割的路径,就是一个Znode,例如/app1/p_1。每个上都会保存自己的数据内容,同时还会保存一系列属性信息。

Hadoop从入门到放弃系列------ZooKeeper

在Zookeeper中,node可以分为持久节点和临时节点两类。

持久节点:一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在Zookeeper上。

临时节点:它的生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。

4、版本

ZooKeeper为每一个ZNode节点维护一个叫做Stat的数据结构,在Stat中维护了节点相关的三个版本:

1、当前ZNode的版本version

2、当前ZNode子节点的版本cversion

3、当前ZNode的ACL(Access Control Lists)版本aversion

5、监听器

监听器(Watcher):Zookeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制是Zookeeper实现分布式协调服务的重要特性。

6、ACL

Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,类似于 UNIX 文件系统的权限控制。Zookeeper 定义了如下5种权限。

CREATE:创建子节点的权限

READ:获取节点数据和子节点列表的权限

WRITE:更新节点数据的权限

DELETE:删除子节点的权限

ADMIN:设置节点ACL的权限

其中尤其需要注意的是,CREATE和DELETE这两种权限都是针对子节点的权限控制。

四、ZooKeeper 的特点

1、顺序一致性

从同一个客户端发起的事务请求,最终将会严格按照其发起顺序被应用到ZooKeeper中

2、原子性

所有事物请求的处理结果在整个集群中所有机器上的应用情况是一致的,即,要么整个集群中所有机器都成功应用了某一事务,要么都没有应用,一定不会出现集群中部分机器应用了该事务,另外一部分没有应用的情况。

3、单一视图(最终一致性)

无论客户端连接的是哪个ZooKeeper Server,其看到的服务端数据模型都是一致的。

4、可靠性

ZooKeeper集群Leader、Follower机制

5、实时性

准确说应该是准实时,通过性能会弥补一定的实时性。

五、ZooKeeper的典型应用场景

1、数据发布与订阅

发布/订阅模式是一对多的关系,多个订阅者对象同时监听某一主题对象,这个主题对象在自身状态发生变化时会通知所有的订阅者对象。使它们能自动的更新自己的状态。发布/订阅可以使得发布方和订阅方独立封装、独立改变。当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象需要改变时可以使用发布/订阅模式。发布/订阅模式在分布式系统中的典型应用有配置管理服务发现、注册

配置管理是指如果集群中的机器拥有某些相同的配置并且这些配置信息需要动态的改变,我们可以使用发布/订阅模式把配置做统一集中管理,让这些机器格子各自订阅配置信息的改变,当配置发生改变时,这些机器就可以得到通知并更新为最新的配置。

服务发现、注册是指对集群中的服务上下线做统一管理。每个工作服务器都可以作为数据的发布方向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息,当工作服务器的基本信息发生改变如上下线、服务器角色或服务范围变更,监控服务器可以得到通知并响应这些变化。

发布/订阅系统一般有两种设计模式,分别是推(Push)模式和拉(Pull)模式。

推模式:服务端主动将数据更新发送给所有订阅的客户端。

拉模式:客户端通过采用定时轮询拉取。

ZooKeeper采用的是推拉相结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知之后,需要主动到服务端获取最新的数据。

 

2、布通知/协调

ZooKeeper 中特有watcher注册与异步通知机制,能够很好的实现分布式环境下不同系统之间的通知与协调,实现对数据变更的实时处理。使用方法通常是不同系统都对 ZK上同一个znode进行注册,监听znode的变化(包括znode本身内容及子节点的),其中一个系统update了znode,那么另一个系统能够收到通知,并作出相应处理。

1、另一种心跳检测机制:检测系统和被检测系统之间并不直接关联起来,而是通过ZK上某个节点关联,大大减少系统耦合。

2. 另一种系统调度模式:某系统有控制台和推送系统两部分组成,控制台的职责是控制推送系统进行相应的推送工作。管理人员在控制台作的一些操作,实际上是修改 了ZK上某些节点的状态,而zk就把这些变化通知给他们注册Watcher的客户端,即推送系统,于是,作出相应的推送任务。

3. 另一种工作汇报模式:一些类似于任务分发系统,子任务启动后,到zk来注册一个临时节点,并且定时将自己的进度进行汇报(将进度写回这个临时节点),这样任务管理者就能够实时知道任务进度。

总之,使用zookeeper来进行分布式通知和协调能够大大降低系统之间的耦合。

 

3、分布式锁

分布式锁,这个主要得益于ZooKeeper为我们保证了数据的强一致性,即用户只要完全相信每时每刻,ZK集群中任意节点(一个ZK server)上的相同znode的数据是一定是相同的。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁,通过create znode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。

控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了。做法和上面基本类似,只是这里 /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)。ZK的父节点(/distribute_lock)维持一份sequence,保证子节点创建的时序性,从而也形成了每个客户端的全局时序。

 

4、Master选举

在分布式环境中,相同的业务应用分布在不同的机器上,有些业务逻辑(例如一些耗时的计算,网络I/O处理),往往只需要让整个集群中的某一台机器进行执行, 其余机器可以共享这个结果,这样可以大大减少重复劳动,提高性能,于是这个master选举便是这种场景下的碰到的主要问题。

利用ZooKeeper的强一致性,能够保证在分布式高并发情况下节点创建的全局唯一性,即:同时有多个客户端请求创建 /currentMaster 临时节点,最终一定只有一个客户端请求能够创建成功,成功创建该节点的客户端所在的机器就成为了 Master。同时,其他没有成功创建该节点的客户端,都会在该节点上注册一个子节点变更的 Watcher,用于监控当前 Master 机器是否存活,一旦发现当前的Master挂了,那么其他客户端将会重新进行 Master 选举, 这样就实现了 Master 的动态选举。