ZooKeeper伪分布式集群安装及简单使用 java api

ZooKeeper整体介绍

一:环境

centos

jdk1.6

zookeeper-3.4.3 下载

二:配置

将解压出来的zookeeper 复制三份,这里分别叫做 zookeeper-1,zookeeper-2和zookeeper-3。

1.  zookeeper-1 配置:

创建data目录:/home/java2000_wl/hadoop/zookeeper-1/data
创建log目录:/home/java2000_wl/hadoop/zookeeper-1/logs
创建myid文件:/home/java2000_wl/hadoop/zookeeper-1/data/myid
内容:
1

创建/home/java2000_wl/hadoop/zookeeper-1/conf/zoo.cfg文件

内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/java2000_wl/hadoop/zookeeper-1/data
clientPort=2181
dataLogDir=/home/java2000_wl/hadoop/zookeeper-1/logs

server.1=127.0.0.1:4000:5000 
server.2=127.0.0.1:4001:5001
server.3=127.0.0.1:4002:5002



2.zookeeper-2 配置:

创建data目录:/home/java2000_wl/hadoop/zookeeper-2/data
创建log目录:/home/java2000_wl/hadoop/zookeeper-2/logs
创建myid文件:/home/java2000_wl/hadoop/zookeeper-2/data/myid
内容:
2

创建/home/java2000_wl/hadoop/zookeeper-2/conf/zoo.cfg文件
内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/java2000_wl/hadoop/zookeeper-2/data
clientPort=2182
dataLogDir=/home/java2000_wl/hadoop/zookeeper-2/logs

server.1=127.0.0.1:4000:5000 
server.2=127.0.0.1:4001:5001 
server.3=127.0.0.1:4002:5002


3.zookeeper-3 配置:

创建data目录:/home/java2000_wl/hadoop/zookeeper-3/data
创建log目录:/home/java2000_wl/hadoop/zookeeper-3/logs
创建myid文件:/home/java2000_wl/hadoop/zookeeper-3/data/myid
内容:
3

创建/home/java2000_wl/hadoop/zookeeper-3/conf/zoo.cfg文件
内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/java2000_wl/hadoop/zookeeper-3/data
clientPort=2183
dataLogDir=/home/java2000_wl/hadoop/zookeeper-3/logs

server.1=127.0.0.1:4000:5000 
server.2=127.0.0.1:4001:5001 
server.3=127.0.0.1:4002:5002


三:启动服务

分别进入三个服务的bin目录 启动服务

bin/zkServer.sh start

出现如下:
JMX enabled by default
Using config: D:\cygwin64\home\zookeeper-3.4.5_1\conf\zoo.cfg
Starting zookeeper ... STARTED

通过jps命令可以查看ZooKeeper服务器进程,名称为QuorumPeerMain。

四:客户端连接

成功启动zookeeper服务之后,输入下述命令,连接到zookeeper服务

./zkCli.sh -server 127.0.0.1:2181


WATCHER::

WatchedEvent state:SyncConnected type:N
[zk: localhost:2181(CONNECTED) 0] ls /
ZooKeeper -server host:port cmd args
        connect host:port
        get path [watch]
        ls path [watch]
        set path data [version]
        rmr path
        delquota [-n|-b] path
        quit
        printwatches on|off
        create [-s] [-e] path data acl
        stat path [watch]
        close
        ls2 path [watch]
        history
        listquota path
        setAcl path acl
        getAcl path
        sync path
        redo cmdno
        addauth scheme auth
        delete path [version]
        setquota -n|-b val path
[zk: localhost:2181(CONNECTED) 1]

可以通过ZooKeeper的脚本来查看启动状态,包括集群中各个结点的角色(或是Leader,或是Follower),如下所示,是在ZooKeeper集群中的每个结点上查询的结果


bin/zkServer.sh status

五:参数说明

参数名

说明

