总结:

what:分布式应用的协调服务。用于对分布式系统进行节点管理、leader选举、配置管理等。zookeeper自身也是个分布式系统,有多个节点,具备一致性(借助Paxos算法)、容错性、高可用等特点。

原理:从设计模式角度来看,是一个基于观察者模式的分布式应用的管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应。

主要概念:znode

zookeeper中的数据是以树形结构组织的,类似于树形文件系统。树中的节点称为znode,znode有持久型和临时型两个类型,具体来说有四种:

持久型:PERSISTENT、PERSISTENT_SEQUENTIAL

临时型:EPHEMERAL、EPHEMERAL_SEQUENTIAL

临时型的znode在创建者与zookeeper连接断开时(客户端主动断开、服务端宕机导致被动断开等)会被自动删除,持久型的则不会;带SEQUENTIAL后缀的与不带的相比区别在于前者类型的znode写入时会自动在末尾加编号,编号递增,客户端可以根据编号排序来推断事件的顺序或实现一些功能(如leader选举、实现读写锁等)。

主要应用场景:

(均为通过利用 zookeeper znode及znode变化通知机制 来实现。对于前者,要么利用“zk中节点不能重名”的特性、要么利用节点顺序做文章。临时节点用得多)

配置管理/命名管理:用于存储所管理的分布式系统的配置数据(如节点的地址等),这些数据被系统的各节点共享。zookeeper自身的配置数据也存储在树形文件系统中。

节点管理(membership):各节点连接zookeeper后往同一个目录(如/kafka/nodes)下创建一个EPHEMERAL类型的zonde,值为当前节点的id(如将ip:port作为id);并监控该目录节点。这样每个节点都可知道系统中其他节点的存在,当节点增减时也能收到通知从而感知到系统的节点的变化。

leader选举(master/slave选举、replication leader选举):与节点选管理类似,只不过进一步地,各节点从节点列表中按定好的规则选出一个作为leader。如改为创建EPHEMERAL_SEQUENTIAL类型的节点,并将编号最小创建者的作为leader。

分布式锁:(创建临时节点,这样在连接断开时节点自动删除)

分布式排他锁

非公平锁:与leader选举类似,按预定的规则选出的znode(如将编号最小的znode)的创建者作为锁的获得者,其他的创建者等待并监听共同父目录的children变化事件。当然,由于编号是按创建顺序递增的,故若规则为选编号最小者,则是公平的。

公平锁:先写先得——往同一个znode下创建多个znode时,会按写入的先后顺序存储,故每次都让最靠前的znode的创建者获得锁即可。

也可利用“zk中的节点不能重名的特性”来实现排他锁:各客户端创建同一EPHEMERAL znode,只会有一个创建成功,成功者获得锁,失败者等待并监听该znode的删除事件,流程图:

屏障(barrier):与节点管理类似,只不过各节点等监控到集群中节点数达到预期数理时才开始接下来的工作。

读/写锁:各客户端往同一目录下创建EPHEMERAL_SEQUENTIAL节点(写或读节点,结果如"read_1"、"write_2"、"read_3"),然后获取目录下的znode列表并按序号升序排序.

读锁:若当前客户端创建的znode前无写znode则获得读锁,否则等待并监听该写节点的删除事件

写锁:若当前客户端创建的znode前无节点(即为第一个节点)则获得锁,否则等待并监听前一节点的删除事件

读锁:        写锁:  

入门简介,不妨见:https://mp.weixin.qq.com/s/jr6pUFurUdBBoKGf9sY-JA

=============以下为正文=============

Apache Zookeeper 由 Apache Hadoop 的 Zookeeper 子项目发展而来,现已经成为 Apache 的顶级项目,它是一个开放源码的分布式应用程序协调服务,是Google Chubby的一个开源实现。它是一个为分布式应用提供一致性服务的组件,提供的功能包括:配置管理,名字服务,提供分布式同步、队列管理、集群管理等。

