Zookeeper配置和使用

来源:互联网 发布:江苏移动网络怎么样 编辑:程序博客网 时间:2024/06/05 01:55

转载:http://blog.csdn.net/tswisdom/article/details/41522041

转载:http://blog.csdn.net/tswisdom/article/details/41522099


一、Zookeeper的环境搭建

Zookeeper安装方式有三种,单机模式、伪集群模式以及集群模式
1.单机模式:Zookeeper只运行在一台服务器上,适合测试环境;
2.伪集群模式:就是在一台物理机上运行多个Zookeeper 实例。
3.集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble)。
Zookeeper通过复制来实现高可用性,只要集合体中半数以上的机器处于可用状态,它就能够保证服务继续。

1 Zookeeper的单机模式搭建

(1)下载ZooKeeper:https://zookeeper.apache.org/releases.html
(2)解压:tar -zxvf zookeeper-3.4.5.tar.gz 重命名:mv zookeeper-3.4.5 zk
(3)配置文件:在conf目录下删除zoo_sample.cfg文件,创建一个配置文件zoo.cfg。

        tickTime=2000    dataDir=/usr/local/zk/data    dataLogDir=/usr/local/zk/dataLog            clientPort=2181
(4)配置环境变量:为了今后操作方便,我们需要对Zookeeper的环境变量进行配置,方法如下在/etc/profile文件中加入如下内容:

export ZOOKEEPER_HOME=/usr/local/zkexport PATH=.:HADOOP H OME/bin: ZOOKEEPER_HOME/bin:JAVA H OME/bin: PATH
(5)启动ZooKeeper的Server:zkServer.sh start;关闭ZooKeeper的Server:zkServer.sh stop

1.2 Zookeeper的伪集群模式搭建

Zookeeper不但可以在单机上运行单机模式Zookeeper,而且可以在单机模拟集群模式 Zookeeper的运行,也就是将不同节点运行在同一台机器。

我们知道伪分布模式下Hadoop的操作和分布式模式下有着很大的不同,但是在集群为分布 式模式下对Zookeeper的操作却和集群模式下没有本质的区别。显然,集群伪分布式模式为我们体验Zookeeper和做一些尝试性的实验提供了很大 的便利。

比如,我们在实验的时候,可以先使用少量数据在集群伪分布模式下进行测试。当测试可行的时候,再将数据移植到集群模式进行真实的数据实验。这样不 但保证了它的可行性,同时大大提高了实验的效率。这种搭建方式,比较简便,成本比较低,适合测试和学习,如果你的手头机器不足,就可以在一台机器上部署了 3个server。

1.2.1. 注意事项

在一台机器上部署了3个server,需要注意的是在集群为分布式模式下我们使用的每个配置文档模拟一台机器,也就是说单台机器及上运行多个Zookeeper实例。但是,必须保证每个配置文档的各个端口号不能冲突,除了clientPort不同之外,dataDir也不同。另外,还要在dataDir所对应的目录中创建myid文件来指定对应的Zookeeper服务器实例
  • (1)clientPort端口:如果在1台机器上部署多个server,那么每台机器都要不同的 clientPort,比如 server1是2181,server2是2182,server3是2183,
  • (2)dataDir和dataLogDir:dataDir和dataLogDir也需要区分下,将数据文件和日志文件分开存放,同时每个server的这两变量所对应的路径都是不同的。
  • (3)server.X和myid: server.X 这个数字就是对应/data/myid中的数字。在3个server的myid文件中分别写入了0,1,2,那么每个server中的zoo.cfg都配 server.0 server.1,server.2就行了。因为在同一台机器上,后面连着的2个端口,3个server都不要一样,否则端口冲突。
下面是我所配置的集群伪分布模式,分别通过zoo1.cfg、zoo2.cfg、zoo3.cfg来模拟由三台机器的Zookeeper集群。详见下图1.1-1.3
代码清单 zoo1.cfg

# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.dataDir=/usr/local/zk/data_1# the port at which the clients will connectclientPort=2181#the location of the log filedataLogDir=/usr/local/zk/logs_1server.0=localhost:2287:3387server.1=localhost:2288:3388server.2=localhost:2289:3389

代码清单 zoo2.cfg

# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.dataDir=/usr/local/zk/data_2# the port at which the clients will connectclientPort=2182#the location of the log filedataLogDir=/usr/local/zk/logs_2server.0=localhost:2287:3387server.1=localhost:2288:3388server.2=localhost:2289:3389

代码清单 zoo3.cfg

# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.dataDir=/usr/local/zk/data_3# the port at which the clients will connectclientPort=2183#the location of the log filedataLogDir=/usr/local/zk/logs_3server.0=localhost:2287:3387server.1=localhost:2288:3388server.2=localhost:2289:3389

1.2.2 启动

在集群为分布式下,我们只有一台机器,按时要运行三个Zookeeper实例。此时,如果在使用单机模式的启动命令是行不通的。此时,只要通过下面三条命令就能运行前面所配置的Zookeeper服务。如下所示:

zkServer.sh start zoo1.shzkServer.sh start zoo2.shzkServer.sh start zoo3.sh

在运行完第一条指令之后,会出现一些错误异常,产生异常信息的原因是由于Zookeeper服务的每个实例都拥有全局配置信息,他们在启动的时候会随时随地的进行Leader选举操作。此时,第一个启动的Zookeeper需要和另外两个Zookeeper实例进行通信。但是,另外两个Zookeeper实例还没有启动起来,因此就产生了这样的异样信息。
我们直接将其忽略即可,待把图中“2号”和“3号”Zookeeper实例启动起来之后,相应的异常信息自然会消失。此时,可以通过下面三条命令,来查询。

 zkServer.sh status zoo1.cfg zkServer.sh status zoo2.cfg zkServer.sh status zoo3.cfg

1.3 Zookeeper的集群模式搭建

为了获得可靠地Zookeeper服务,用户应该在一个机群上部署Zookeeper。只要机群上大多数的Zookeeper服务启动了,那么总的Zookeeper服务将是可用的。集群的配置方式,和前两种类似,同样需要进行环境变量的配置。在每台机器上conf/zoo.cf配置文件的参数设置相同

1.3.1 创建myid

在dataDir(/usr/local/zk/data)目录创建myid文件
Server0机器的内容为:0
Server1机器的内容为:1
Server2机器的内容为:2

1.3.2 编写配置文件

在conf目录下删除zoo_sample.cfg文件,创建一个配置文件zoo.cfg,如图2.4所示。
代码清单 2.4 zoo.cfg中的参数设置

# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.dataDir=/usr/local/zk/data# the port at which the clients will connectclientPort=2183#the location of the log filedataLogDir=/usr/local/zk/logserver.0=hadoop:2288:3388server.1=hadoop0:2288:3388server.2=hadoop1:2288:3388

1.3.3 启动

分别在3台机器上启动ZooKeeper的Server:zkServer.sh start;


二、Zookeeper的配置

Zookeeper的功能特性是通过Zookeeper配置文件来进行控制管理的(zoo.cfg).这样的设计其实有其自身的原因,通过前面对Zookeeper的配置可以看出,在对Zookeeper集群进行配置的时候,它的配置文档是完全相同的。集群伪分布模式中,有少部分是不同的。这样的配置方式使得在部署Zookeeper服务的时候非常方便。如果服务器使用不同的配置文件,必须确保不同配置文件中的服务器列表相匹配。
在设置Zookeeper配置文档时候,某些参数是可选的,某些是必须的。这些必须参数就构成了Zookeeper配置文档的最低配置要求。另外,若要对Zookeeper进行更详细的配置,可以参考下面的内容。

2.1 基本配置

下面是在最低配置要求中必须配置的参数:
1.client:监听客户端连接的端口。
2.tick Time:基本事件单元,这个时间是作为Zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,每隔tickTime时间就会发送一个心跳;最小的session过期时间为2倍tickTime   
3.dataDir:存储内存中数据库快照的位置,如果不设置参数,更新食物的日志将被存储到默认位置。
应该谨慎的选择日志存放的位置,使用专用的日志存储设备能够大大提高系统的性能,如果将日志存储在比较繁忙的存储设备上,那么将会很大程度上影响系统性能。

2.2 高级配置

下面是高级配置参数中可选配置参数,用户可以使用下面的参数来更好的规定Zookeeper的行为:
(1)dataLogdDir
这个操作让管理机器把事务日志写入“dataLogDir”所指定的目录中,而不是“dataDir”所指定的目录。这将允许使用一个专用的日志设备,帮助我们避免日志和快照的竞争。配置如下:

# the directory where the snapshot is storeddataDir=/usr/local/zk/data

(2)maxClientCnxns
这个操作将限制连接到Zookeeper的客户端数量,并限制并发连接的数量,通过IP来区分不同的客户端。此配置选项可以阻止某些类别的Dos攻击。将他设置为零或忽略不进行设置将会取消对并发连接的限制。
例如,此时我们将maxClientCnxns的值设为1,如下所示:

# set maxClientCnxnsmaxClientCnxns=1

启动Zookeeper之后,首先用一个客户端连接到Zookeeper服务器上。之后如果有第二个客户端尝试对Zookeeper进行连接,或者有某些隐式的对客户端的连接操作,将会触发Zookeeper的上述配置。
(3)minSessionTimeout和maxSessionTimeout
即最小的会话超时和最大的会话超时时间。在默认情况下,minSession=2*tickTime;maxSession=20*tickTime。

2.3 集群配置

(1)initLimit
此配置表示,允许follower(相对于Leaderer言的“客户端”)连接并同步到Leader的初始化连接时间,以tickTime为单位。当初始化连接时间超过该值,则表示连接失败。
(2)syncLimit
此配置项表示Leader与Follower之间发送消息时,请求和应答时间长度。如果follower在设置时间内不能与leader通信,那么此follower将会被丢弃。
(3)server.A=B:C:D
A:其中 A 是一个数字,表示这个是服务器的编号
B:是这个服务器的 ip 地址
C:Leader选举的端口
D:Zookeeper服务器之间的通信端口
(3)myid和zoo.cfg
除了修改 zoo.cfg 配置文件,集群模式下还要配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面就有一个数据就是 A 的值,Zookeeper 启动时会读取这个文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是那个 server。

三、Zookeeper的CLI

ZooKeeper 命令行界面(CLI)是用来与 ZooKeeper 集成作开发进行交互的。这是在调试和使用不同的选项时的工作有用。

为了执行ZooKeeper的CLI操作, ZooKeeper服务器首先要启动 (“bin/zkServer.sh start”) , 然后使用 ZooKeeper 客户端 (“bin/zkCli.sh”). 当客户端启动后,可以执行以下操作:


使用Zookeeper命令的简单操作步骤:

(1)使用ls命令查看当前Zookeeper中所包含的内容:ls /
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 2]

(2)创建一个新的Znode节点"zk",以及和它相关字符,执行命令:create /zk myData
[zk: localhost:2181(CONNECTED) 2] create /zk myData
Created /zk

(3)再次使用ls命令来查看现在Zookeeper的中所包含的内容:ls /
[zk: localhost:2181(CONNECTED) 3] ls /
[zk, zookeeper]

此时看到,zk节点已经被创建。
(4)使用get命令来确认第二步中所创建的Znode是否包含我们创建的字符串,执行命令:get /zk
[zk: localhost:2181(CONNECTED) 4] get /zk
myData
cZxid = 0x500000006
ctime = Fri Oct 17 03:54:20 PDT 2014
mZxid = 0x500000006
mtime = Fri Oct 17 03:54:20 PDT 2014
pZxid = 0x500000006
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0

(4)接下来通过set命令来对zk所关联的字符串进行设置,执行命令:set /zk jiang1234
[zk: localhost:2181(CONNECTED) 5] set /zk jiang2014
cZxid = 0x500000006
ctime = Fri Oct 17 03:54:20 PDT 2014
mZxid = 0x500000007
mtime = Fri Oct 17 03:55:50 PDT 2014
pZxid = 0x500000006
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0

(5)再次使用get命令来查看,上次修改的内容,执行命令:get /zk
[zk: localhost:2181(CONNECTED) 6] get /zk
jiang2014
cZxid = 0x500000006
ctime = Fri Oct 17 03:54:20 PDT 2014
mZxid = 0x500000007
mtime = Fri Oct 17 03:55:50 PDT 2014
pZxid = 0x500000006
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0

