ZooKeeperクライアント開発


前述のZooKeeperの原理とサーバクラスタの導入はZooKeeperサーバクラスタの導入を完了し,本稿では公式APIとzkClientの2つの方法でZooKeeperデータの修正と状態監視を実証した.DubboにおけるZooKeeperの役割をコードでシミュレートした.作者:王克鋒出典:https://kefeng.wang/2017/11/10/zookeeper-development/ 著作権:自由転載-非商用-非派生-署名を保持し、転載は作者と出典を明記してください.
1.応用開発
APIドキュメント:https://zookeeper.apache.org/doc/current/api/index.html Javaの例:https://zookeeper.apache.org/doc/current/javaExample.html プログラマガイド:https://zookeeper.apache.org/doc/current/zookeeperProgrammers.html 通常、ZooKeeperアプリケーションは2つのユニットに分けられ、1つは接続を維持し、もう1つはデータを監視します.
1.1主要API
  • create:ノードの作成;
  • delete:ノードを削除する;
  • exists:ノードが存在するか否かを判断する;
  • get data:ノードデータの読み出し;
  • set data:ノードデータを書き込む;
  • get children:ノードのサブノードを取得する;
  • sync:データ同期;

  • 1.2 Zookeeper開発コンポーネント
    Document: http://zookeeper.apache.org/doc/r3.4.11/ ZooKeeper 3.4.11 API: https://zookeeper.apache.org/doc/r3.4.11/api/index.html
    zookeeperが持参したコンポーネントで、煩雑で信頼性がありません.
  • セッションタイムアウト異常の場合、再接続が煩雑である.
  • watcherは使い捨てであり、使い捨てサブスクリプションを永続サブスクリプションに変更する追加の符号化が必要である.
  • ノードデータはバイナリであり、オブジェクトデータはバイナリ保存に変換する必要がある.

  • 1.2.1 pom.xml
    
    <dependency>
        <groupId>org.apache.zookeepergroupId>
        <artifactId>zookeeperartifactId>
        <version>3.4.11version>
    dependency>

    1.2.2 ZookeeperClient.java
    public class ZookeeperClient {
        private static Log logger = LogFactory.getLog(ZookeeperClient.class);
    
        public static void main(String args[]) throws IOException, KeeperException, InterruptedException {
            //      
            final String serverUrl = "centos:2181,centos:2182,centos:2183";
            ZooKeeper zk = new ZooKeeper(serverUrl, 30000, new Watcher() {
                public void process(WatchedEvent event) { //           (     ,       watcher)
                    String path = event.getPath(); //     
                    Event.EventType type = event.getType(); //     (        、    ,     )
                    logger.info("***      : path=" + path + ", type=" + type);
                }
            });
    
            //     
            List acl = ZooDefs.Ids.OPEN_ACL_UNSAFE; //     (  ,      )
            CreateMode createMode = CreateMode.PERSISTENT; //     (    ,               ,        )
            zk.create("/parentNode", "parentData".getBytes(), acl, createMode);
            zk.create("/parentNode/childNode1", "childData1".getBytes(), acl, createMode); //        
            zk.create("/parentNode/childNode2", "childData2".getBytes(), acl, createMode);
    
            //     
            logger.info("     : " + zk.getChildren("/parentNode", true)); //        
            logger.info("     : " + (zk.exists("/parentNode/childNode1", true) != null));
            logger.info("     : " + new String(zk.getData("/parentNode/childNode1", true, null))); //       
            zk.setData("/parentNode/childNode1", "childData1-X".getBytes(), -1); //       (    1M,       )
            logger.info("     : " + new String(zk.getData("/parentNode/childNode1", true, null))); //       
    
            //     (          ,      )
            zk.delete("/parentNode/childNode2", -1);
            zk.delete("/parentNode/childNode1", -1);
            zk.delete("/parentNode", -1);
    
            //     
            zk.close();
        }
    }

    1.2.3運転結果
    15:33:59.215  INFO  [ZookeeperClient.java:24] - ***      : path=null, type=None
    15:33:59.233  INFO  [ZookeeperClient.java:36] -      : [childNode1, childNode2]
    15:33:59.237  INFO  [ZookeeperClient.java:37] -      : true
    15:33:59.240  INFO  [ZookeeperClient.java:38] -      : childData1
    15:33:59.247  INFO  [ZookeeperClient.java:24] - ***      : path=/parentNode/childNode1, type=NodeDataChanged
    15:33:59.247  INFO  [ZookeeperClient.java:40] -      : childData1-X
    15:33:59.252  INFO  [ZookeeperClient.java:24] - ***      : path=/parentNode, type=NodeChildrenChanged
    15:33:59.254  INFO  [ZookeeperClient.java:24] - ***      : path=/parentNode/childNode1, type=NodeDeleted

    1.3 zkClient開発コンポーネント
    公式ZooKeeper APIをカプセル化し、公式APIの欠点を回避した.https://github.com/sgroschupf/zkclient
    1.3.1 pom.xml
    <dependency>
        <groupId>com.101tecgroupId>
        <artifactId>zkclientartifactId>
        <version>0.10version>
    dependency>

    1.3.2 ZookeeperClient.java
    public class ZookeeperClient {
        private static Log logger = LogFactory.getLog(ZookeeperClient.class);
    
        public static void main(String args[]) {
            //      
            final String serverUrl = "centos:2181,centos:2182,centos:2183";
            ZkClient zk = new ZkClient(serverUrl);
    
            //     、       
            zk.createPersistent("/parentNode", "parentData"); //     
            zk.createEphemeral("/parentNode/childNode1", "childData1"); //     
            zk.createEphemeral("/parentNode/childNode2", "childData2"); //     
            zk.subscribeChildChanges("/parentNode", new IZkChildListener() { //        
                public void handleChildChange(String parentPath, List childList) throws Exception {
                    logger.info("***      : " + parentPath + ", " + childList);
                }
            });
            zk.subscribeDataChanges("/parentNode/childNode1", new IZkDataListener() { //     (   )  
                public void handleDataChange(String path, Object data) throws Exception {
                    logger.info("***       : " + path + ", " + data);
                }
    
                public void handleDataDeleted(String path) throws Exception {
                    logger.info("***       : " + path);
                }
            });
    
            //     
            logger.info("     : " + zk.getChildren("/parentNode"));
            logger.info("     : " + zk.exists("/parentNode/childNode1"));
            logger.info("     : " + zk.readData("/parentNode/childNode1"));
            zk.writeData("/parentNode/childNode1", "childData1-X"); //       (    1M,       )
            logger.info("     : " + zk.readData("/parentNode/childNode1"));
    
            //     (          ,      )
            zk.delete("/parentNode/childNode2");
            zk.delete("/parentNode/childNode1");
            zk.delete("/parentNode");
    
            //     
            zk.close();
        }
    }

    1.3.3運転結果
    16:17:21.904  INFO  [ZookeeperClient.java:42] -      : [childNode1, childNode2]
    16:17:21.904  INFO  [ZookeeperClient.java:43] -      : true
    16:17:21.909  INFO  [ZookeeperClient.java:44] -      : childData1
    16:17:21.919  INFO  [ZookeeperClient.java:46] -      : childData1-X
    16:17:21.921  INFO  [ZookeeperClient.java:33] - ***       : /parentNode/childNode1, childData1-X
    16:17:21.931  INFO  [ZookeeperClient.java:28] - ***      : /parentNode, []
    16:17:21.951  INFO  [ZookeeperClient.java:37] - ***       : /parentNode/childNode1

    2.dubboにおけるZooKeeperの応用
    ZooKeeperは構成センターとして、サービスアドレスの登録とクエリーを提供する.consumerサブスクリプションサービス(サブスクリプションイベント、サービスアドレスの変化を動的に感知する);provider登録サービス(zkノードの作成);
    ZooKeeperにおけるDubboのストレージ構造は以下の通りである(consumerブランチを増やすのは、サービス消費状況の統計を容易にするためである).
  • レベル1:ルートノード(configcenter)、永続ノード;
  • レベル2:各サービス名(serviceName)、永続ノード;
  • レベル3(拡張):ノード分類(nodeType)、provider/consumer、永続ノードを区別するために使用される.
  • レベル4[provider]:特定のserviceNameのプロバイダアドレスリスト(provideAddress)、非永続ノード、providerがラインオフすると自動的にノードが削除され、consumerに自動的に通知されます.
  • レベル4[consumer]:特定のserviceNameのコンシューマアドレスリスト(consumerAddress)は、非永続ノードであり、consumerがラインオフすると自動的に削除されます.

  • 2.1 ServiceProvider.java
    ServiceProviderが登録センター(ZooKeeperクラスタ)にサービスを登録するキーコード:
    public class ServiceProvider {
        private static Log logger = LogFactory.getLog(ServiceProvider.class);
        private static final String rootPath = "/configcenter";
        private static final String servicePath = rootPath + "/serviceName";
        private static final String zookeeperList = "centos:2181,centos:2182,centos:2183";
    
        public static void main(String args[]) throws UnknownHostException {
            ZkClient zk = new ZkClient(zookeeperList);
    
            //        
            if (!zk.exists(rootPath)) {
                zk.createPersistent(rootPath);
            }
    
            //         
            if (!zk.exists(servicePath)) {
                zk.createPersistent(servicePath);
            }
    
            //          IP
            String serviceIp = InetAddress.getLocalHost().getHostAddress().toString();
            zk.createEphemeral(servicePath + "/" + serviceIp);
    
            //     
            zk.close();
        }
    }

    2.2 ServiceConsumer.java
    ServiceConsumerは、登録センター(ZooKeeperクラスタ)からサービスプロバイダのアドレスリストのキーコードを取得します.
    public class ServiceConsumer {
        private static Log logger = LogFactory.getLog(ServiceConsumer.class);
        private static final String servicePath = "/configcenter/serviceName";
        private static final String zookeeperList = "centos:2181,centos:2182,centos:2183";
        private static List providerList = null; //               
    
        public static void main(String args[]) throws UnknownHostException {
            ZkClient zk = new ZkClient(zookeeperList);
    
            //          
            if (zk.exists(servicePath)) {
                providerList = zk.getChildren(servicePath);
            } else {
                throw new RuntimeException("[" + servicePath + "] not exist.");
            }
    
            //          
            zk.subscribeChildChanges(servicePath, new IZkChildListener() {
                public void handleChildChange(String parentPath, List childList) throws Exception {
                    providerList = childList;
                }
            });
    
            //     
            zk.close();
        }
    }