使用场景(即上述的功能):典型应用场景篇一典型应用场景篇二

原理:Zookeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。

1、安装

Zookeeper有两种运行模式:

1.1、独立模式(standalone mode)

(具体参考:http://blog.csdn.net/csfreebird/article/details/44006453

只运行在一台服务器上,适合测试环境。

1.2、复制模式(replicated mode)

运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble)。

Zookeeper通过复制来实现高可用性,只要集合体中半数以上的机器处于可用状态,它就能够保证服务继续。这跟Zookeeper的复制策略有关:Zookeeper确保对znode树的每一个修改都会被复制到集合体中超过半数的机器上。

由于ZooKeeper集群,会有一个Leader负责管理和协调其他集群服务器,因此服务器的数量通常都是奇数,例如3,5,7...等,这样2n+1的数量的服务器就可以允许最多n台服务器的失效。

(安装可参考:http://blog.csdn.net/csfreebird/article/details/44007295

这里以zookeeper-3.4.8为例:

1.2.1、下载解压

解压后目录结构为:

.
├── bin
├── build.xml
├── CHANGES.txt
├── conf
├── contrib
├── dist-maven
├── docs
├── ivysettings.xml
├── ivy.xml
├── lib
├── LICENSE.txt
├── NOTICE.txt
├── README_packaging.txt
├── README.txt
├── recipes
├── src
├── zookeeper-3.4.8.jar
├── zookeeper-3.4.8.jar.asc
├── zookeeper-3.4.8.jar.md5
└── zookeeper-3.4.8.jar.sha1

1.2.2、配置文件

进入conf目录, cp  zoo_sample.cfg  zoo.cfg  ,修改配置文件zoo.cfg为如下:

# The number of milliseconds of each tick
tickTime=
# The number of ticks that the initial
# synchronization phase can take
initLimit=
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/usr/local/zookeeper/zookeeper-3.4./zk_data
# the port at which the clients will connect
clientPort=
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=
#
# 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=
# Purge task interval in hours
# Set to "" to disable auto purge feature
#autopurge.purgeInterval=
server.=192.168.6.131::
server.=192.168.6.132::
server.=192.168.6.133::

各配置项的含义:

1. tickTime  = 2000:Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,每隔tickTime时间就会发送一个心跳。

2. initLimit: 配置 Zookeeper 接受客户端(此客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已超过initLimit个tickTime长度后 Zookeeper 服务器还没有收到客户端的返回信息,则表明客户端连接失败。总的时间长度就是 initLimit * tickTime 秒。

3. syncLimit: 配置 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 syncLimit * tickTime 秒 

4. dataDir:   Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。

5. dataLogDir:若没提供的话则用dataDir。zookeeper的持久化都存储在这两个目录里。dataLogDir里是放到的顺序日志(WAL)。而dataDir里放的是内存数据结构的snapshot,便于快速恢复。为了达到性能最大化,一般建议把dataDir和dataLogDir分到不同的磁盘上,以充分利用磁盘顺序写的特性。

6. clientPort:Zookeeper服务器监听的端口,以接受客户端的访问请求。

7. server.A=B:C:D:其中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,此端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。

每个节点的配置文件都一样。

更多可参考Zookeeper的配置

1.2.3、添加myid文件

除了修改 zoo.cfg 配置文件,集群模式下还要配置一个文件 myid,这个文件在 上述dataDir 指定的目录下,这个文件里面就只有一个数据就是 A 的值,Zookeeper 启动时会读取这个文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是那个 server。

1.2.4、启动/结束

bin/zkServer.sh start|start-foreground|stop|restart|status|upgrade|print-cmd ,启动后默认在bin下产生日志文件zookeeper.out

. 启动ZK服务:       bin/zkServer.sh start
. 查看ZK服务状态: bin/zkServer.sh status
. 停止ZK服务: bin/zkServer.sh stop
. 重启ZK服务: bin/zkServer.sh restart

(启动后在zoo.cfg所指定的dataDir下有version-2文件夹(下有log.1文件)和zookeeper_server.pid文件)

启动后可以借助下面的命令行客户端看是否能连上以确定是否成功启动,也可使用四字命令(如 echo stat|netcat localhost 2181 )快速确定节点状态

2、使用

2.1、Shell客户端

2.1.1 zk命令

命令行客户端连接ZooKeeper: ./bin/zkCli.sh -server localhost: ,连接成功后,会输出 ZooKeeper 的相关环境以及配置信息。并能进行一些操作:

. 显示根目录下、文件: ls /        使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
. 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
. 创建文件并设置初始内容:create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串
. 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
. 修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置
. 删除文件: delete /zk 将刚才创建的 znode 删除
. 删除目录(即使非空):rmr 目录 如可用于删除Kafka的某个Consumer Group
. 退出客户端: quit
. 帮助命令: help

客户端连接后,用get / 命令可以发现此时只有zookeeper一项;如果此Zookeeper用于对Kafka或JStorm等提供服务,则还会有相应的其他目录。

2.1.2 四字命令

此外,也可通过四字命令更方便地获取服务端信息, 四字命令的用法为 echo 四字命令|netcat localhost 2181 ,常用的四字命令如下:

  1. conf:输出Zookeeper服务器配置的详细信息
  2. cons:输出所有连接到服务器的客户端的完全的连接/会话的详细信息。包括“接收/发送”的包数量、会话ID、操作延迟、最后的操作执行等
  3. dump:输出未经处理的会话和临时节点
  4. envi:输出关于服务器运行环境的详细信息
  5. reqs:输出未经处理的请求
  6. ruok:测试服务是否处于正确状态。若是则会返回“imok”,否则不做任何反应
  7. stat:输出关于性能和连接的客户端的列表。(通过此命令也可查看节点是leader还是follower)
  8. wchs:输出服务器watch的详细信息
  9. wchc:通过session列出服务器watch的详细信息,它的输出是一个与watch相关的会话的列表
  10. wchp:通过路径列出服务器watch的详细信息,它输出一个与session相关的路径
  11. mntr:输出一些Zookeeper运行时信息,通过对这些返回结果的解析可以达到监控效果

2.2、Java客户端

使用Java进行Zookeeper的CRUD操作,示例如下:

 package cn.edu.buaa.act.test.TestZookeeper;

 import java.io.IOException;

 import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper; /**
* 此类包含两个主要的 ZooKeeper 函数,分别为 createZKInstance ()和 ZKOperations ()。<br>
* <br>
*
* (1)createZKInstance ()函数负责对 ZooKeeper 实例 zk 进行初始化。 ZooKeeper 类有两个构造函数,我们这里使用
* “ ZooKeeper ( String connectString, , int sessionTimeout, , Watcher watcher
* )”对其进行初始化。因此,我们需要提供初始化所需的,连接字符串信息,会话超时时间,以及一个 watcher 实例。<br>
* <br>
*
* (2)ZKOperations ()函数是我们所定义的对节点的一系列操作。它包括:创建 ZooKeeper
* 节点、查看节点、修改节点数据、查看修改后节点数据、删除节点、查看节点是否存在。另外,需要注意的是:在创建节点的时候,需要提供节点的名称、数据、
* 权限以及节点类型。此外,使用 exists 函数时,如果节点不存在将返回一个 null 值。
*/
public class ZookeeperTest { // 会话超时时间,设置为与系统默认时间一致 private static final int SESSION_TIMEOUT = 30000; // 创建 ZooKeeper 实例 ZooKeeper zk; // 创建 Watcher 实例 Watcher wh = new Watcher() { public void process(org.apache.zookeeper.WatchedEvent event) {
System.out.println("event=" + event.toString());
} }; // 初始化 ZooKeeper 实例 private void createZKInstance() throws IOException {
zk = new ZooKeeper("192.168.6.131:2181,192.168.6.132:2181,192.168.6.133:2181", ZookeeperTest.SESSION_TIMEOUT,
this.wh);
} private void ZKOperations() throws IOException, InterruptedException, KeeperException { System.out.println("\n 创建 ZooKeeper 节点 (znode : zoo2, 数据: myData2 ,权限: OPEN_ACL_UNSAFE ,节点类型: Persistent");
zk.create("/zoo2", "myData2".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("\n 查看是否创建成功: ");
System.out.println(new String(zk.getData("/zoo2", false, null))); System.out.println("\n 修改节点数据 ");
zk.setData("/zoo2", "shenlan211314".getBytes(), -1); System.out.println("\n 查看是否修改成功: ");
System.out.println(new String(zk.getData("/zoo2", false, null))); System.out.println("\n 删除节点 ");
zk.delete("/zoo2", -1); System.out.println("\n 查看节点是否被删除: ");
System.out.println(" 节点状态: [" + zk.exists("/zoo2", false) + "]"); } private void ZKClose() throws InterruptedException {
zk.close();
} public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
ZookeeperTest dm = new ZookeeperTest();
dm.createZKInstance();
dm.ZKOperations();
dm.ZKClose();
} }

