zookeeper编程

本文主要内容主要来自博客: http://www.cnblogs.com/zhangchaoyang/articles/2536178.html

 

ZooKeeper的用途:distributed coordination;maintaining configuration information, naming, providing distributed synchronization, and providing group services.
Zookeeper的节点都是存放在内存中的,所以读写速度很快。更新日志被记录到了磁盘中,以便用于恢复数据。在更新内在中节点数之前,会先序列化到磁盘中。
为避免单点失效,zookeeper的数据是在多个server上留有备份的。不管客户端连接到的是哪个server,它看到的数据都是一致的。如果client和一个server的TCP连接失效,它会尝试连接另一个server。众多server中有一个是leader。
所有的server 都必须知道彼此的存在。
zookeeper在读写比例为10:1时性能最佳。
每个znode上data的读写都是原子操作。
读是局部性的,即client只需要从与它相连的server上读取数据即可;而client有写请求的话,与之相连的server会通知leader,然后leader会把写操作分发给所有server。所以定要比读慢很多。
在建立zookeeper连接时,给定的地址字符串可以是这样的:"192.168.1.1:3000,192.168.1.2:3000,192.168.1.3:3000/app/a",以后的所有操作就都是在/app/a下进行的。实际上只连接到一台ZooKeeper机器就可了,没必要指定每台zk机器的IP和端口,即用“192.168.1.2:3000/app/a”也是可以的。
当client与一个server断连接时(可能是因为server失效了),它就收不到任何watches;当它与另一个server建立好连接后,它就会收到"session expired"通知。
ACL不是递归的,它只针对当前节点,对子节点没有任何影响。
默认情况下日志文件和数据文件是放在同一个目录下的,为缩短延迟提高响应性,你可以把日志文件单独放在另一个目录下。
为避免swaping,运行java时最好把可用物理内在调得大一些,比如对于4G的内在,可以把它调到3G。java有以下两个运行参数:
-Xms<size>
设置虚拟机可用内存堆的初始大小,缺省单位为字节,该大小为1024的整数倍并且要大于1MB,可用k(K)或m(M)为单位来设置较大的内存数。初始堆大小为2MB。
例如:-Xms6400K,-Xms256M
-Xmx<size>
设置虚拟机内存堆的最大可用大小,缺省单位为字节。该值必须为1024整数倍,并且要大于2MB。可用k(K)或m(M)为单位来设置较大的内存数。缺省堆最大值为64MB。
例如:-Xmx81920K,-Xmx80M

 

CreateMode:
PERSISTENT:创建后只要不删就永久存在
EPHEMERAL:会话结束年结点自动被删除,EPHEMERAL结点不允许有子节点
SEQUENTIAL:节点名末尾会自动追加一个10位数的单调递增的序号,同一个节点的所有子节点序号是单调递增的
PERSISTENT_SEQUENTIAL:结合PERSISTENT和SEQUENTIAL
EPHEMERAL_SEQUENTIAL:结合EPHEMERAL和SEQUENTIAL

代码示例:

package com.ssm.zk;

import java.io.IOException;
import java.util.List;

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Ids;

public class Demo {

    public static final int TIMEOUT = 3000;

    public static void main(String[] args) throws IOException {
        // 打开一个会话
        ZooKeeper zooKeeper = new ZooKeeper("localhost:2181", TIMEOUT, null);
        try {
            // 创建一个EPHEMERAL类型的节点,会话关闭后它会自动被删除
            zooKeeper.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            if (zooKeeper.exists("/node1", false) != null) {
                System.out.println("node1 exists now.");
            }

            try {
                zooKeeper.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // 关闭会话
            zooKeeper.close();

            zooKeeper = new ZooKeeper("localhost:2181", TIMEOUT, null);
            // 重新建立会话后node1已经不存在了
            if (zooKeeper.exists("/node1", false) == null) {
                System.out.println("node1 dosn't exists now.");
            }

            // 创建SEQUENTIAL节点
            zooKeeper.create("/node-", "same data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
            zooKeeper.create("/node-", "same data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
            zooKeeper.create("/node-", "same data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);

            List<String> children = zooKeeper.getChildren("/", null);
            System.out.println("Children of root node:");
            for (String child : children) {
                System.out.println(child);
            }
            zooKeeper.close();
        } catch (KeeperException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

第一次运行输出:
node1 exists now.
KeeperException caught:KeeperErrorCode = NodeExists for /node1
node1 dosn't exists now.
Children of root node:
node-0000000003
zookeeper
node-0000000002
node-0000000001

第二次运行输出:
node1 exists now.
KeeperException caught:KeeperErrorCode = NodeExists for /node1
node1 dosn't exists now.
Children of root node:
node-0000000003
zookeeper
node-0000000002
node-0000000001
node-0000000007
node-0000000005
node-0000000006

注意两次会话中创建的PERSISTENT_SEQUENTIAL节点序号并不是连续的,比如上例中缺少了node-0000000004.

 

Watcher & Version

watcher分为两大类:data watches和child watches。getData()和exists()上可以设置data watches,getChildren()上可以设置child watches。
setData()会触发data watches;
create()会触发data watches和child watches;
delete()会触发data watches和child watches.
如果对一个不存在的节点调用了exists(),并设置了watcher,而在连接断开的情况下create/delete了该znode,则watcher会丢失。
在server端用一个map来存放watcher,所以相同的watcher在map中只会出现一次,只要watcher被回调一次,它就会被删除----map解释了watcher的一次性。比如如果在getData()和exists()上设置的是同一个data watcher,调用setData()会触发data watcher,但是getData()和exists()只有一个会收到通知。

package com.ssm.zk;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;


import org.apache.zookeeper.ZooDefs.Ids;

public class SelfWatch implements Watcher{

    ZooKeeper zooKeeper = null;
    
    public void process(WatchedEvent event) {
        System.out.println(event.toString());
    }
 
    SelfWatch(String address) {
        try {
            zooKeeper = new ZooKeeper(address,3000, this);
            zooKeeper.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        } catch (Exception e) {
            
        }
    }
    
    public void setWatch(){
        try {
            Stat stat = zooKeeper.exists("/root", true);
            if(stat!=null){
                zooKeeper.getData("/root", false, stat);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
    
    public void triggerWatch(){
        try {
            Stat stat = zooKeeper.exists("/root", false);
            zooKeeper.setData("/root", "a".getBytes(),stat.getAversion());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
    
    public void disconnect(){
        if(zooKeeper!=null){
            try {
                zooKeeper.close();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }
    
    public static void main(String[] args) {
        SelfWatch selfWatch = new SelfWatch("localhsot:2181");
        selfWatch.setWatch();
        selfWatch.triggerWatch();
        selfWatch.disconnect();
    }
}

 

posted @ 2017-02-16 15:49  梅花瘦  阅读(110)  评论(0)    收藏  举报