zookeeper java API 的使用

1 eclipse环境配置

  • 普通的java项目

    1. 创建一个java项目

    2. 依赖的jar包

      zookeeper-3.4.7\lib下的
          jline-0.9.94.jar
          log4j-1.2.15.jar
          netty-3.2.2.Final.jar
          slf4j-api-1.6.1.jar
          slf4j-log4j12-1.6.1.jar
      zookeeper-3.4.7\zookeeper-3.4.7.jar
  • maven项目

    1. 创建maven项目步骤:略

    2. pom.xml (查询该坐标的网站:http://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper/3.4.7)

      <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
      <dependency>
          <groupId>org.apache.zookeeper</groupId>
          <artifactId>zookeeper</artifactId>
          <version>3.4.7</version>
          <type>pom</type>
      </dependency>
    3. 在maven工程的src/main/resource目录放置一个log4j.properties,其内容如下:

      # Rules reminder:
      # DEBUG < INFO < WARN < ERROR < FATAL
      # Global logging configuration
      log4j.rootLogger=INFO,R,stdout
      ## File output...
      log4j.appender.R=org.apache.log4j.RollingFileAppender
      log4j.appender.R.File=/home/hadoop/flume/logs/test.log
      log4j.appender.R.MaxFileSize=100MB
      log4j.appender.R.MaxBackupIndex=7
      log4j.appender.R.layout=org.apache.log4j.PatternLayout
      log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p%l method\:%M %m%n
      #log4j.logger.org.apache.catalina=INFO,R,stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p%l method\:%M %m%n
      #%d:显示日志记录时间
      #[%t]:输出产生该日志事件的线程名
      #%-5p:显示该条日志的优先级
      #%l:输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数
      #%M:方法名
      #%m:显示输出消息
      #%n:当前平台下的换行符

2 基本操作

public class TestCRUD {
​
    private static final String connectString = "min1:2181," +"min2:2181," +"min3:2181";
    private static final int sessionTimeout = 2000;
    
    @Test
    public void testConnect(){
        ZooKeeper zkClient = null;
        try {
            //连接成功后,会回调watcher监听,此连接操作是异步的,执行完new语句后,直接调用后续代码
            zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
                /**
                 * public enum EventType {
                            None (-1),
                            NodeCreated (1),
                            NodeDeleted (2),
                            NodeDataChanged (3),
                            NodeChildrenChanged (4);
                 */
                @Override
                public void process(WatchedEvent event) {
                    // 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
                    System.out.println("=========="+event.getType()+"===="+event.getState()); 
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //连接状态值   CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY,
        System.out.println("-------------------"+zkClient.getState());
        while(true){
            try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
            //等待zookeeper客户端连接服务器成功的,查看连接时的状态信息。
            System.out.println("====-----===="+zkClient.getState());
        }
    }
    
    
    @Test   
    public void testCreate() throws Exception {
        ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
                new Watcher() {
                    @Override
                    public void process(WatchedEvent event) {
                        System.out.println("=========="+event.getType()); 
                    }
        });
        
        Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
        
        if(zkClient.getState() == States.CONNECTED){//连接服务器连接成功
            String nodeCreated = zkClient.create("/age", //:要创建的节点的路径
                    "18".getBytes(), //节点中的数据
                    Ids.OPEN_ACL_UNSAFE, //节点的权限
                    CreateMode.PERSISTENT);//节点的类型
            System.out.println("创建成功后,节点的真是路径是:"+nodeCreated);
        }       
    }
    
    //判断znode是否存在
    @Test   
    public void testExist() throws Exception{
        
        ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
                new Watcher() {
                    //修改目标节点   event.getType()的值是NodeDataChanged
                    @Override
                    public void process(WatchedEvent event) {
                        System.out.println("=========="+event.getType()); 
                    }
        });
        
        Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
        
        //第二个参数表示  是否监听”/age“节点的状态的改变,为true时,则监听,当另一个zookeeper客户端修改、删除该节点的值时,回调watcher
        Stat stat = zkClient.exists("/age", true);
        System.out.println(stat==null?"not exist":"exist");
        
        Thread.sleep(20*1000);
    }
    
    //获取znode的数据
    @Test
    public void getData() throws Exception {
        ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
                new Watcher() {
                    @Override
                    public void process(WatchedEvent event) {
                        System.out.println("=========="+event.getType()); 
                    }
        });
        
        Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
        
        byte[] data = zkClient.getData("/age", false, null);
        System.out.println(new String(data));
        
    }
    
    // 获取子节点
    @Test
    public void getChildren() throws Exception {
        ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
                new Watcher() {
                    @Override
                    public void process(WatchedEvent event) {
                        System.out.println("=========="+event.getType()); 
                    }
        });
        
        Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
        
        //只能获得一个路径下的直接子节点的信息,不能递归获取孙节点
        List<String> children = zkClient.getChildren("/", true);
        for (String child : children) {
            System.out.println(child);
        }
        Thread.sleep(Long.MAX_VALUE);
    }
        
    
    //删除znode
    @Test
    public void deleteZnode() throws Exception {
        ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
                new Watcher() {
                    @Override
                    public void process(WatchedEvent event) {
                        System.out.println("=========="+event.getType()); 
                    }
        });
        
        Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
        
        //参数2:指定要删除的版本,-1表示删除所有版本
        zkClient.delete("/age", -1);
    
    }
}
​