(6)下面我们将刚才创建的Znode删除,执行命令:delete /zk
[zk: localhost:2181(CONNECTED) 7] delete /zk
(7)最后再次使用ls命令查看Zookeeper中的内容,执行命令:ls /
[zk: localhost:2181(CONNECTED) 8] ls /
[zookeeper]

经过验证,zk节点已经删除。

四、Zookeeper的Java API

Zookeeper API共包含五个包,分别为:
(1)org.apache.zookeeper
(2)org.apache.zookeeper.data
(3)org.apache.zookeeper.server
(4)org.apache.zookeeper.server.quorum
(5)org.apache.zookeeper.server.upgrade
其中org.apache.zookeeper,包含Zookeeper类,他是我们编程时最常用的类文件。这个类是Zookeeper客户端的主要类文件。如果要使用Zookeeper服务,应用程序首先必须创建一个Zookeeper实例,这时就需要使用此类。一旦客户端和Zookeeper服务建立起了连接,Zookeeper系统将会给这次连接会话分配一个ID值,并且客户端将会周期性的向服务器端发送心跳来维持会话连接。只要连接有效,客户端就可以使用Zookeeper API来做相应处理了。
Zookeeper类提供了如图2.2所示的几类主要方法:


这里通过一个例子来简单介绍如何使用Zookeeper API 编写自己的应用程序,代码如下:

// 创建一个与服务器的连接ZooKeeper zk = new ZooKeeper("localhost:" + CLIENT_PORT,        ClientBase.CONNECTION_TIMEOUT, new Watcher() {            // 监控所有被触发的事件           public void process(WatchedEvent event) {                System.out.println("已经触发了" + event.getType() + "事件!");            }        }); // 创建一个目录节点zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,  CreateMode.PERSISTENT); // 创建一个子目录节点zk.create("/testRootPath/testChildPathOne", "testChildDataOne".getBytes(),  Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); System.out.println(new String(zk.getData("/testRootPath",false,null))); // 取出子目录节点列表System.out.println(zk.getChildren("/testRootPath",true)); // 修改子目录节点数据zk.setData("/testRootPath/testChildPathOne","modifyChildDataOne".getBytes(),-1); System.out.println("目录节点状态:["+zk.exists("/testRootPath",true)+"]"); // 创建另外一个子目录节点zk.create("/testRootPath/testChildPathTwo", "testChildDataTwo".getBytes(),   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo",true,null))); // 删除子目录节点zk.delete("/testRootPath/testChildPathTwo",-1); zk.delete("/testRootPath/testChildPathOne",-1); // 删除父目录节点zk.delete("/testRootPath",-1); // 关闭连接zk.close();

Zookeeper示例2如下:

package org.zk;import java.io.IOException;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class CreateGroup implements Watcher{    private static final int SESSION_TIMEOUT=5000;        private ZooKeeper zk;    private CountDownLatch connectedSignal=new CountDownLatch(1);    @Override    public void process(WatchedEvent event) {        if(event.getState()==KeeperState.SyncConnected){            connectedSignal.countDown();        }    }        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {        CreateGroup createGroup = new CreateGroup();        createGroup.connect(args[0]);        createGroup.create(args[1]);        createGroup.close();    }    private void close() throws InterruptedException {        zk.close();    }    private void create(String groupName) throws KeeperException, InterruptedException {        String path="/"+groupName;        if(zk.exists(path, false)== null){            zk.create(path, null/*data*/, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        }        System.out.println("Created:"+path);    }     private void connect(String hosts) throws IOException, InterruptedException {        zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);        connectedSignal.await();    }}

在上面代码中,main()方法执行时,创建了一个CreateGroup的实例并且调用了这个实例的connect()方法。connect方法实例化了一个新的ZooKeeper类的对象,这个类是客户端API中的主要类,并且负责维护客户端和ZooKeeper服务之间的连接。

ZooKeeper类的构造函数有三个参数:
第一个是:ZooKeeper服务的主机地址,可指定端口,默认端口是2181。
第二个是:以毫秒为单位的会话超时参数,这里我们设成5秒。
第三个是:参数是一个Watcher对象的实例。
Watcher对象接收来自于ZooKeeper的回调,以获得各种事件的通知。在这个例子中,CreateGroup是一个Watcher对象,因此我们将它传递给ZooKeeper的构造函数
当一个ZooKeeper的实例被创建时,会启动一个线程连接到ZooKeeper服务。由于对构造函数的调用是立即返回的,因此在使用新建的ZooKeeper对象之前一定要等待其与ZooKeeper服务之间的连接建立成功。我们使用Java的CountDownLatch类来阻止使用新建的ZooKeeper对象,直到这个ZooKeeper对象已经准备就绪。这就是Watcher类的用途,在它的接口中只有一个方法:

public void process(WatcherEvent event);

客户端已经与ZooKeeper建立连接后,Watcher的process()方法会被调用,参数是一个表示该连接的事件。在接收到一个连接事件(由Watcher.Event.KeeperState的枚举型值SyncConnected来表示)时,我们通过调用CountDownLatch的countDown()方法来递减它的计数器。锁存器(latch)被创建时带有一个值为1的计数器,用于表示在它释放所有等待线程之前需要发生的事件数。在调用一欢countDown()方法之后,计数器的值变为0,则await()方法返回。
现在connect()方法已经返回,下一个执行的是CreateGroup的create()方法。在这个方法中,我们使用ZooKeeper实例中的create()方法来创建一个新的ZooKeeper的znode。所需的参数包括:
1.路径:用字符串表示。
2.znode的内容:字节数组,本例中使用空值。
3.访问控制列表:简称ACL,本例中使用了完全开放的ACL,允许任何客户端对znode进行读写。
4.创建znode的类型:有两种类型的znode:短暂的和持久的。
创建znode的客户端断开连接时,无论客户端是明确断开还是因为任何原因而终止,短暂znode都会被ZooKeeper服务删除。与之相反,当客户端断开连接时,持久znode不会被删除。我们希望代表一个组的znode存活的时间应当比创建程序的生命周期要长,因此在本例中我们创建了一个持久的znode。
  create()方法的返回值是ZooKeeper所创建的路径,我们用这个返回值来打印一条表示路径成功创建的消息。当我们查看“顺序znode”(sequential znode)时.会发现create()方法返回的路径与传递给该方法的路径不同

加入组
下面的这一段程序用于注册组的成员。每个组成员将作为一个程序运行,并且加入到组中。当程序退出时,这个组成员应当从组中被删除。为了实现这一点,我们在ZooKeeper的命名空间中使用短暂znode来代表一个组成员。

package org.zk;import java.io.IOException;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.ZooDefs.Ids;public class JoinGroup extends ConnectionWatcher{    public void join(String groupName,String memberName) throws KeeperException, InterruptedException{        String path="/"+groupName+"/"+memberName;        String createdPath=zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);        System.out.println("Created:"+createdPath);    }    public static void main(String[] args) throws InterruptedException, IOException, KeeperException {        JoinGroup joinGroup = new JoinGroup();        joinGroup.connect(args[0]);        joinGroup.join(args[1], args[2]);                //stay alive until process is killed or thread is interrupted        Thread.sleep(Long.MAX_VALUE);    }}

JoinGroup 实现了这个想法。在基类ConnectionWatcher中,对创建和连接ZooKeeper实例的程序逻辑进行了重构。

package org.zk;import java.io.IOException;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooKeeper;public class ConnectionWatcher implements Watcher{    private static final int SESSION_TIMEOUT=5000;        protected ZooKeeper zk;    CountDownLatch connectedSignal=new CountDownLatch(1);    public void connect(String host) throws IOException, InterruptedException{        zk=new ZooKeeper(host, SESSION_TIMEOUT, this);        connectedSignal.await();    }    @Override    public void process(WatchedEvent event) {        if(event.getState()==KeeperState.SyncConnected){            connectedSignal.countDown();        }    }    public void close() throws InterruptedException{        zk.close();    }}

JoinGroup的代码与CreateGroup非常相似,在它的join()方法中,创建短暂znode,作为组znode的子节点,然后通过休眠来模拟正在做某种工作,直到该进程被强行终止。接着,你会看到随着进程终止,这个短暂znode被ZooKeeper删除。

列出组成员
现在,我们需要一段程序来查看组成员,参见如下代码:

package org.zk;import java.io.IOException;import java.util.List;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.ZooKeeper;public class ListGroup extends ConnectionWatcher {    public void list(String groupNmae) throws KeeperException, InterruptedException{        String path ="/"+groupNmae;        try {            List children = zk.getChildren(path, false);            if(children.isEmpty()){                System.out.printf("No memebers in group %s\n",groupNmae);                System.exit(1);            }            for(String child:children){                System.out.println(child);            }        } catch (KeeperException.NoNodeException e) {            System.out.printf("Group %s does not exist \n", groupNmae);            System.exit(1);        }     }    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {        ListGroup listGroup = new ListGroup();        listGroup.connect(args[0]);        listGroup.list(args[1]);        listGroup.close();    }}
在list()方法中,我们调用了getChildren()方法来检索并打印输出一个znode的子节点列表,调用参数为:该znode的路径和设为false的观察标志。如果在一个znode上设置了观察标志,那么一旦该znode的状态改变,关联的观察(Watcher)会被触发。虽然在这里我们可以不使用观察,但在查看一个znode的子节点时,也可以设置观察,让应用程序接收到组成员加入、退出和组被删除的有关通知。
在这段程序中,我们捕捉了KeeperException.NoNodeException异常,代表组的znode不存在时,这个异常就会被抛出。

下面看一下ListGroup程序的工作过程:虽然搭建了分布式的ZooKeeper,但分布式ZooKeeper启动运行比较耗时,我在这采用前面提到的复制模式下的ZooKeeper来进行测试。
首先我们得启动ZooKeeper,启动以后将上面的源程序放到Linux目录中并进行编译,我将其放到了"/usr/code"目录下,并在该目录下创建一个classes文件夹,用于存放生成字节码文件:

[root@hadoop ~]# cd /usr/code[root@hadoop code]# lsConnectionWatcher.java  DeleteGroup.java  ListGroup.javaclasses  CreateGroup.java  JoinGroup.java  PackageTest.java[root@hadoop code]# javac -d ./classes ConnectionWatcher.java[root@hadoop code]# javac -d ./classes *.java

由于目前我们还没有在组中添加任何成员,因此zoo是空的:

[root@hadoop code]# java org.zk.ListGroup  localhost zoo2014-10-30 01:52:19,703 [myid:] - INFO  [main:Environment@100] - Client environment:…………No memebers in group zoo

我们可以使用JoinGroup来向组中添加成员。在sleep语句的作用下,这些作为组成员的znode不会自己终止,所以我们可以,以后台进程的方式来启动他们:

[root@hadoop code]# java org.zk.JoinGroup localhost zoo duck &2014-10-30 02:06:05,018 [myid:] - INFO  [main:Environment@100] - Client environment:…………Created:/zoo/duck[root@hadoop code]# java org.zk.JoinGroup localhost zoo cow &2014-10-30 02:06:05,018 [myid:] - INFO  [main:Environment@100] - Client environment:…………Created:/zoo/cow[root@hadoop code]# java org.zk.JoinGroup localhost zoo goat &2014-10-30 02:06:05,018 [myid:] - INFO  [main:Environment@100] - Client environment:…………Created:/zoo/goat

最后一行命令保存了将goat添加到组中的java进程的ID。我们需要保存这个进程的ID,以便能够在查看组成员之后杀死进程。

[root@hadoop code]# 2014-10-30 03:15:30,619 [myid:] - INFO  [main:Environment@100] - Client environment:…………duckcowgoat
为了从组中删除一个成员,我们杀死了goat所对应的进程:

[root@hadoop code]# kill $goat_pid几秒钟之后,由于进程的ZooKeeper会话已经结束(超时为5秒),所以goat会从组成员列表消失,并且对应的短暂znode也已经被删除。[root@hadoop code]# java org.zk.ListGroup localhost zoo2014-10-30 03:23:41,120 [myid:] - INFO  [main:Environment@100] - Client environment:…………duckcow

对于参与到一个分布式系统中的节点,这样就有了一个建立节点列表的方法。这些节点也许彼此并不了解。例如,一个想使用列表中节点来完成某些工作的客户端,能够在这些节点不知道客户端的情况下发现它们。
最后,注意,组成员关系管理并不能解决与节点通信过程中出现的网络问题。即使一个节点是一个组中的成员,在与其通信的过程中仍然会出现故障,这种故障必须以一种合适的方式解决(重试、使用组中另外一个成员等)。



原创粉丝点击