zookeeper综述
zk概念
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。
他主要用来解决分布式应用中的数据管理的一致性问题。例如统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
官网:http://hadoop.apache.org/zookeeper/。
从上面的定义中,我没可以看出两个重要信息:zk是用来管理分布式应用的;zk本身也是可以部署成分布式的。
作为初级用户,首先关注的是zk怎么用,接着是zk管理分布式应用的思路,最后才是zk自己是如何处理实现分布式的。这里我们重点关注第二点。
zk如何管理客户的分布式数据
Zookeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。
通俗解释一下,zookeeper的名字翻译过来就是动物管理员。这个动物管理员管理着很多个兔子啊,老虎啊,狗熊啊什么的。动物管理员接受游客的访问,一旦游客有什么要求,动物管理员能够通知所有手下的动物,动物们都知道了最新的消息,就能根据消息安排自己的生活:该要饭的要饭,该表演节目的表演节目。
发布者------动物管理员-----zk Server
观察者------游客--------------zk Client
下图zk Server存储的数据模型,这是一个树状层次的结构,与Unix文件系统很类似。这些数据的特点在下面也简单描述了一下。
1、每个子目录项如 NameService 都被称作为 znode,这个 znode 是被它所在的路径唯一标识,如 Server1 这个 znode 的标识为 /NameService/Server1
2、znode 可以有子节点目录,并且每个znode 可以存储数据
3、znode 可以是临时节点,一旦创建这个 znode 的客户端与服务器失去联系,这个znode 也将自动删除,Zookeeper的客户端和服务器通信采用长连接方式,每个客户端和服务器通过心跳来保持连接,这个连接状态称为 session,如果 znode 是临时节点,这个 session 失效,znode也就删除了
4、znode 可以被监控(设置Watcher),包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置该Watcher的客户端,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反应。这个是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基于这个特性实现的。
举一个应用的栗子
假设在一个集群应用中,有一些机器用来发布服务,另外一些机器用来消费服务。要做到高可用,有一些最低的要求:
1、提供者提供的服务能让消费者找到;
2、消费者本地要存储一个服务列表,里面所有的服务都是alive的
2、提供者挂了,消费者要得到通知,更新自己的列表,避免再向这个服务器要服务
我们看看向zk如何做,才能满足上面的要求:基本原理就是发布者观察者模式,提供者把消息写到zk Server的某一个目录,消费者就观察这个目录,一旦服务提供者有啥变化,zk Server都能够觉察出来,并把消息及时发给正在观察这个目录的消费者。
(1)zk客户端连接zk服务器(发布者)
(2)发布者客户端调用create方法在zk server上创建目录节点,同时将服务属性写入目录节点的数据中
(3)zk客户端连接zk服务器(消费者)
(4)消费者客户端从服务器获取服务地地址和属性信息,同时设置watcher来监控跟这个目录节点的数据。获得服务的信息之后, 更新到本地缓存中。
(5)消费者监听服务提供者的目录列表,当有服务上下线的时候,可以获得通知
(6)发布者调用create动态注册新服务
(7)消费者获取新服务上线通知,获取新的服务地址,并更新到本地缓存
(8)发布者取消服务,只要delete目录即可,同时删除了目录相关的数据
(9)消费者受到服务下线通知,获取下线的信息,并从本地缓存中删除
(10)zk客户端与服务器的连接会话终止,存储在zk上的所有临时数据与注册的订阅者都被自动移除
(11)消费者获取服务列表被删除的通知之后,更新本地缓存路由表
zk server之间如何保持数据一致性
zookeeper本身是分布式部署的,也就是说可以有很多个zk Server,这么多个节点都把数据都放在内存中,并且要求各节点保持一致,任何一个client访问任何一个server,要求得到的数据是一样的,就像访问一个server一样,这个要求要做到其实很难的,我们简单看看zk Server端是如何做到的。
(1)Zk Server要有一个leader作为leader server,其他的称之为follower。leader很重要,系统刚启动的时候,还有leader挂了的时候,都要能够自动选出一个新的leader,这里就涉及到一个选举算法。
(2)所有的写请求会被转到leader server来处理,然后再通知followers节点更新状态;读请求则可由followers直接处理。由于写操作需要进行全局同步,所以Zookeeper更适合读多写少类型的应用。
(3)进行全局同步的核心是原子广播,这个机制保障了各个server之间的数据一致性。实现这个机制的协议叫做Zab协议,包括广播模式和恢复模式。
(4)server之间通过定时发送心跳消息感知健康状态。
其他应用场景
1、配置管理(Configuration Management)
将配置信息保存在 Zookeeper 的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中。
2、集群管理(Group Membership)
Zookeeper 能够很容易的实现集群管理的功能,如有多台 Server 组成一个服务集群,那么必须要一个“总管”知道当前集群中每台机器的服务状态,一旦有机器不能提供服务,集群中其它集群必须知道,从而做出调整重新分配服务策略。同样当增加集群的服务能力时,就会增加一台或多台 Server,同样也必须让“总管”知道。
它们的实现方式都是在 Zookeeper 上创建一个 EPHEMERAL 类型的目录节点,然后每个 Server 在它们创建目录节点的父目录节点上调用 getChildren(String path, boolean watch) 方法并设置 watch 为 true,由于是 EPHEMERAL 目录节点,当创建它的 Server 死去,这个目录节点也随之被删除,所以 Children 将会变化,这时 getChildren上的 Watch 将会被调用,所以其它 Server 就知道已经有某台 Server 死去了。新增 Server 也是同样的原理。
3、分布式锁
虽然Zookeeper没有原生提供锁操作,但是通过Zookeeper提供的一些API, 较容易实现分布式锁。我们可以利用临时节点来实现,多个进程都尝试创键临时节点/lock, 但最终只会有一个进程P能创建成功,而其他没能创建成功的进程,可以在节点/lock上Watch(相当于等待锁释放), 一旦进程P处理完事务,断开连接,节点/lock被自动删除,其他进程将得到通知,进而继续创建节点/lock,以争得锁资源。 (这里使用临时节点,是为了防止获得锁的进程突然崩溃而没有释放锁,导致死锁发生)。
4、管理队列
参考文档:
http://www.techweb.com.cn/network/hardware/2015-12-25/2246973.shtml
http://blog.csdn.net/yanlinwang/article/details/45080455
http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/
t.hao0.me