3 监听集群中主机的上下线

案例说明:

1.DistributedServer程序一运行起来就向zookeeper的/servers路径下创建一个临时节点

如该类启动三个实例时,分别为传入三个字符串,分别为   server1,server2,server3
    根据代码逻辑,会在zookeeper的/servers下创建三个EPHEMERAL_SEQUENTIAL类型的节点,节点名为
        /servers/server000001    此节点对应的value是server1   
        /servers/server000002    此节点对应的value是server2
        /servers/server000003    此节点对应的value是server3 

2.DistributedClient代码实时夺取/servers下的节点集合内容

    如 [/servers/server000001,/servers/server000002,/servers/server000003]
    说明这个客户端所在的机器,可用的集群有三台机器
DistributedClient代码监听了/servers目录的子节点,当有机器掉线时,/servers下的节点集合内容会变化的
    如 [/servers/server000001,,/servers/server000003]
       [/servers/server000003]
       这样也就实时感知了三台集群中机器的状态

总结:有四台机器组成的集群,如a1,a2,a3,a4其中a1是主节点;a2,a3,a4是从节点

DistributedServer代码分别运行在a2,a3,a4从节点上
DistributedClient代码运行在a1主节点上

代码如下:

public class DistributedServer {
    
    private static final String connectString = "min1:2181," +"min2:2181," +"min3:2181";
    private static final int sessionTimeout = 2000;
    private static final String parentNode = "/test2017-12-25";

    private ZooKeeper zk = null;

    public static void main(String[] args) throws Exception {

        // 获取zk连接
        DistributedServer server = new DistributedServer();
        server.getConnect();
        Thread.sleep(10*1000);
        // 利用zk连接注册服务器信息
        server.registerServer(args[0]);
        // 启动业务功能
        server.handleBussiness(args[0]);
    }
    
    /**
     * 创建到zk的客户端连接
     */
    public void getConnect() throws Exception {

        zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                // 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
                System.out.println(event.getType() + "---" + event.getPath());
                try {
                    zk.getChildren("/", true);
                } catch (Exception e) {
                }
            }
        });
    }

    /**
     * 向zk集群注册服务器信息
     */
    public void registerServer(String hostname) throws Exception {
        // CreateMode.EPHEMERAL_SEQUENTIAL  节点类型
        /**
         * 参数3 acl是Access Contral
         * ZooKeeper使用ACL来控制访问其znode(ZooKeeper的数据树的数据节点)。ACL的实现方式非常类似于UNIX文件的访问权限:它采用访问权限位 允许/禁止 对节点的各种操作以及能进行操作的范围。
         * 不同于UNIX权限的是,ZooKeeper的节点不局限于 用户(文件的拥有者),组和其他人(其它)这三个标准范围。ZooKeeper不具有znode的拥有者的概念。相反,ACL指定id集以及与之对应的权限。
         * http://ifeve.com/zookeeper-access-control-using-acls/
         */
        String create = zk.create(parentNode + "/server", hostname.getBytes(), 
                Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(hostname + "is online.." + create);
    }

    /**
     * 业务功能
     */
    public void handleBussiness(String hostname) throws InterruptedException {
        System.out.println(hostname + "start working.....");
        Thread.sleep(Long.MAX_VALUE);
    }
}

 

public class DistributedClient {
​
    private static final String connectString = "min1:2181," +"min2:2181," +"min3:2181";
    private static final int sessionTimeout = 2000;
    private static final String parentNode = "/test2017-12-25";
    private volatile List<String> serverList;
    private ZooKeeper zk = null;
​
    public static void main(String[] args) throws Exception {
​
        // 获取zk连接
        DistributedClient client = new DistributedClient();
        client.getConnect();
        Thread.sleep(10*1000);
        
        // 获取servers的子节点信息(并监听),从中获取服务器信息列表
        client.getServerList();
​
        // 业务线程启动
        client.handleBussiness();
    }
    /**
     * 创建到zk的客户端连接
     */
    public void getConnect() throws Exception {
​
        zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                // 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
                try {
                    //重新更新服务器列表,并且注册了监听
                    getServerList();
                } catch (Exception e) {}
            }
        });
    }
​
    /**
     * 获取服务器信息列表
     */
    public void getServerList() throws Exception {
​
        // 获取服务器子节点信息,并且对父节点进行监听
        List<String> children = zk.getChildren(parentNode, true);
​
        // 先创建一个局部的list来存服务器信息
        List<String> servers = new ArrayList<String>();
        for (String child : children) {
            // child只是子节点的节点名
            byte[] data = zk.getData(parentNode + "/" + child, false, null);
            servers.add(new String(data));
        }
        // 把servers赋值给成员变量serverList,已提供给各业务线程使用
        serverList = servers;
        
        //打印服务器列表
        System.out.println(serverList);
        
    }
​
    /**
     * 业务功能
     * 
     * @throws InterruptedException
     */
    public void handleBussiness() throws InterruptedException {
        System.out.println("client start working.....");
        Thread.sleep(Long.MAX_VALUE);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值