定义html
ZooKeeper是Hadoop的正式子项目,它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。node
原理算法
ZooKeeper是以Fast Paxos算法为基础的,paxos算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥致使没有一个proposer能提交成功,而Fast Paxos做了一些优化,经过选举产生一个leader,只有leader才能提交propose,具体算法可见Fast Paxos。shell
系统结构apache
在zookeeper中实现了一个相似file system系统的数据结构,好比/zookeeper/status。 每一个节点都对应于一个znode节点。Zookeeper的功能都是经过对znode的操做实现的服务器
znode 的 模式:网络
PERSISTENT (持续的,相比于EPHEMERAL,不会随着client session的close/expire而消失)session
PERSISTENT_SEQUENTIAL数据结构
EPHEMERAL (短暂的,生命周期依赖于client session,对应session close/expire后其znode也会消失)app
EPHEMERAL_SEQUENTIAL (SEQUENTIAL意为顺序的)
zxid (ZooKeeper Transaction Id,每次请求对应一个惟一的zxid,若是zxid a < zxid b ,则能够保证a必定发生在b以前)。
对应zxid 有两个
czxid
The zxid of the change that caused this znode to be created.
mzxid
The zxid of the change that last modified this znode.
Alone模式的启动方法:
conf/zoo.cfg:
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
运行 bin/zkServer.sh start
shell客户端链接:
bin/zkCli.sh -server 127.0.0.1:2181
能够经过help打印出帮助信息
常见操控znode命令有:
get path [watch]
create [-s] [-e] path data acl
ls path [watch]
set path data [version]
delete path [version]
[zk: 127.0.0.1:2181(CONNECTED) 2] create -s /zk_test/st1 aaaa
Created /zk_test/st10000000000
[zk: 127.0.0.1:2181(CONNECTED) 3] create -s /zk_test/st1 aaaa
Created /zk_test/st10000000001
对某个znode节点 创建watch
get /zk_test/et10000000009 watch
Watches
Zookeeper 全部的读操做—— getData() , getChildren() , 和 exists() 都 能够设置监视(watch),监视事件能够理解为一次性的触发器, 官方定义以下: a watch event is one-time trigger, sent to the client that set the watch, which occurs when the data for which the watch was set changes。对此须要做出以下理解:
(一次性触发)One-time trigger
当设置监视的数据发生改变时,该监视事件会被发送到客户端,例如,若是客户端调用了 getData("/znode1", true) 而且稍后 /znode1 节点上的数据发生了改变或者被删除了,客户端将会获取到 /znode1 发生变化的监视事件,而若是 /znode1 再一次发生了变化,除非客户端再次对 /znode1 设置监视,不然客户端不会收到事件通知。
(发送至客户端)Sent to the client
Zookeeper 客户端和服务端是经过 socket 进行通讯的,因为网络存在故障,因此监视事件颇有可能不会成功地到达客户端,监视事件是异步发送至监视者的,Zookeeper 自己提供了保序性(ordering guarantee):即客户端只有首先看到了监视事件后,才会感知到它所设置监视的 znode 发生了变化(a client will never see a change for which it has set a watch until it first sees the watch event). 网络延迟或者其余因素可能致使不一样的客户端在不一样的时刻感知某一监视事件,但 是不一样的客户端所看到的一切具备一致的顺序。
(被设置watch的数据)The data for which the watch was set
这意味着 znode 节点自己具备不一样的改变方式。你也能够想象 Zookeeper 维护了两条监视链表:数据监视和子节点监视(data watches and child watches) getData() and exists() 设置数据监视,getChildren() 设置子节点监视。 或者,你也能够想象 Zookeeper 设置的不一样监视返回不一样的数据,getData() 和 exists() 返回 znode 节点的相关信息,而 getChildren() 返回子节点列表。所以, setData() 会触发设置在某一节点上所设置的数据监视(假定数据设置成功),而一次成功的 create() 操做则会出发当前节点上所设置的数据监视以及父节点的子节点监视。一次成功的 delete() 操做将会触发当前节点的数据监视和子节点监视事件,同时也会触发该节点父节点的child watch。
Zookeeper 中的监视是轻量级的,所以容易设置、维护和分发。当客户端与 Zookeeper 服务器端失去联系时,客户端并不会收到监视事件的通知,只有当客户端从新链接后,若在必要的状况下,之前注册的监视会从新被注册并触发,对于开发人员来讲 这一般是透明的。只有一种状况会致使监视事件的丢失,即:经过 exists() 设置了某个 znode 节点的监视,可是若是某个客户端在此 znode 节点被建立和删除的时间间隔内与 zookeeper 服务器失去了联系,该客户端即便稍后从新链接 zookeeper服务器后也得不到事件通知。
对于watch,zookeeper提供如下保证:
1.watch对于其余事件、watch、异步响应是有序的。zookeeper client library保证有序分发
2.客户端监视一个节点,老是先获取watch事件,再发现节点的数据变化。
3.watch事件的顺序对应于zookeeper服务所见的数据更新的顺序。
关于watch要记住的是:
1.watch是一次性触发的,若是获取一个watch事件并但愿获得新变化的通知,须要从新设置watch
2.watch是一次性触发的而且在获取watch事件和设置新watch事件之间有延迟,因此不能可靠的观察到节点的每一次变化。要认识到这一点。
3.watch object只触发一次,好比,一个watch object被注册到同一个节点的getData()和exists(),节点被删除,仅对应于exists()的watch ojbect被调用
4.若与服务端断开链接,直到重连后才能获取watch事件。
Watch事件类型:
ZOO_CREATED_EVENT:节点建立事件,须要watch一个不存在的节点,当节点被建立时触发,此watch经过zoo_exists()设置
ZOO_DELETED_EVENT:节点删除事件,此watch经过zoo_exists()或zoo_get()设置
ZOO_CHANGED_EVENT:节点数据改变事件,此watch经过zoo_exists()或zoo_get()设置
ZOO_CHILD_EVENT:子节点列表改变事件,此watch经过zoo_get_children()或zoo_get_children2()设置
ZOO_SESSION_EVENT:会话失效事件,客户端与服务端断开或重连时触发
ZOO_NOTWATCHING_EVENT:watch移除事件,服务端出于某些缘由再也不为客户端watch节点时触发
ACL
传统的文件系统中,ACL分为两个维度,一个是属组,一个是权限,子目录/文件默认继承父目录的ACL。而在Zookeeper中,node的ACL是没有继承关系的,是独立控制的。Zookeeper的ACL,能够从三个维度来理解:一是scheme; 二是user; 三是permission,一般表示为scheme:id:permissions, 下面从这三个方面分别来介绍:
scheme: scheme对应于采用哪一种方案来进行权限管理,zookeeper实现了一个pluggable的ACL方案,能够经过扩展scheme,来扩展ACL的机制。zookeeper-3.4.4缺省支持下面几种scheme:
world: 它下面只有一个id, 叫anyone, world:anyone表明任何人,zookeeper中对全部人有权限的结点就是属于world:anyone的
auth: 它不须要id, 只要是经过authentication的user都有权限(zookeeper支持经过kerberos来进行authencation, 也支持username/password形式的authentication)
digest: 它对应的id为username:BASE64(SHA1(password)),它须要先经过username:password形式的authentication
ip: 它对应的id为客户机的IP地址,设置的时候能够设置一个ip段,好比ip:192.168.1.0/16, 表示匹配前16个bit的IP段
super: 在这种scheme状况下,对应的id拥有超级权限,能够作任何事情(cdrwa)
另外,zookeeper-3.4.4的代码中还提供了对sasl的支持,不过缺省是没有开启的,须要配置才能启用,具体怎么配置在下文中介绍。
sasl: sasl的对应的id,是一个经过sasl authentication用户的id,zookeeper-3.4.4中的sasl authentication是经过kerberos来实现的,也就是说用户只有经过了kerberos认证,才能访问它有权限的node.
id: id与scheme是紧密相关的,具体的状况在上面介绍scheme的过程都已介绍,这里再也不赘述。
permission: zookeeper目前支持下面一些权限:
CREATE(c): 建立权限,能够在在当前node下建立child node
DELETE(d): 删除权限,能够删除当前的node
READ(r): 读权限,能够获取当前node的数据,能够list当前node全部的child nodes
WRITE(w): 写权限,能够向当前node写数据
ADMIN(a): 管理权限,能够设置当前node的permission
zookeeper使用事例:
1. 配置项管理
分布式系统中,常常会有多个节点共享一份配置信息,而且配置信息可能动态的发生变化,此时须要节点能在配置变化时动态加载,经过zookeeper可很方便的完成。将配置信息存储在zookeeper的某个节点C上(可能包含不少配置子项),进程启动时先链接zookeeper获取C上的配置信息并注册watch,当配置信息发生变化时会获得通知,此时进程从新加载配置。
2. 主从配合
分布式系统中,多个进程可能须要协做,某个进程在启动时须要知道其余进程的一些信息,而这些信息可能会动态变化。如某系统中,包含一个master进程和多个worker进程,worker在启动时必须链接知道master的运行的一些信息(如ip:port,状态等),而master的运行由调度器完成,可能动态变化,经过zookeeper可完成这类需求。在zookeeper上建立一个节点R,当master启动时,将其运行信息写入R节点,当worker启动时,读取R的信息并设置watch,若是R中有信息,则读取并启动;若是没有,当master向R写入信息后,worker会被通知,此时读取信息而且启动worker;另外,能够将R设为Ephemeral并注册deletewatch时间,当R不存在时,全部的进程退出。
3. 组管理
组管理在分布式系统中很常见,如某个分布式存储系统,包含多个存储节点,这多个存储节点构成一个group,合理管理group是系统运行的关键,如监控并处理group中节点加入(扩展性)和退出(容错)事件,经过zookeeper也可方便实现组管理功能。用一个节点G表明group,系统在group上设置watch,当有节点加入时,在G下建立一个临时子节点,当节点退出时,临时子节点也会被删除,系统只须要根据相应的事件类型进行处理便可。
4. 分布式锁
解决方案依然很简单,须要加锁的进程先尝试在zookeeper上建立一个临时节点L,若是建立成功则加锁成功,若是不成功(已存在)则在该节点上设置watch。进程经过删除L来解锁(当进程意外终止,L也会被删除,不会形成死锁),当L被删除时,其它等待锁的进程会获得通知,此时这些进程再次建立L来得到锁。
上面的方案,当竞争锁的进程比较多时,解锁时会引发Herd Effect,可对加锁规则进行限制,如按进程尝试加锁的顺序来分配锁。在zookeeper上,每一个加锁的进程建立一个带SEQUENTIAL标志的临时节点,每次让序号最小的节点得到锁,这样每一个节点只须要watch它前面节点的状态便可,当其前面节点被删除时,其将被通知,并得到锁。
5. 分布式Barrier
Barrier是一种控制和协调多个任务触发次序的机制,简单说来就是搞个闸门把欲执行的任务给拦住,等全部任务都处于能够执行的状态时,才放开闸门。
是用一个Node做为Barrer的实体,须要被Barrer的任务经过调用exists()检测这个Node的存在,当须要打开Barrier的时候,删掉这个Node,ZooKeeper的watch机制会通知到各个任务能够开始执行。
6. 分布式 Queue
与 Barrier相似 分布式环境中 实现Queue也须要高一致性作保障, ZooKeeper提供了一个种简单的方式, ZooKeeper经过一个Node来维护Queue的实体,用其children来存储Queue的内容,而且 ZooKeeper的create方法中提供了顺序递增的模式,会自动地在name后面加上一个递增的数字来插入新元素。能够用其 children来构建一个queue的数据结构,offer的时候使用create,take的时候按照children的顺序删除第一个便可。 ZooKeeper保障了各个server上数据是一致的,所以也就实现了一个 分布式 Queue。
Curator
Curator是Netflix开源的一套ZooKeeper客户端框架.
Curator主要解决了三类问题:
封装ZooKeeper client与ZooKeeper server之间的链接处理;
提供了一套Fluent风格的操做API;
提供ZooKeeper各类应用场景(recipe, 好比共享锁服务, 集群领导选举机制)的抽象封装.
CuratorFramework zkClient = CuratorFrameworkFactory .builder() .connectString(zkQuorum) .retryPolicy( new RetryNTimes(zkRetryTimes, zkRetrySleepInterval))
.build(); zkClient.start(); zkClient.create().creatingParentsIfNeeded() .forPath(shardZkPath, null); byte[] shardZkData = zkClient.getData().forPath( shardZkPath);
参考资料:
整体:
http://agapple.iteye.com/blog/1111377
http://blog.csdn.net/cutesource/article/details/5822459
http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html
http://okwangxing.iteye.com/blog/598548
Acl:
http://www.wuzesheng.com/?p=2438
curator