ZooKeeper zkClient的使用


ZkClient解决了watcher的一次性注册问题,将znode的事件重新定义为子节点的变化、数据的变化、连接状态的变化三类,有ZkClient统一将watcher的WatchedEvent转换到以上三种情况中去处理,watcher执行后重新读取数据的同时,在注册新的相同的watcher。

1.简单的使用ZkClient

    public static void main( String[] args )
    {
        //连接Zookeeper
        ZkClient zkClient = new ZkClient("127.0.0.1:2181");
        //创建节点
        zkClient.create("/root", "server data", CreateMode.PERSISTENT);
        //创建子节点
        zkClient.create("/root/server", "server data", CreateMode.EPHEMERAL);
        //获取子节点
        List<String> children = zkClient.getChildren("/root");
        //编辑子节点
        for (String item : children) {
            System.out.println(item);
        }
        //获取子节点的数量
        Integer number = zkClient.countChildren("/root");
        //判断节点是否存在
        if(zkClient.exists("/root")){
            System.out.println("存在");
        };
        //写入数据
        zkClient.writeData("/root/child", "哈哈哈");
        //读取节点数据
        Object object = zkClient.readData("/root/child");
        //删除节点
        zkClient.delete("/root/child");
    }
    

ZkClient将Zookeeper的watcher机制转化为一种更加容易理解的订阅形式,并且这种关系是可以保持的,而非一次性的。也就是说子节点的变化、数据的变化、状态的变化是可以订阅的。当watcher使用完后,zkClient会自动增加一个相同的watcher。

        zkClient.subscribeChildChanges("/root", new IZkChildListener() {
            
            @Override
            public void handleChildChange(String arg0, List<String> arg1) throws Exception {
                // TODO Auto-generated method stub
                System.out.println("子节点的变化");
            }
        });
        zkClient.subscribeDataChanges("/root", new IZkDataListener() {
            
            @Override
            public void handleDataDeleted(String arg0) throws Exception {
                // TODO Auto-generated method stub
                System.out.println("数据被删除");
            }
            
            @Override
            public void handleDataChange(String arg0, Object arg1) throws Exception {
                // TODO Auto-generated method stub
                System.out.println("数据被更改");
            }
        });
        zkClient.subscribeStateChanges(new IZkStateListener() {
            
            @Override
            public void handleStateChanged(KeeperState arg0) throws Exception {
                // TODO Auto-generated method stub
                System.out.println("数据状态改变");
            }
            
            @Override
            public void handleNewSession() throws Exception {
                // TODO Auto-generated method stub
                System.out.println("当session expire异常重新连接时,由于原来的所有的watcher和EPHEMERAL节点都已失效,可以在这里进行相应的容错处理");
            }
        });

2.路由和负载均衡的实现

当服务越来越多,规模越来越大,机器的数量也会越来越大,如果纯靠人工来管理和维护服务及地址的信息,已经越来越困难了。并且,依赖单一的硬件负载均衡设备或者使用LVS和Ngnix等软件方案来解决进行路由和负载均衡调度,一旦服务路由或者服务器宕机,所依赖的所有服务都将失效。如果采用双机高可用的部署方案,使用一台服务器“stand by”,能部分解决问题,但是鉴于负载均衡设备的昂贵成本,也难以全面推广。

一旦服务器与Zookeeper集群断开连接,节点就不存在了,通过注册相应的watcher,服务消费者能够第一时间获知提供者机器信息的变更。利用其znode的特点和watcher记住,将作为动态注册和获取服务信息的配置中心,统一管理服务名称和其对应的服务列表消息。我们近乎实时的感知到后端服务器的状态(上线、下线、宕机)。Zookeeper集群之间通过zab协议,服务配置信息能够保持一致,而Zookeeper本身的容错特性和leader选举机制,能保障我们方便地进行扩容。

        //基于Zookeeper所实现的服务消费者获取服务提供者地址列表的关键代码 消费者
        ZkClient zkClient = new ZkClient("127.0.0.1:2181");
        String serviceName = "service-B";
        String zkServiceList = "127.0.0.1:2181";
        
        String SERVICE_PATH = "/configcenter/"+serviceName;
        //判断是否存在
        boolean serviceExists = zkClient.exists(SERVICE_PATH);
        //如果存在,获取地址列表
        if(serviceExists){
            serviceList = zkClient.getChildren(SERVICE_PATH);
        }else{
            throw new RuntimeException("节点不存在");
        }
        //注册事件监听
        zkClient.subscribeChildChanges(SERVICE_PATH, new IZkChildListener() {
            
            @Override
            public void handleChildChange(String arg0, List<String> currentChilds) throws Exception {
                // TODO Auto-generated method stub
                //返回新的列表
                serviceList = currentChilds;
            }
        });

这段代码实例化了一个zkClient对象,判断服务名称是否已经注册,如果还没有注册该节点,则表明没有该服务,继而抛出异常。如果存在则获取其所有子节点获取地址后就可以通过负载均衡算法,选出一台服务器,发起远程调用。服务器列表缓存在本地只有当地址列表发生变化时,才需要更新该列表,以降低网络开销。这就是注册一个 subscribeChildChanges 的作用。

3.服务提供者想Zookeeper集群注册的部分关键代码:

        //服务提供者想Zookeeper集群注册服务的关键代码  服务者
        ZkClient zkClient = new ZkClient("127.0.0.1:2181");
        String PATH = "/configcenter";//根节点路径
        //判断是否存在
        boolean rootExists = zkClient.exists(PATH);
        //如果存在,获取地址列表
        if(!rootExists){
            zkClient.createPersistent(PATH);
        }
        String serviceName = "service-c";
        boolean serviceExists = zkClient.exists(PATH+"/"+serviceName);
        if(!serviceExists){
            zkClient.createPersistent((PATH+"/"+serviceName));
        }
        InetAddress address  = InetAddress.getLocalHost();
        //创建当前服务器节点
        String ip = address.getHostAddress().toString();
        //创建当前服务器节点
        zkClient.createEphemeral(PATH+"/"+serviceName+"/"+ip);
        
        for (String item : zkClient.getChildren("/configcenter")) {
            System.out.println(item);
        }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM