#1、什么是zookeeper?# Zookeeper,一种分布式应用的协作服务,是Google的Chubby一个开源的实现,是Hadoop的分布式协调服务,它包含一个简单的原语集,应用于分布式应用的协作服务,使得分布式应用可以基于这些接口实现诸如同步、配置维护和分集群或者命名的服务。
zookeeper是一个由多个service组成的集群,一个leader,多个follower,每个server保存一份数据部分,全局数据一致,分布式读写,更新请求转发由leader实施。
更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行,数据更新原子性,一次数据更新要么成功,要么失败,全局唯一数据视图,client无论连接到哪个server,数据视图是一致的。
#2、Zookeeper 基础# 在深入了解ZooKeeper的运作之前,让我们来看看ZooKeeper的基本概念。 1、Architecture(架构) 2、Hierarchical namespace(层次命名空间) 3、Session(会话) 4、Watches(监视)
ZooKeeper的架构 看看下面的图表。它描述了ZooKeeper的“客户端-服务器架构”。
作为ZooKeeper架构的一部分的每个组件在下表中进行了说明。
| 部分 | 描述 |
|---|---|
| Client(客户端) | 客户端,我们的分布式应用集群中的一个节点,从服务器访问信息。对于特定的时间间隔,每个客户端向服务器发送消息以使服务器知道客户端是活跃的。类似地,当客户端连接时,服务器发送确认码。如果连接的服务器没有响应,客户端会自动将消息重定向到另一个服务器。 |
| Server(服务器) | 服务器,我们的ZooKeeper总体中的一个节点,为客户端提供所有的服务。向客户端发送确认码以告知服务器是活跃的。 |
| Ensemble | ZooKeeper服务器组。形成ensemble所需的最小节点数为3。 |
| Leader | 服务器节点,如果任何连接的节点失败,则执行自动恢复。Leader在服务启动时被选举。 |
| Follower | 跟随leader指令的服务器节点,用于接收客户请求并向客户端返回结果,在选主过程中参与投票。 |
| Observer | Observer可以接接收客户端连接,将请求转发给leader节点。Observer不参与投票过程,只同步leader状态。 |
层次命名空间 下图描述了用于内存表示的ZooKeeper文件系统的树结构。ZooKeeper节点称为 znode 。每个znode由一个名称标识,并用路径(/)序列分隔。
在图中,首先有一个由“/”分隔的znode。在根目录下,你有两个逻辑命名空间 config 和 workers 。
config 命名空间用于集中式配置管理,workers 命名空间用于命名。
与文件系统不同的是,这些znode节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M。
ZooKeeper数据模型中的每个znode都维护着一个 stat 结构。一个stat仅提供一个znode的元数据。它由版本号,操作控制列表(ACL),时间戳和数据长度组成。
-
版本号 - 每个znode都有版本号,这意味着每当与znode相关联的数据发生变化时,其对应的版本号也会增加。当多个zookeeper客户端尝试在同一znode上执行操作时,版本号的使用就很重要。
-
操作控制列表(ACL) - ACL基本上是访问znode的认证机制。它管理所有znode读取和写入操作。
-
时间戳 - 时间戳表示创建和修改znode所经过的时间。它通常以毫秒为单位。ZooKeeper从“事务ID"(zxid)标识znode的每个更改。Zxid 是唯一的,并且为每个事务保留时间,以便你可以轻松地确定从一个请求到另一个请求所经过的时间。
-
数据长度 - 存储在znode中的数据总量是数据长度。你最多可以存储1MB的数据。
Znode的类型 Znode被分为持久(persistent)节点,顺序(sequential)节点和临时(ephemeral)节点。
-
PERSISTENT 持久节点 - 即使在创建该特定znode的客户端断开连接后,持久节点仍然存在。默认情况下,除非另有说明,否则所有znode都是持久的。
-
EPHEMERAL 临时节点 - 客户端活跃时,临时节点就是有效的。当客户端与ZooKeeper集合断开连接时,临时节点会自动删除。因此,只有临时节点不允许有子节点。如果临时节点被删除,则下一个合适的节点将填充其位置。临时节点在leader选举中起着重要作用。
-
SEQUENTIAL 顺序节点 - 当一个新的znode被创建为一个顺序节点时,ZooKeeper通过将10位的序列号附加到原始名称来设置znode的路径。例如,如果将具有路径 /myapp 的znode创建为顺序节点,则ZooKeeper会将路径更改为 /myapp0000000001 ,并将下一个序列号设置为0000000002。如果两个顺序节点是同时创建的,那么ZooKeeper不会对每个znode使用相同的数字。顺序节点在锁定和同步中起重要作用。
-
PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点 - 客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
-
EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点 - 客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
Sessions(会话) 会话对于ZooKeeper的操作非常重要。会话中的请求按FIFO顺序执行。一旦客户端连接到服务器,将建立会话并向客户端分配会话ID 。
客户端以特定的时间间隔发送心跳以保持会话有效。如果ZooKeeper集合在超过服务器开启时指定的期间(会话超时)都没有从客户端接收到心跳,则它会判定客户端死机。
会话超时通常以毫秒为单位。当会话由于任何原因结束时,在该会话期间创建的临时节点也会被删除。
Watches(监视) 监视是一种简单的机制,使客户端收到关于ZooKeeper集合中的更改的通知。客户端可以在读取特定znode时设置Watches。Watches会向注册的客户端发送任何znode(客户端注册表)更改的通知。
Znode更改是与znode相关的数据的修改或znode的子项中的更改。只触发一次watches。如果客户端想要再次通知,则必须通过另一个读取操作来完成。当连接会话过期时,客户端将与服务器断开连接,相关的watches也将被删除。
#3、Zookeeper工作原理#
核心 Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
zookeeper事务一致性 zookeeper采用了递增的事务Id来标识,所有的proposal(提议)都在被提出的时候加上了zxid,zxid实际上是一个64位的数字,高32位是epoch(时期; 纪元; 世; 新时代)用来标识leader是否发生改变,如果有新的leader产生出来,epoch会自增,低32位用来递增计数。当新产生proposal的时候,会依据数据库的两阶段过程,首先会向其他的server发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。以此来保证事务顺序一致性。
zookeeper工作状态 每个Server在工作过程中有四种状态: LOOKING:当前Server不知道leader是谁,正在搜寻 LEADING:当前Server即为选举出来的leader FOLLOWING:leader已经选举出来,当前Server与之同步 OBSERVING: 观察者状态、表明当前server是Observer,不参与选主投票。
zookeeper选主
当leader崩溃或者leader失去大多数的follower,这时zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。
1、Zookeeper选主流程(basic paxos) (1)选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server; (2)选举线程首先向所有Server发起一次询问(包括自己); (3)选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中; (4)收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server; (5)线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数,设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。 通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1. 每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。
2、Zookeeper选主流程(fast paxos) fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和 zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。
Zookeeper同步流程 选完Leader以后,zk就进入状态同步过程。 1、Leader等待server连接; 2、Follower连接leader,将最大的zxid发送给leader; 3、Leader根据follower的zxid确定同步点; 4、完成同步后通知follower 已经成为uptodate状态; 5、Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。
Zookeeper数据复制 Zookeeper作为一个集群提供一致的数据服务,自然,它要在所有机器间做数据复制。数据复制的好处: 1、容错:一个节点出错,不致于让整个系统停止工作,别的节点可以接管它的工作; 2、提高系统的扩展能力 :把负载分布到多个节点上,或者增加节点来提高系统的负载能力; 3、提高性能:让客户端本地访问就近的节点,提高用户访问速度。
从客户端读写访问的透明度来看,数据复制集群系统分下面两种: 1、写主(WriteMaster) :对数据的修改提交给指定的节点。读无此限制,可以读取任何一个节点。这种情况下客户端需要对读与写进行区别,俗称读写分离; 2、写任意(Write Any):对数据的修改可提交给任意的节点,跟读一样。这种情况下,客户端对集群节点的角色与变化透明。
对zookeeper来说,它采用的方式是写任意。通过增加机器,它的读吞吐能力和响应能力扩展性非常好,而写,随着机器的增多吞吐能力肯定下降(这也是它建立observer的原因),而响应能力则取决于具体实现方式,是延迟复制保持最终一致性,还是立即复制快速响应。
关于Observer模式
增加Observer模式模式的目的在于在不伤害写性能的情况下扩展ZooKeeper。
虽然通过Client直接连接到ZooKeeper集群的性能已经很好了,可是这样的架构假设要承受超大规模的Client,就必须添加ZooKeeper集群的Server数量,随着Server的添加,ZooKeeper集群的写性能必定下降。我们知道ZooKeeper的ZNode变更是要过半数投票通过,随着机器的添加,因为网络消耗等原因必定导致投票成本添加,从而导致写性能的下降。
Observer是一种新型的ZooKeeper节点。能够帮助解决上述问题,提供ZooKeeper的可扩展性。Observer不參与投票,仅仅是简单的接收投票结果。因此我们添加再多的Observer,也不会影响集群的写性能。除了这个区别,其它的和Follower基本上全然一样。比如:Client都能够连接到他们,而且都能够发送读写请求给他们,收到写请求都会上报到Leader。
Observer有另外一个优势,由于它不參与投票,所以他们不属于ZooKeeper集群的关键部位,即使他们Failed,或者从集群中断开,也不会影响集群的可用性。
Observer和Follower在一些方面是一样的。详细点来讲,他们都向Leader提交proposal(投票)。但与Follower不同,Observer不参与投票的过程。它简单的通过接收Leader发过来的INFORM(通知)消息来learn已经Commit的proposal。因为Leader都会给Follower和Observer发送INFORM消息,所以它们都被称为Learner。
为了使用Observer模式,在任何想变成Observer模式的配置文件($ZOOKEEPER_HOME/conf/zoo.cfg)中加入如下配置:
peerType=observer
并在所有Server的配置文件($ZOOKEEPER_HOME/conf/zoo.cfg)中,配置成Observer模式的server的那行配置追加:observer,例如:
server.1=localhost:2181:3181:observer
Zookeeper分布式锁
有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。 对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。 对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便。
获取分布式锁的流程:
在获取分布式锁的时候在locker节点下创建临时顺序节点,释放锁的时候删除该临时节点。客户端调用createNode方法在locker下创建临时顺序节点, 然后调用getChildren(“locker”)来获取locker下面的所有子节点,注意此时不用设置任何Watcher。客户端获取到所有的子节点path之后,如果发现自己创建的节点在所有创建的子节点序号最小,那么就认为该客户端获取到了锁。如果发现自己创建的节点并非locker所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时对其注册事件监听器。之后,让这个被关注的节点删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是locker子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。当前这个过程中还需要许多的逻辑判断。
#4、zookeeper的应用场景#
- 数据发布订阅(配置中心)
数据发布/订阅(Publish/Subscribe)系统,即所谓的配置中心,顾名思义就是发布者将数据发布到ZooKeeper的一个或一系列节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和数据的动态更新。 发布/订阅系统一般有两种设计模式,分别是推(Push)模式和拉(Pull)模式。
推模式
服务端主动将数据更新发送给所有订阅的客户端。
拉模式
客户端通过采用定时轮询拉取。 ZooKeeper采用的是推拉相结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知之后,需要主动到服务端获取最新的数据。
- 分布式锁
当分布式系统操作数据,例如:读取数据、分析数据、最后修改数据。在分布式系统里这些操作可能会分散到集群里不同的节点上,那么这时候就存在数据操作过程中一致性的问题,如果不一致,我们将会得到一个错误的运算结果,在单一进程的程序里,一致性的问题很好解决,但是到了分布式系统就比较困难,因为分布式系统里不同服务器的运算都是在独立的进程里,运算的中间结果和过程还要通过网络进行传递,那么想做到数据操作一致性要困难的多。Zookeeper提供了一个锁服务解决了这样的问题,能让我们在做分布式数据运算时候,保证数据操作的一致性。
- 分布式ID生成
之前在ZNode介绍时提过,创建节点时可以设定为SEQUENTIAL顺序节点,创建后API会返回这个节点的完整名字,利用这个特性我们就可以来生成全局唯一ID了。
所有客户端根据自己的任务类型,在指定类型的任务下创建一个顺序节点,例如“Job-”节点节点创建完毕后会返回一个完整的节点名称,如Job-0000000001客户端拿到这个返回值后拼接上type类型,例如type1-Job-000000001,这样就可以作为一个全局唯一的ID了在ZK中每个数据节点都能维护一份子节点的顺序序列,当客户端对其创建一个顺序子节点时ZK会自动以后缀的形式在其子节点上添加一个序号,该场景就利用了ZK的这个特性。
- Master选举
Master选举是一个在分布式系统中常见的应用场景。分布式系统中Master是一个往往用来协调集群中其他角色、处理写操作及复杂逻辑、数据同步等,通常决定对分布式系统状态变更。针对Master选举的需求,我们通常可以使用依靠关系数据库的主键特性在集群中选举出唯一的Master,但是如果当前的Master挂了slave收不到通知怎么办?显然关系数据库做不到通知这一点。ZK创建节点时有一个重要的特性,利用ZK的强一致性能够很好的保证在分布式高并发情况下节点的创建一定能够保证全局唯一,即ZK会保证客户端无法重复创建一个已经存在的数据节点。也就是说同时有多个客户端请求创建同一个节点最终一定只有一个客户端能够请求创建成功,利用这个特性就能很容易的在分布式环境中进行Master选举了。
进行Master选举时客户端启动后可以向ZK请求创建一个临时节点,例如/master_election/master。在多个客户端创建时只有一个能创建成功,那么这个创建成功的客户端所在的机器就成为了Master。同时其他没有创建成功的客户端都可以在节点/master_election上注册一个子节点变更的Watcher来监控当前Master是否在线,一旦发现Master挂了临时节点会被删除,其它客户端会收到通知,开始重新进行Master选举。因此,如果只要求静态Maser选举的话,可以选择关系数据库;如果需要动态Master选举实现HA的话,ZK是更好的选择。
ZK在其它大型分布式系统中的应用
-
Hadoop - 在Hadoop中ZooKeeper主要用于实现HA做主备切换(类似上面讲的Master选举),同时在YARN中又特别提供了ZK来存储应用的运行状态。
-
Kafka -Kafaka是由LinkedIn开源的分布式消息系统,是一个吞吐量极高的分布式消息系统,主要用于实现低延迟的发送和收集大量的事件和日志等活跃数据。Kafaka使用ZK作为其分布式协调框架,将消息生产、消息存储和消息消费的过程结合起来,保持包括生产者消费者和Broker在内的所有组件无状态的情况下,建立起生产者和消费者之间的订阅关系,并实现生产者和消费者之间的负载均衡。
-
HBase -HBase全称Hadoop DataBase,是一个基于Hadoop文件系统设计、面向海量数据的高可靠性、高性能、面向列、可伸缩的分布式存储系统。在HBase向在线分布式存储方向发展过程中,开发者发现如果有RegionServer服务器挂掉时系统和客户端都无法及时得知信息,服务难以快速迁移到其它RegionServer服务器上,问题原因是缺少相应的分布式协调组件,于是后来ZooKeeper被加入到HBase的技术体系中。
#5、为什么zookeeper不适合做服务发现?#
zookeeper本质上实现的是CP而不是AP:
CAP理论告诉我们,一个分布式系统不可能同时满足以下三种
一致性(C:Consistency)
可用性(A:Available)
分区容错性(P:Partition Tolerance)
这三个基本需求,最多只能同时满足其中的两项,因为P是必须的,因此往往选择就在CP或者AP中。
可用性(A:Available)不能保证每次服务请求的可用性。任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性(注:也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果)。所以说,ZooKeeper不能保证服务可用性。进行leader选举时集群都是不可用。在使用ZooKeeper获取服务列表时,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。所以说,ZooKeeper不能保证服务可用性。
借用阿里一篇文章的阐述 jm.taobao.org/2018/06/13/…
在实践中,注册中心不能因为自身的任何原因破坏服务之间本身的可连通性,这是注册中心设计应该遵循的铁律!
目前dubbo已放弃zookeeper注册中心的方案,转而采用阿里开发的Nacos,最新版本为1.0.0。
#6、zookeeper 配置与命令#
**zookeeper 集群配置 **
安装步骤如下:
1) 解压Zookeeper安装包;
2) 将zookeeper/conf目录下的zoo_sample.cfg重命名为zoo.cfg;
3) 修改zoo.cfg,集群配置方案采用一台机器一个节点的方式,构成一个Zookeeper集群至少需要3个节点,单机不需要配置集群配置部分,具体配置如下:
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
# zookeeper数据存储目录
dataDir=/u01/zookeeper/data
# zookeeper日志存储目录
dataLogDir=/u01/zookeeper/log
# the port at which the clients will connect
# zookeeper访问端口,由于每台机器安装一个节点,所以采用统一的端口2181
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
# 保留的日志文件个数,如果数据量大可以设置大一点
autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
# 日志文件清理周期 ,单位小时
autopurge.purgeInterval=1
# 集群配置
# server.A=B:C:D
# 其中 A 是一个数字,表示这个是第几号服务器;
# B 是这个服务器的 ip 地址;
# C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;
# D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
server.1=192.168.1.199:2889:3889
server.2=192.168.1.200:2889:3889
server.3=192.168.1.201:2889:3889
4) 创建dataDir和dataLogDir;
5) 在dataDir目录下创建一个myid文件,然后分别在myid文件中按照zoo.cfg文件的server.A中A的数值,在不同机器上的该文件中填写相应的值(单机无需配置);
6) 启动Zookeeper:Linux系统下,在Zookeeper的bin目录下执行“zkServer.sh start”命令启动Zookeeper,执行命令“zkServer.sh stop”将会停止Zookeeper; Windows 系统下,直接双击zkServer.cmd打开即可;
7) 执行“zkServer.sh status”命令查看Zookeeper集群状态,确认相应的节点是否处于可用状态;
8) Linux系统下执行“zkCli.sh -server 192.168.1.199:2181”命令可以连接相应的Zookeeper节点;Windows系统下执行,“zkCli -server 192.168.1.199:2181”;
在生产环境中,一定要部署成集群模式,一般不少于3个节点,不多于7个节点,合理的节点数为3、5、7。节点需要分布到不同的机器上。zookeeper对网络稳定性极为敏感,一定要保证网络环境的稳定性。
**zookeeper 命令 **
- 连接远程Server:zkCli.sh –server : 比如连接到本地Zoopker服务: ./zkCli.sh -server localhost:2181
- 查看节点数据:ls ,比如ls / 则查看根目录节点数据 查看某个服务Service的提供者 ls 服务名/providers 查看节点数据并能看到更新次数等数据:ls2 ,输出字段含义如下: cZxid:创建节点的事务id ctime:创建节点的时间 mZxid:修改节点的事务id mtime:修改节点的时间 pZxid:子节点列表最后一次修改的事务id。删除或添加子节点,不包含修改子节点的数据 cversion:子节点的版本号,删除或添加子节点,版本号会自增 dataVersion:节点数据版本号,数据写入操作,版本号会递增 aclVersion:节点ACL权限版本,权限写入操作,版本号会递增 ephemeralOwner:临时节点创建时的事务id,如果节点是永久节点,则它的值为0 dataLength:节点数据长度(单位:byte),中文占3个byte numChildren:子节点数量
- 创建节点:create
- 获取节点,包含数据和更新次数等数据:get
- 修改节点:set
- 删除节点:delete ,如果有子节点存在则删除失败
#7、zookeeper java客户端工具# 推荐使用curator作为zookeeper java客户端实现,zookeeper原生的java api非常的难用。