扫描二维码关注公众号,回复: 556924 查看本文章
clientPort 客户端连接server的端口,即对外服务端口,一般设置为2181吧。
dataDir 存储快照文件snapshot的目录。默认情况下,事务日志也会存储在这里。建议同时配置参数dataLogDir, 事务日志的写性能直接影响zk性能。
tickTime ZK中的一个时间单元。ZK中所有时间都是以这个时间单元为基础,进行整数倍配置的。例如,session的最小超时时间是2*tickTime。
dataLogDir 事务日志输出目录。尽量给事务日志的输出配置单独的磁盘或是挂载点,这将极大的提升ZK性能。
(No Java system property)
globalOutstandingLimit 最大请求堆积数。默认是1000。ZK运行的时候, 尽管server已经没有空闲来处理更多的客户端请求了,但是还是允许客户端将请求提交到服务器上来,以提高吞吐性能。当然,为了防止Server内存溢出,这个请求堆积数还是需要限制下的。
(Java system property:zookeeper.globalOutstandingLimit.)
preAllocSize 预先开辟磁盘空间,用于后续写入事务日志。默认是64M,每个事务日志大小就是64M。如果ZK的快照频率较大的话,建议适当减小这个参数。(Java system property:zookeeper.preAllocSize)
snapCount 每 进行snapCount次事务日志输出后,触发一次快照(snapshot), 此时,ZK会生成一个snapshot.*文件,同时创建一个新的事务日志文件log.*。默认是100000.(真正的代码实现中,会进行一定的随机数 处理,以避免所有服务器在同一时间进行快照而影响性能)(Java system property:zookeeper.snapCount)
traceFile 用于记录所有请求的log,一般调试过程中可以使用,但是生产环境不建议使用,会严重影响性能。(Java system property:?requestTraceFile)
maxClientCnxns 单 个客户端与单台服务器之间的连接数的限制,是ip级别的,默认是60,如果设置为0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端 机器与单台ZK服务器之间的连接数限制,不是针对指定客户端IP,也不是ZK集群的连接数限制,也不是单台ZK对所有客户端的连接数限制。指定客户端IP 的限制策略,这里有一个patch,可以尝试一下:http://rdc.taobao.com/team/jm/archives/1334(No Java system property)
clientPortAddress 对于多网卡的机器,可以为每个IP指定不同的监听端口。默认情况是所有IP都监听clientPort指定的端口。New in 3.3.0
minSessionTimeoutmaxSessionTimeout Session超时时间限制,如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。默认的Session超时时间是在2 * tickTime ~ 20 * tickTime这个范围 New in 3.3.0
fsync.warningthresholdms 事务日志输出时,如果调用fsync方法超过指定的超时时间,那么会在日志中输出警告信息。默认是1000ms。(Java system property:fsync.warningthresholdms)New in 3.3.4
autopurge.purgeInterval 在上文中已经提到,3.4.0及之后版本,ZK提供了自动清理事务日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是0,表示不开启自动清理功能。(No Java system property) New in 3.4.0
autopurge.snapRetainCount 这个参数和上面的参数搭配使用,这个参数指定了需要保留的文件数目。默认是保留3个。(No Java system property) New in 3.4.0
electionAlg 在 之前的版本中, 这个参数配置是允许我们选择leader选举算法,但是由于在以后的版本中,只会留下一种“TCP-based version of fast leader election”算法,所以这个参数目前看来没有用了,这里也不详细展开说了。(No Java system property)
initLimit Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader允许F在initLimit时间内完成这个工作。通常情况下,我们不用太在意这个参数的设置。如果ZK集群的数据量确实很大了,F在启动的时候,从Leader上同步数据的时间也会相应变长,因此在这种情况下,有必要适当调大这个参数了。(No Java system property)
syncLimit 在 运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。如果L发出心跳包在syncLimit之 后,还没有从F那里收到响应,那么就认为这个F已经不在线了。注意:不要把这个参数设置得过大,否则可能会掩盖一些问题。(No Java system property)
leaderServes 默认情况下,Leader是会接受客户端连接,并提供正常的读写服务。但是,如果你想让Leader专注于集群中机器的协调,那么可以将这个参数设置为no,这样一来,会大大提高写操作的性能。(Java system property: zookeeper.leaderServes)。
server.x=[hostname]:nnnnn[:nnnnn] 这里的x是一个数字,与myid文件中的id是一致的。右边可以配置两个端口,第一个端口用于F和L之间的数据同步和其它通信,第二个端口用于Leader选举过程中投票通信。
(No Java system property)
group.x=nnnnn[:nnnnn]weight.x=nnnnn 对机器分组和权重设置,可以 参见这里(No Java system property)
cnxTimeout Leader选举过程中,打开一次连接的超时时间,默认是5s。(Java system property: zookeeper.cnxTimeout)
zookeeper.DigestAuthenticationProvider
.superDigest
ZK权限设置相关,具体参见使用super身份对有权限的节点进行操作 和 ZooKeeper权限控制
skipACL 对所有客户端请求都不作ACL检查。如果之前节点上设置有权限限制,一旦服务器上打开这个开头,那么也将失效。(Java system property:zookeeper.skipACL)
forceSync 这个参数确定了是否需要在事务日志提交的时候调用FileChannel.force来保证数据完全同步到磁盘。(Java system property:zookeeper.forceSync)
jute.maxbuffer 每个节点最大数据量,是默认是1M。这个限制必须在server和client端都进行设置才会生效。(Java system property:jute.maxbuffer)




六:常用的四字命令

参数名

说明

conf 输出server的详细配置信息。New in 3.3.0

 

$>echo conf|nc localhost 2181
clientPort=2181
dataDir=/home/test/taokeeper/zk_data/version-2
dataLogDir=/test/admin/taokeeper/zk_log/version-2
tickTime=2000
maxClientCnxns=1000
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=2
initLimit=10
syncLimit=5
electionAlg=3
electionPort=3888
quorumPort=2888
peerType=0

cons 输出指定server上所有客户端连接的详细信息,包括客户端IP,会话ID等。
New in 3.3.0类似于这样的信息:

 

$>echo cons|nc localhost 2181
/1.2.3.4:43527[1](queued=0,recved=152802,sent=152806,sid=0x2389e662b98c424,lop=PING,
est=1350385542196,to=6000,lcxid=0×114,lzxid=0xffffffffffffffff,lresp=1350690663308,
llat=0,minlat=0,avglat=0,maxlat=483)
……

crst 功能性命令。重置所有连接的统计信息。New in 3.3.0
dump 这个命令针对Leader执行,用于输出所有等待队列中的会话和临时节点的信息。
envi 用于输出server的环境变量。包括操作系统环境和Java环境。
ruok 用于测试server是否处于无错状态。如果正常,则返回“imok”,否则没有任何响应。
注意:ruok不是一个特别有用的命令,它不能反映一个server是否处于正常工作。“stat”命令更靠谱。
stat 输出server简要状态和连接的客户端信息。
srvr 和stat类似,New in 3.3.0

 

$>echo stat|nc localhost 2181
Zookeeper version: 3.3.5-1301095, built on 03/15/2012 19:48 GMT
Clients:
/10.2.3.4:59179[1](queued=0,recved=44845,sent=44845)

Latency min/avg/max: 0/0/1036
Received: 2274602238
Sent: 2277795620
Outstanding: 0
Zxid: 0xa1b3503dd
Mode: leader
Node count: 37473

$>echo srvr|nc localhost 2181
Zookeeper version: 3.3.5-1301095, built on 03/15/2012 19:48 GMT
Latency min/avg/max: 0/0/980
Received: 2592698547
Sent: 2597713974
Outstanding: 0
Zxid: 0xa1b356b5b
Mode: follower
Node count: 37473

srst 重置server的统计信息。
wchs 列出所有watcher信息概要信息,数量等:New in 3.3.0

 

$>echo wchs|nc localhost 2181
3890 connections watching 537 paths
Total watches:6909

wchc 列出所有watcher信息,以watcher的session为归组单元排列,列出该会话订阅了哪些path:New in 3.3.0

 

$>echo wchc|nc localhost 2181
0x2389e662b97917f
/mytest/test/path1/node1
0x3389e65c83cd790
/mytest/test/path1/node2
0x1389e65c7ef6313
/mytest/test/path1/node3
/mytest/test/path1/node1

wchp 列出所有watcher信息,以watcher的path为归组单元排列,列出该path被哪些会话订阅着:New in 3.3.0

 

$>echo wchp|nc localhost 2181
/mytest/test/path1/node
0x1389e65c7eea4f5
0x1389e65c7ee2f68
/mytest/test/path1/node2
0x2389e662b967c29
/mytest/test/path1/node3
0x3389e65c83dd2e0
0x1389e65c7f0c37c
0x1389e65c7f0c364

注意,wchc和wchp这两个命令执行的输出结果都是针对session的,对于运维人员来说可视化效果并不理想,可以尝试将cons命令执行输出的信息整合起来,就可以用客户端IP来代替会话ID了,具体可以看这个实现:http://rdc.taobao.com/team/jm/archives/1450

mntr 输出一些ZK运行时信息,通过对这些返回结果的解析,可以达到监控的效果。New in 3.4.0

 

$ echo mntr | nc localhost 2185
zk_version 3.4.0
zk_avg_latency 0
zk_max_latency 0
zk_min_latency 0
zk_packets_received 70
zk_packets_sent 69
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count 4
zk_watch_count 0
zk_ephemerals_count 0
zk_approximate_data_size 27
zk_followers 4 – only exposed by the Leader
zk_synced_followers 4 – only exposed by the Leader
zk_pending_syncs 0 – only exposed by the Leader
zk_open_file_descriptor_count 23 – only available on Unix platforms
zk_max_file_descriptor_count 1024 – only available on Unix platforms


七:客户端简单操作

1.  连接到zookeeper服务

    [java2000_wl@localhost zookeeper-3]$ bin/zkCli.sh -server 127.0.0.1:2181

2.  使用ls命令查看当前zookeeper中包含的内容

    [zk: 127.0.0.1:2181(CONNECTED) 1] ls /

    [zookeeper]


3.  创建新的znode,使用create命令

    [zk:127.0.0.1:2181(CONNECTED) 2] create /zk testData

    Created /zk


4.  获取节点中的值  get命令

    [zk:127.0.0.1:2181(CONNECTED) 4] get /zk

    testData

    cZxid = 0x700000008

    ctime = Sat Mar 0923:01:24 CST 2013

    mZxid = 0x700000008

    mtime = Sat Mar 0923:01:24 CST 2013

    pZxid = 0x700000008

    cversion = 0

    dataVersion = 0

    aclVersion = 0

    ephemeralOwner = 0x0

    dataLength = 8

    numChildren = 0


5.  使用set命令来对znode关联的字符串进行设置

    [zk: 127.0.0.1:2181(CONNECTED) 5] set /zk mydata

    cZxid = 0x700000008

    ctime = Sat Mar 09 23:01:24 CST 2013

    mZxid = 0x700000009

    mtime = Sat Mar 09 23:06:03 CST 2013

    pZxid = 0x700000008

    cversion = 0

    dataVersion = 1

    aclVersion = 0

    ephemeralOwner = 0x0

    dataLength = 6

    numChildren = 0


6.  删除znode节点

    [zk: 127.0.0.1:2181(CONNECTED) 7]delete /zk

javaapi


znode创建类型(CreateMode):

    PERSISTENT               持久化节点
      
    PERSISTENT_SEQUENTIAL     顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1
      
    EPHEMERAL    临时节点, 客户端session超时这类节点就会被自动删除
     

    EPHEMERAL_SEQUENTIAL   临时自动编号节点