相关Maven依赖:

        <dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.2</version>
</dependency>

3、Zookeeper dashboard

GitHub Zookeeper UI Dashboard

4、进阶

4.1 数据及日志维护

  Zookeeper的数据文件存放在配置中指定的dataDir中,每个数据文件名都以snapshot开头,每个数据文件为zookeeper某个时刻数据全量快照。在zookeeper中,对数据的更新操作,包括创建节点、更新节点内容、删除节点都会记录事务日志;客户端对ZK的更新操作都是永久的,不可回退的。为做到这点,ZK会将每次更新操作以事务日志的形式写入磁盘,写入成功后才会给予客户端响应。zookeeper在完成若干次事务日志(snapCount)后会生成一次快照,把当前zk中的所有节点的状态以文件的形式dump到硬盘中,生成一个snapshot文件。这里的事务次数是可以配置,默认是100000个。

  Zookeeper的日志包括两个部分,一部分是系统日志,另一部分是事务日志。

  系统日志使用log4j进行管理,conf目录中有一个log4j配置文件,该配置文件默认没有打开滚动输出,需要用户自己配置,具体请参看log4j介绍。

  事务日志默认存放在dataDir中,当然可以使用dataLogDir指定存放的位置。正常运行过程中,针对所有更新操作,在返回客户端“更新成功”的响应前,ZK会确保已经将本次更新操作的事务日志写到磁盘上,只有这样,整个更新操作才会生效。每触发一次数据快照,就会生成一个新的事务日志。

  默认情况下,zk不会自动清理数据文件和日志文件,因此需要管理员自己清理。我们可以使用ZK的工具类PurgeTxnLog进行清理,当然,我们也可以写脚本自己维护,同时可以使用工具慢慢清理,避免占用大量IO。清理脚本如下:

  

务必注意:

  如果长时间不清理,切忌同一时间使用rm命令同时删除大量文件,这样会造成IO利用率瞬间飙升,zookeeper的连接会出现断连或session超时,影响现网业务使用。

  另外,对于每一个数据文件,它都是某一时刻的完整快照,我们可以定时将该文件备份,方便对数据进行还原或将zookeeper直接迁移到另外一个集群。

4.2 数据清理

具体详见:http://nileader.blog.51cto.com/1381108/932156

4.3 可视化事务日志

具体详见:http://nileader.blog.51cto.com/1381108/926753

Zookeeper运行久了产生的日志和事务数据非常大,在我们的实践中甚至由于从没清理导致磁盘满了,虽然Zookeeper节点没死,但ZK UI监控上显示出“This instance is not serviceing requests”。由于Zookeeper不能提供服务,JStorm节点就死了,Kafka节点也无法提供服务(没死),清理数据后就好了。

上述参考资料里列出了几种方法,我们采取定时自动清理的做法(每次留10个),写如下脚本,加入crontab定期执行:

#snapshot file dir
dataDir=/usr/local/zookeeper/zookeeper-3.4./zk_data/version-
#tran log dir
dataLogDir=/usr/local/zookeeper/zookeeper-3.4./zk_data/version-
#zk log dir
#Leave files
count=
count=$[$count+]
ls -t $dataLogDir/log.* | tail -n +$count | xargs rm -f
ls -t $dataDir/snapshot.* | tail -n +$count | xargs rm -f

4.4 权限控制

具体参见:使用super身份对有权限的节点进行操作 和 ZooKeeper权限控制

4.5 Zookeeper应用场景及实践

经典应用:

1)NameService

不多说,本身就是一个共享的树形文件系统

2)配置管理

不同的process watch 自己的配置znode, 当配置变化可以收到通知

3)集群membership管理

集群节点下,每个server对应一个EPHEMERAL的节点,节点名就是server name/ IP,当它和zookeeper的心跳断了,对应的节点被删除,并且所有集群内的节点可以收到新的child List,保证每个server都知道进群内的其他server

4) master选举

和3)类似,但是节点换成EPHEMERAL_SEQUENTIAL的,大家都约定以当前编号最小的server做为master。当master挂了,每个server都会被通知到一份新的server 列表,大家都把编号最小的那个作为master

5) 分布式独占锁

类似Java synchronized的语义 在约定的锁节点上创建EPHEMERAL_SEQUENTIAL节点作为等待队列,如果编号最小的就是自己就获得锁,否则wait()住。获得锁的process通过删除自己的节点释放锁,这样每个等待的process会得到通知,在事件处理函数里判断自己是不是最小的编号,如果是则唤醒之前wait住的线程,这样本进程就获得了锁

6)barrier屏障

意思是所有相关的process都到达齐了再往下执行。实现方法,也是在barrier节点创建EPHEMERAL_SEQUENTIAL的节点,每个process都会得到变化后的children list,当大小为barrier要求数的时候,各个process继续执行。 zookeeper作为分布式process协调的中介,本身是一个单点failure点,所以它本身也做为一个集群,通常部署2n + 1台, 客户端连接不同的zookeeper server,但是得到视图是一样的,这点是zookeeper内部保证的

Zookeeper客户端主要有原生客户端、zclient、Apache Curator等。

以下代码使用Zookeeper原生的客户端(Zookeeper源码里),推荐使用更方便的客户端 Curator

4.5.1 配置管理

 package cn.edu.buaa.act.test.TestZookeeper;

 import java.io.IOException;

 import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids; /**
* <h1>配置管理</h1><br/>
* Zookeeper很容易实现集中式的配置管理:<br/>
*
* <p>
* 比如将APP1的所有配置配置到/APP1
* node下,APP1所有机器一启动就对/APP1这个节点进行监控(zk.exist("/APP1",true)),并且实现回调方法Watcher.
* </p>
*
* <p>
* 那么在zookeeper上/APP1
* znode节点下数据发生变化的时候,每个机器都会收到通知,Watcher方法将会被执行,那么应用再取下数据即可(zk.getData("/APP1",
* false,null));
* </p>
*
* @author zsm Email: qzdhzsm@163.com
* @date Sep 13, 2016 8:31:08 PM
* @version 1.0
* @parameter
* @since
* @return
*
*/
public class ManageConfiguration {
private static final int SESSION_TIMEOUT = 30000;
private static final String zookeeperAddr = "192.168.6.131:2181,192.168.6.132:2181,192.168.6.133:2181";
private static final String znodePath = "/zsm_dbIP"; private ZooKeeper zk; public ManageConfiguration() throws KeeperException, InterruptedException, IOException {
Watcher wh = new Watcher() {
public void process(org.apache.zookeeper.WatchedEvent event) {
try {
System.out.println("db ip changed,new value:" + new String(zk.getData(znodePath, true, null)));
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}; // 初始化 ZooKeeper 实例,初始化时提供的Watcher就会触发一次
zk = new ZooKeeper(zookeeperAddr, SESSION_TIMEOUT, wh); {
// 为了确保节点存在,不存在则先创建
if (zk.exists(znodePath, false) == null) {
zk.create(znodePath, "192.168.0.7".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("节点不存在,新建节点:" + znodePath + "=" + new String(zk.getData(znodePath, true, null)));
}
} } public static void main(String[] args) throws InterruptedException, KeeperException, IOException {
new ManageConfiguration();
while (true) {
;
}
}
}

4.5.2 集群管理

 package cn.edu.buaa.act.test.TestZookeeper;

 import java.io.IOException;

 import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper; /**
* <h1>集群管理</h1> <br/>
*
* <pre>
* 在 Zookeeper 上创建一个 EPHEMERAL 类型的节点,然后每个 Server 在它们创建目录节点的父目录节点上调用getChildren(String path, boolean watch) 方法并设置 watch 为 true
* </pre>
*
* <pre>
* 由于是 EPHEMERAL 目录节点,当创建它的 Server 死去,这个目录节点也随之被删除,所以 Children 将会变化,这时
* getChildren上的 Watch 将会被调用,所以其它 Server 就知道已经有某台 Server 死去了。新增 Server 同理。
* </pre>
*
* <pre>
* 若创建的是EPHEMERAL_SEQUENTIAL 节点,节点名会自动被append上一个唯一编号。可以在节点加入或删除触发wh时取编号最小的作为Leader,实现master选举
* </pre>
*
* @author zsm
* @date Sep 13, 2016 8:31:08 PM
* @version 1.0
* @parameter
* @since
* @return
*/
public class ManageCluster {
private static final int SESSION_TIMEOUT = 30000;
private static final String zookeeperAddr = "192.168.6.131:2181,192.168.6.132:2181,192.168.6.133:2181";
private static final String znodePath = "/zsm_Nodes"; private ZooKeeper zk; public ManageCluster(String thisNodeID) throws IOException, KeeperException, InterruptedException { Watcher wh = new Watcher() {
public void process(org.apache.zookeeper.WatchedEvent event) {
// System.out.println("*********wh1:event=" + event.toString() +
// " ********");
try {
System.out.println("节点变化,现有所有节点:" + zk.getChildren(znodePath, true));
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}; // 初始化 ZooKeeper 实例,初始化时提供的Watcher就会触发一次
zk = new ZooKeeper(zookeeperAddr, SESSION_TIMEOUT, wh); {// 根节点不存在的话创建PERSISTENT根节点
if (zk.exists(znodePath, null) == null) {
zk.create(znodePath, "root node".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
} // 创建EPHEMERAL_SEQUENTIAL节点
zk.create(znodePath + "/" + thisNodeID, thisNodeID.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL); // 在父节点getChildren,true
zk.getChildren(znodePath, true); } public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// TODO Auto-generated method stub
if (args.length < 0) {
System.out.println("args length is <0.");
System.exit(1);
}
new ManageCluster(args[0]);
while (true) {
;
}
} }

4.5.3 分布式同步锁、队列等

 package cn.edu.buaa.act.test.TestZookeeper;

 import java.io.IOException;
import java.util.Arrays;
import java.util.List; import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper; /**
* <pre>
* 分布式共享锁,与通过Zookeeper管理Cluster类似,只是每次触发Watcher后的操作,取现有所有节点后有下一步操作: 若最小节点等于当前节点,
* 则获得锁.
*
* <pre/>
*
* <pre>
* 如果所有节点的nodeid都一样,则各节点优先级一样,先进先得到锁;若不同节点的nodeid不能一样.则nodeid越小优先级越大
*
* <pre/>
*
* @author zsm
* @date 2016年9月18日 下午10:15:24
* @version 1.0
* @parameter
* @since
* @return
*/
public class T3_ManageLocks {
private static final int SESSION_TIMEOUT = 5000;
private static final String zookeeperAddr = "192.168.6.131:2181,192.168.6.132:2181,192.168.6.133:2181";
private static final String znodePath = "/zsm_Locks"; private ZooKeeper zk;
private static String thisNodeID; public T3_ManageLocks(String thisNodeID) throws IOException, KeeperException, InterruptedException {
T3_ManageLocks.thisNodeID = thisNodeID; Watcher wh = new Watcher() {
public void process(org.apache.zookeeper.WatchedEvent event) {
// System.out.println("*********wh1:event=" + event.toString() +
// " ********");
try {
List<String> nodeListTmp = zk.getChildren(znodePath, true);
System.out.println("节点变化,现有所有节点:" + nodeListTmp); String[] nodeList = nodeListTmp.toArray(new String[nodeListTmp.size()]);
Arrays.sort(nodeList); String nodeIdWithLock = new String(zk.getData(znodePath + "/" + nodeList[0], null, null));
System.out.println("curnode: " + T3_ManageLocks.thisNodeID + " node with lock: " + nodeIdWithLock);
if (nodeIdWithLock.equals(T3_ManageLocks.thisNodeID)) {
System.out.println("当前节点 " + nodeIdWithLock + " 获得锁");
// do something then System.exit(0);
} } catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}; // 初始化 ZooKeeper 实例,初始化时提供的Watcher就会触发一次
zk = new ZooKeeper(zookeeperAddr, SESSION_TIMEOUT, wh); {// 根节点不存在的话创建PERSISTENT根节点
if (zk.exists(znodePath, null) == null) {
zk.create(znodePath, "root node".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
} // 创建EPHEMERAL_SEQUENTIAL节点
zk.create(znodePath + "/" + thisNodeID, thisNodeID.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL); // 在父节点getChildren,true
// zk.getChildren(znodePath, true); } public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// TODO Auto-generated method stub
if (args.length < 0) {
System.out.println("args length is <0.");
System.exit(1);
}
new T3_ManageLocks(args[0]);
while (true) {
;
}
}
}

5、参考资料

1、http://blog.csdn.net/csfreebird/article/details/43984425(安装)

2、http://www.cnblogs.com/yuyijq/p/3424473.html(Zookeeper系列)

3、http://www.blogjava.net/BucketLi/archive/2010/12/21/341268.html(使用和原理探究)

4、http://data.qq.com/article?id=2863(全。腾讯大数据之Zookeeper运营经验分享)

Zookeeper集群的安装和使用的更多相关文章

  1. ZooKeeper 集群的安装、配置---Dubbo 注册中心

    ZooKeeper 集群的安装.配置.高可用测试 Dubbo 注册中心集群 Zookeeper-3.4.6 Dubbo 建议使用 Zookeeper 作为服务的注册中心. Zookeeper 集群中只 ...

  2. Zookeeper 集群的安装及高可用性验证已完成!

    安装包 kafka_2.12-0.10.2.0.tgz zookeeper-3.3.5.tar.gz Java 环境 Zookeeper 和 Kafka 的运行都需要 Java 环境,Kafka 默认 ...

  3. Dubbo入门到精通学习笔记(十三):ZooKeeper集群的安装、配置、高可用测试、升级、迁移

    文章目录 ZooKeeper集群的安装.配置.高可用测试 ZooKeeper 与 Dubbo 服务集群架构图 1. 修改操作系统的/etc/hosts 文件,添加 IP 与主机名映射: 2. 下载或上 ...

  4. zookeeper集群环境安装配置

    众所周知,Zookeeper有三种不同的运行环境,包括:单机环境.集群环境和集群伪分布式环境 在此介绍的是集群环境的安装配置 一.下载: http://apache.fayea.com/zookeep ...

  5. zookeeper集群的安装

    顾名思义zookeeper就是动物园管理员,他是用来管hadoop(大象).Hive(蜜蜂).pig(小猪)的管理员, Apache Hbase和 Apache Solr 的分布式集群都用到了zook ...

  6. ZooKeeper集群的安装、配置、高可用测试

    Dubbo注册中心集群Zookeeper-3.4.6 Dubbo建议使用Zookeeper作为服务的注册中心. Zookeeper集群中只要有过半的节点是正常的情况下,那么整个集群对外就是可用的.正是 ...

  7. ZooKeeper集群详细安装教程

    1. 安装JDK 1.1 官网下载JDK 进入网址<a href="http://www.oracle.com/technetwork/java/javase/downloads/jd ...

  8. zookeeper集群的安装和配置

    Zookeeper的目的是封装好复杂易出错的关键服务,将简单易用的接口和性能高效.功能稳定的系统提供给用户.Zookeeper有两种运行模式,单机模式(Standalone)和集群模式(Distrib ...

  9. 大数据集群环境 zookeeper集群环境安装

    大数据集群环境 zookeeper集群环境准备 zookeeper集群安装脚本,如果安装需要保持zookeeper保持相同目录,并且有可执行权限,需要准备如下 编写脚本: vi zkInstall.s ...

随机推荐

  1. JNI系列——C文件中使用logcat

    1.在Android.mk文件中添加:LOCAL_LDLIBS += -llog 注:加载的这个库在NDK对应平台目录下的lib目录中. 2.在C文件中添加如下内容: #include <and ...

  2. Qt5.3.0 for Android开发环境配置

    1.去官网下载Qt5.3.0 for Android 2.去http://developer.android.com下载Ndk 和SDk            3.去http://ant.apache ...

  3. Android:View随手指移动

    View的自动移动,我们可以设置动画,如之类提到的 ViewCompat,Animation. 如何是View随着手指的移动而移动呢? 在onTouch事件实现 @Overridepublic boo ...

  4. [转]JDBC中日期时间的处理技巧

    Java中用类java.util.Date对日期/时间做了封装,此类提供了对年.月.日.时.分.秒.毫秒以及时区的控制方法,同时也提供一些工具方法,比如日期/时间的比较,前后判断等. java.uti ...

  5. Jenkins_多项目构建(二):使用Maven聚集关系

        一.假设有四个Maven项目 1.soa-dub-parent:父项目 1 2 3 4 5 <modules>         <module>../soa-dub-f ...

  6. Java算法-选择排序

    (转载出处) 选择排序的基本思想是遍历数组的过程中,以 i 代表当前需要排序的序号,则需要在剩余的 [i…n-1] 中找出其中的最小值,然后将找到的最小值与 i 指向的值进行交换.因为每一趟确定元素的 ...

  7. Java 垃圾收集机制

    对象引用 Java 中的垃圾回收一般是在 Java 堆中进行,因为堆中几乎存放了 Java 中所有的对象实例.谈到 Java 堆中的垃圾回收,自然要谈到引用.在 JDK1.2 之前,Java 中的引用 ...

  8. 使用IDEA和gradle搭建Spring MVC和MyBatis开发环境

    1. 概述 Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具. 它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐 ...

  9. MySQL 1045登录失败

    当你登录MySQL数据库出现:Error 1045错误时(如下图),就表明你输入的用户名或密码错误被拒绝访问了,最简单的解决方法就是将MySQL数据库卸载然后重装,但这样的缺点就是就以前的数据库中的信 ...

  10. Servlet、Filter和Listener

    Java Servlet是与平台无关的服务器端组件,运行于Servlet容器中(如Tomcat),Servlet容器负责Servlet和客户端的通信以及调用Servlet的方法,Servlet和客户端 ...