八 :开发(Zookeeper API操作)
  

    /* 
     * ZookeeperTest.java 
     */  
    package com.x.zookeeper;  
      
    import java.io.IOException;  
    import java.util.List;  
      
    import org.apache.zookeeper.CreateMode;  
    import org.apache.zookeeper.WatchedEvent;  
    import org.apache.zookeeper.Watcher;  
    import org.apache.zookeeper.ZooKeeper;  
    import org.apache.zookeeper.ZooDefs.Ids;  
    import org.apache.zookeeper.data.Stat;  
    import org.junit.After;  
    import org.junit.Assert;  
    import org.junit.Before;  
    import org.junit.Test;  
    import org.slf4j.Logger;  
    import org.slf4j.LoggerFactory;  
      
    /** 
     *  
     * @author http://blog.csdn.net/java2000_wl 
     * @version <b>1.0</b> 
     */  
    public class ZookeeperTest {  
          
        private static final int SESSION_TIMEOUT = 30000;  
          
        public static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperTest.class);  
          
        private Watcher watcher =  new Watcher() {  
      
            public void process(WatchedEvent event) {  
                LOGGER.info("process : " + event.getType());  
            }  
        };  
          
        private ZooKeeper zooKeeper;  
          
        /** 
         *  连接zookeeper 
         * <br>------------------------------<br> 
         * @throws IOException 
         */  
        @Before  
        public void connect() throws IOException {  
            zooKeeper  = new ZooKeeper("localhost:2181,localhost:2182,localhost:2183", SESSION_TIMEOUT, watcher);  
        }  
          
        /** 
         *  关闭连接 
         * <br>------------------------------<br> 
         */  
        @After  
        public void close() {  
            try {  
                zooKeeper.close();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
      
        /** 
         * 创建一个znode  
         *  1.CreateMode 取值   
         *  PERSISTENT:持久化,这个目录节点存储的数据不会丢失 
         *  PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名; 
         *  EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session过期超时,这种节点会被自动删除 
         *  EPHEMERAL_SEQUENTIAL:临时自动编号节点 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testCreate() {  
            String result = null;  
             try {  
                 result = zooKeeper.create("/zk001", "zk001data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             LOGGER.info("create result : {}", result);  
         }  
          
        /** 
         * 删除节点  忽略版本 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testDelete() {  
             try {  
                zooKeeper.delete("/zk001", -1);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
        }  
          
        /** 
         *   获取数据 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testGetData() {  
            String result = null;  
             try {  
                 byte[] bytes = zooKeeper.getData("/zk001", null, null);  
                 result = new String(bytes);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             LOGGER.info("getdata result : {}", result);  
        }  
          
        /** 
         *   获取数据  设置watch 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testGetDataWatch() {  
            String result = null;  
             try {  
                 byte[] bytes = zooKeeper.getData("/zk001", new Watcher() {  
                    public void process(WatchedEvent event) {  
                        LOGGER.info("testGetDataWatch  watch : {}", event.getType());  
                    }  
                 }, null);  
                 result = new String(bytes);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             LOGGER.info("getdata result : {}", result);  
               
             // 触发wacth  NodeDataChanged  
             try {  
                 zooKeeper.setData("/zk001", "testSetData".getBytes(), -1);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
        }  
          
        /** 
         *    判断节点是否存在 
         *    设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper实例时指定的 watcher 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testExists() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.exists("/zk001", false);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
             LOGGER.info("exists result : {}", stat.getCzxid());  
        }  
          
        /** 
         *     设置对应znode下的数据  ,  -1表示匹配所有版本 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testSetData() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.setData("/zk001", "testSetData".getBytes(), -1);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
             LOGGER.info("exists result : {}", stat.getVersion());    
        }  
          
        /** 
         *    判断节点是否存在,  
         *    设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper实例时指定的 watcher 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testExistsWatch1() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.exists("/zk001", true);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
               
             try {  
                zooKeeper.delete("/zk001", -1);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
        /** 
         *    判断节点是否存在,  
         *    设置监控这个目录节点的 Watcher 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testExistsWatch2() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.exists("/zk002", new Watcher() {  
                    @Override  
                    public void process(WatchedEvent event) {  
                        LOGGER.info("testExistsWatch2  watch : {}", event.getType());  
                    }  
                 });  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
               
             // 触发watch 中的process方法   NodeDataChanged  
             try {  
                zooKeeper.setData("/zk002", "testExistsWatch2".getBytes(), -1);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
               
             // 不会触发watch 只会触发一次  
             try {  
                zooKeeper.delete("/zk002", -1);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
        /** 
         *  获取指定节点下的子节点 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testGetChild() {  
             try {  
                 zooKeeper.create("/zk/001", "001".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
                 zooKeeper.create("/zk/002", "002".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
                   
                 List<String> list = zooKeeper.getChildren("/zk", true);  
                for (String node : list) {  
                    LOGGER.info("node {}", node);  
                }  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
        }  
    }  

一:环境

centos

jdk1.6

zookeeper-3.4.3 下载

二:配置

将解压出来的zookeeper 复制三份,这里分别叫做 zookeeper-1,zookeeper-2和zookeeper-3。

1.  zookeeper-1 配置:

创建data目录:/home/java2000_wl/hadoop/zookeeper-1/data
创建log目录:/home/java2000_wl/hadoop/zookeeper-1/logs
创建myid文件:/home/java2000_wl/hadoop/zookeeper-1/data/myid
内容:
1

创建/home/java2000_wl/hadoop/zookeeper-1/conf/zoo.cfg文件

内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/java2000_wl/hadoop/zookeeper-1/data
clientPort=2181
dataLogDir=/home/java2000_wl/hadoop/zookeeper-1/logs

server.1=127.0.0.1:4000:5000 
server.2=127.0.0.1:4001:5001
server.3=127.0.0.1:4002:5002



2.zookeeper-2 配置:

创建data目录:/home/java2000_wl/hadoop/zookeeper-2/data
创建log目录:/home/java2000_wl/hadoop/zookeeper-2/logs
创建myid文件:/home/java2000_wl/hadoop/zookeeper-2/data/myid
内容:
2

创建/home/java2000_wl/hadoop/zookeeper-2/conf/zoo.cfg文件
内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/java2000_wl/hadoop/zookeeper-2/data
clientPort=2182
dataLogDir=/home/java2000_wl/hadoop/zookeeper-2/logs

server.1=127.0.0.1:4000:5000 
server.2=127.0.0.1:4001:5001 
server.3=127.0.0.1:4002:5002


3.zookeeper-3 配置:

创建data目录:/home/java2000_wl/hadoop/zookeeper-3/data
创建log目录:/home/java2000_wl/hadoop/zookeeper-3/logs
创建myid文件:/home/java2000_wl/hadoop/zookeeper-3/data/myid
内容:
3

创建/home/java2000_wl/hadoop/zookeeper-3/conf/zoo.cfg文件
内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/java2000_wl/hadoop/zookeeper-3/data
clientPort=2183
dataLogDir=/home/java2000_wl/hadoop/zookeeper-3/logs

server.1=127.0.0.1:4000:5000 
server.2=127.0.0.1:4001:5001 
server.3=127.0.0.1:4002:5002


三:启动服务

分别进入三个服务的bin目录 启动服务

bin/zkServer.sh start

出现如下:
JMX enabled by default
Using config: D:\cygwin64\home\zookeeper-3.4.5_1\conf\zoo.cfg
Starting zookeeper ... STARTED

通过jps命令可以查看ZooKeeper服务器进程,名称为QuorumPeerMain。

四:客户端连接

成功启动zookeeper服务之后,输入下述命令,连接到zookeeper服务

./zkCli.sh -server 127.0.0.1:2181


WATCHER::

WatchedEvent state:SyncConnected type:N
[zk: localhost:2181(CONNECTED) 0] ls /
ZooKeeper -server host:port cmd args
        connect host:port
        get path [watch]
        ls path [watch]
        set path data [version]
        rmr path
        delquota [-n|-b] path
        quit
        printwatches on|off
        create [-s] [-e] path data acl
        stat path [watch]
        close
        ls2 path [watch]
        history
        listquota path
        setAcl path acl
        getAcl path
        sync path
        redo cmdno
        addauth scheme auth
        delete path [version]
        setquota -n|-b val path
[zk: localhost:2181(CONNECTED) 1]

可以通过ZooKeeper的脚本来查看启动状态,包括集群中各个结点的角色(或是Leader,或是Follower),如下所示,是在ZooKeeper集群中的每个结点上查询的结果


bin/zkServer.sh status

五:参数说明

参数名

说明

clientPort 客户端连接server的端口,即对外服务端口,一般设置为2181吧。
dataDir 存储快照文件snapshot的目录。默认情况下,事务日志也会存储在这里。建议同时配置参数dataLogDir, 事务日志的写性能直接影响zk性能。
tickTime ZK中的一个时间单元。ZK中所有时间都是以这个时间单元为基础,进行整数倍配置的。例如,session的最小超时时间是2*tickTime。
dataLogDir 事务日志输出目录。尽量给事务日志的输出配置单独的磁盘或是挂载点,这将极大的提升ZK性能。
(No Java system property)
globalOutstandingLimit 最大请求堆积数。默认是1000。ZK运行的时候, 尽管server已经没有空闲来处理更多的客户端请求了,但是还是允许客户端将请求提交到服务器上来,以提高吞吐性能。当然,为了防止Server内存溢出,这个请求堆积数还是需要限制下的。
(Java system property:zookeeper.globalOutstandingLimit.)
preAllocSize 预先开辟磁盘空间,用于后续写入事务日志。默认是64M,每个事务日志大小就是64M。如果ZK的快照频率较大的话,建议适当减小这个参数。(Java system property:zookeeper.preAllocSize)
snapCount 每 进行snapCount次事务日志输出后,触发一次快照(snapshot), 此时,ZK会生成一个snapshot.*文件,同时创建一个新的事务日志文件log.*。默认是100000.(真正的代码实现中,会进行一定的随机数 处理,以避免所有服务器在同一时间进行快照而影响性能)(Java system property:zookeeper.snapCount)
traceFile 用于记录所有请求的log,一般调试过程中可以使用,但是生产环境不建议使用,会严重影响性能。(Java system property:?requestTraceFile)
maxClientCnxns 单 个客户端与单台服务器之间的连接数的限制,是ip级别的,默认是60,如果设置为0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端 机器与单台ZK服务器之间的连接数限制,不是针对指定客户端IP,也不是ZK集群的连接数限制,也不是单台ZK对所有客户端的连接数限制。指定客户端IP 的限制策略,这里有一个patch,可以尝试一下:http://rdc.taobao.com/team/jm/archives/1334(No Java system property)
clientPortAddress 对于多网卡的机器,可以为每个IP指定不同的监听端口。默认情况是所有IP都监听clientPort指定的端口。New in 3.3.0
minSessionTimeoutmaxSessionTimeout Session超时时间限制,如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。默认的Session超时时间是在2 * tickTime ~ 20 * tickTime这个范围 New in 3.3.0
fsync.warningthresholdms 事务日志输出时,如果调用fsync方法超过指定的超时时间,那么会在日志中输出警告信息。默认是1000ms。(Java system property:fsync.warningthresholdms)New in 3.3.4
autopurge.purgeInterval 在上文中已经提到,3.4.0及之后版本,ZK提供了自动清理事务日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是0,表示不开启自动清理功能。(No Java system property) New in 3.4.0
autopurge.snapRetainCount 这个参数和上面的参数搭配使用,这个参数指定了需要保留的文件数目。默认是保留3个。(No Java system property) New in 3.4.0
electionAlg 在 之前的版本中, 这个参数配置是允许我们选择leader选举算法,但是由于在以后的版本中,只会留下一种“TCP-based version of fast leader election”算法,所以这个参数目前看来没有用了,这里也不详细展开说了。(No Java system property)
initLimit Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader允许F在initLimit时间内完成这个工作。通常情况下,我们不用太在意这个参数的设置。如果ZK集群的数据量确实很大了,F在启动的时候,从Leader上同步数据的时间也会相应变长,因此在这种情况下,有必要适当调大这个参数了。(No Java system property)
syncLimit 在 运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。如果L发出心跳包在syncLimit之 后,还没有从F那里收到响应,那么就认为这个F已经不在线了。注意:不要把这个参数设置得过大,否则可能会掩盖一些问题。(No Java system property)
leaderServes 默认情况下,Leader是会接受客户端连接,并提供正常的读写服务。但是,如果你想让Leader专注于集群中机器的协调,那么可以将这个参数设置为no,这样一来,会大大提高写操作的性能。(Java system property: zookeeper.leaderServes)。
server.x=[hostname]:nnnnn[:nnnnn] 这里的x是一个数字,与myid文件中的id是一致的。右边可以配置两个端口,第一个端口用于F和L之间的数据同步和其它通信,第二个端口用于Leader选举过程中投票通信。
(No Java system property)
group.x=nnnnn[:nnnnn]weight.x=nnnnn 对机器分组和权重设置,可以 参见这里(No Java system property)
cnxTimeout Leader选举过程中,打开一次连接的超时时间,默认是5s。(Java system property: zookeeper.cnxTimeout)
zookeeper.DigestAuthenticationProvider
.superDigest
ZK权限设置相关,具体参见使用super身份对有权限的节点进行操作 和 ZooKeeper权限控制
skipACL 对所有客户端请求都不作ACL检查。如果之前节点上设置有权限限制,一旦服务器上打开这个开头,那么也将失效。(Java system property:zookeeper.skipACL)
forceSync 这个参数确定了是否需要在事务日志提交的时候调用FileChannel.force来保证数据完全同步到磁盘。(Java system property:zookeeper.forceSync)
jute.maxbuffer 每个节点最大数据量,是默认是1M。这个限制必须在server和client端都进行设置才会生效。(Java system property:jute.maxbuffer)




六:常用的四字命令

参数名

说明

conf 输出server的详细配置信息。New in 3.3.0

 

$>echo conf|nc localhost 2181
clientPort=2181
dataDir=/home/test/taokeeper/zk_data/version-2
dataLogDir=/test/admin/taokeeper/zk_log/version-2
tickTime=2000
maxClientCnxns=1000
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=2
initLimit=10
syncLimit=5
electionAlg=3
electionPort=3888
quorumPort=2888
peerType=0

cons 输出指定server上所有客户端连接的详细信息,包括客户端IP,会话ID等。
New in 3.3.0类似于这样的信息:

 

$>echo cons|nc localhost 2181
/1.2.3.4:43527[1](queued=0,recved=152802,sent=152806,sid=0x2389e662b98c424,lop=PING,
est=1350385542196,to=6000,lcxid=0×114,lzxid=0xffffffffffffffff,lresp=1350690663308,
llat=0,minlat=0,avglat=0,maxlat=483)
……

crst 功能性命令。重置所有连接的统计信息。New in 3.3.0
dump 这个命令针对Leader执行,用于输出所有等待队列中的会话和临时节点的信息。
envi 用于输出server的环境变量。包括操作系统环境和Java环境。
ruok 用于测试server是否处于无错状态。如果正常,则返回“imok”,否则没有任何响应。
注意:ruok不是一个特别有用的命令,它不能反映一个server是否处于正常工作。“stat”命令更靠谱。
stat 输出server简要状态和连接的客户端信息。
srvr 和stat类似,New in 3.3.0

 

$>echo stat|nc localhost 2181
Zookeeper version: 3.3.5-1301095, built on 03/15/2012 19:48 GMT
Clients:
/10.2.3.4:59179[1](queued=0,recved=44845,sent=44845)

Latency min/avg/max: 0/0/1036
Received: 2274602238
Sent: 2277795620
Outstanding: 0
Zxid: 0xa1b3503dd
Mode: leader
Node count: 37473

$>echo srvr|nc localhost 2181
Zookeeper version: 3.3.5-1301095, built on 03/15/2012 19:48 GMT
Latency min/avg/max: 0/0/980
Received: 2592698547
Sent: 2597713974
Outstanding: 0
Zxid: 0xa1b356b5b
Mode: follower
Node count: 37473

srst 重置server的统计信息。
wchs 列出所有watcher信息概要信息,数量等:New in 3.3.0

 

$>echo wchs|nc localhost 2181
3890 connections watching 537 paths
Total watches:6909

wchc 列出所有watcher信息,以watcher的session为归组单元排列,列出该会话订阅了哪些path:New in 3.3.0

 

$>echo wchc|nc localhost 2181
0x2389e662b97917f
/mytest/test/path1/node1
0x3389e65c83cd790
/mytest/test/path1/node2
0x1389e65c7ef6313
/mytest/test/path1/node3
/mytest/test/path1/node1

wchp 列出所有watcher信息,以watcher的path为归组单元排列,列出该path被哪些会话订阅着:New in 3.3.0

 

$>echo wchp|nc localhost 2181
/mytest/test/path1/node
0x1389e65c7eea4f5
0x1389e65c7ee2f68
/mytest/test/path1/node2
0x2389e662b967c29
/mytest/test/path1/node3
0x3389e65c83dd2e0
0x1389e65c7f0c37c
0x1389e65c7f0c364

注意,wchc和wchp这两个命令执行的输出结果都是针对session的,对于运维人员来说可视化效果并不理想,可以尝试将cons命令执行输出的信息整合起来,就可以用客户端IP来代替会话ID了,具体可以看这个实现:http://rdc.taobao.com/team/jm/archives/1450

mntr 输出一些ZK运行时信息,通过对这些返回结果的解析,可以达到监控的效果。New in 3.4.0

 

$ echo mntr | nc localhost 2185
zk_version 3.4.0
zk_avg_latency 0
zk_max_latency 0
zk_min_latency 0
zk_packets_received 70
zk_packets_sent 69
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count 4
zk_watch_count 0
zk_ephemerals_count 0
zk_approximate_data_size 27
zk_followers 4 – only exposed by the Leader
zk_synced_followers 4 – only exposed by the Leader
zk_pending_syncs 0 – only exposed by the Leader
zk_open_file_descriptor_count 23 – only available on Unix platforms
zk_max_file_descriptor_count 1024 – only available on Unix platforms


七:客户端简单操作

1.  连接到zookeeper服务

    [java2000_wl@localhost zookeeper-3]$ bin/zkCli.sh -server 127.0.0.1:2181

2.  使用ls命令查看当前zookeeper中包含的内容

    [zk: 127.0.0.1:2181(CONNECTED) 1] ls /

    [zookeeper]


3.  创建新的znode,使用create命令

    [zk:127.0.0.1:2181(CONNECTED) 2] create /zk testData

    Created /zk


4.  获取节点中的值  get命令

    [zk:127.0.0.1:2181(CONNECTED) 4] get /zk

    testData

    cZxid = 0x700000008

    ctime = Sat Mar 0923:01:24 CST 2013

    mZxid = 0x700000008

    mtime = Sat Mar 0923:01:24 CST 2013

    pZxid = 0x700000008

    cversion = 0

    dataVersion = 0

    aclVersion = 0

    ephemeralOwner = 0x0

    dataLength = 8

    numChildren = 0


5.  使用set命令来对znode关联的字符串进行设置

    [zk: 127.0.0.1:2181(CONNECTED) 5] set /zk mydata

    cZxid = 0x700000008

    ctime = Sat Mar 09 23:01:24 CST 2013

    mZxid = 0x700000009

    mtime = Sat Mar 09 23:06:03 CST 2013

    pZxid = 0x700000008

    cversion = 0

    dataVersion = 1

    aclVersion = 0

    ephemeralOwner = 0x0

    dataLength = 6

    numChildren = 0


6.  删除znode节点

    [zk: 127.0.0.1:2181(CONNECTED) 7]delete /zk

javaapi


znode创建类型(CreateMode):

    PERSISTENT               持久化节点
      
    PERSISTENT_SEQUENTIAL     顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1
      
    EPHEMERAL    临时节点, 客户端session超时这类节点就会被自动删除
     

    EPHEMERAL_SEQUENTIAL   临时自动编号节点


八 :开发(Zookeeper API操作)
  

    /* 
     * ZookeeperTest.java 
     */  
    package com.x.zookeeper;  
      
    import java.io.IOException;  
    import java.util.List;  
      
    import org.apache.zookeeper.CreateMode;  
    import org.apache.zookeeper.WatchedEvent;  
    import org.apache.zookeeper.Watcher;  
    import org.apache.zookeeper.ZooKeeper;  
    import org.apache.zookeeper.ZooDefs.Ids;  
    import org.apache.zookeeper.data.Stat;  
    import org.junit.After;  
    import org.junit.Assert;  
    import org.junit.Before;  
    import org.junit.Test;  
    import org.slf4j.Logger;  
    import org.slf4j.LoggerFactory;  
      
    /** 
     *  
     * @author http://blog.csdn.net/java2000_wl 
     * @version <b>1.0</b> 
     */  
    public class ZookeeperTest {  
          
        private static final int SESSION_TIMEOUT = 30000;  
          
        public static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperTest.class);  
          
        private Watcher watcher =  new Watcher() {  
      
            public void process(WatchedEvent event) {  
                LOGGER.info("process : " + event.getType());  
            }  
        };  
          
        private ZooKeeper zooKeeper;  
          
        /** 
         *  连接zookeeper 
         * <br>------------------------------<br> 
         * @throws IOException 
         */  
        @Before  
        public void connect() throws IOException {  
            zooKeeper  = new ZooKeeper("localhost:2181,localhost:2182,localhost:2183", SESSION_TIMEOUT, watcher);  
        }  
          
        /** 
         *  关闭连接 
         * <br>------------------------------<br> 
         */  
        @After  
        public void close() {  
            try {  
                zooKeeper.close();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
      
        /** 
         * 创建一个znode  
         *  1.CreateMode 取值   
         *  PERSISTENT:持久化,这个目录节点存储的数据不会丢失 
         *  PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名; 
         *  EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session过期超时,这种节点会被自动删除 
         *  EPHEMERAL_SEQUENTIAL:临时自动编号节点 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testCreate() {  
            String result = null;  
             try {  
                 result = zooKeeper.create("/zk001", "zk001data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             LOGGER.info("create result : {}", result);  
         }  
          
        /** 
         * 删除节点  忽略版本 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testDelete() {  
             try {  
                zooKeeper.delete("/zk001", -1);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
        }  
          
        /** 
         *   获取数据 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testGetData() {  
            String result = null;  
             try {  
                 byte[] bytes = zooKeeper.getData("/zk001", null, null);  
                 result = new String(bytes);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             LOGGER.info("getdata result : {}", result);  
        }  
          
        /** 
         *   获取数据  设置watch 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testGetDataWatch() {  
            String result = null;  
             try {  
                 byte[] bytes = zooKeeper.getData("/zk001", new Watcher() {  
                    public void process(WatchedEvent event) {  
                        LOGGER.info("testGetDataWatch  watch : {}", event.getType());  
                    }  
                 }, null);  
                 result = new String(bytes);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             LOGGER.info("getdata result : {}", result);  
               
             // 触发wacth  NodeDataChanged  
             try {  
                 zooKeeper.setData("/zk001", "testSetData".getBytes(), -1);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
        }  
          
        /** 
         *    判断节点是否存在 
         *    设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper实例时指定的 watcher 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testExists() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.exists("/zk001", false);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
             LOGGER.info("exists result : {}", stat.getCzxid());  
        }  
          
        /** 
         *     设置对应znode下的数据  ,  -1表示匹配所有版本 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testSetData() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.setData("/zk001", "testSetData".getBytes(), -1);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
             LOGGER.info("exists result : {}", stat.getVersion());    
        }  
          
        /** 
         *    判断节点是否存在,  
         *    设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper实例时指定的 watcher 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testExistsWatch1() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.exists("/zk001", true);  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
               
             try {  
                zooKeeper.delete("/zk001", -1);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
        /** 
         *    判断节点是否存在,  
         *    设置监控这个目录节点的 Watcher 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testExistsWatch2() {  
            Stat stat = null;  
             try {  
                 stat = zooKeeper.exists("/zk002", new Watcher() {  
                    @Override  
                    public void process(WatchedEvent event) {  
                        LOGGER.info("testExistsWatch2  watch : {}", event.getType());  
                    }  
                 });  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
             Assert.assertNotNull(stat);  
               
             // 触发watch 中的process方法   NodeDataChanged  
             try {  
                zooKeeper.setData("/zk002", "testExistsWatch2".getBytes(), -1);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
               
             // 不会触发watch 只会触发一次  
             try {  
                zooKeeper.delete("/zk002", -1);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
        /** 
         *  获取指定节点下的子节点 
         * <br>------------------------------<br> 
         */  
        @Test  
        public void testGetChild() {  
             try {  
                 zooKeeper.create("/zk/001", "001".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
                 zooKeeper.create("/zk/002", "002".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
                   
                 List<String> list = zooKeeper.getChildren("/zk", true);  
                for (String node : list) {  
                    LOGGER.info("node {}", node);  
                }  
            } catch (Exception e) {  
                 LOGGER.error(e.getMessage());  
                 Assert.fail();  
            }  
        }  
    }  

猜你喜欢

转载自liyonghui160com.iteye.com/blog/2087475
今日推荐