{"id":16599204,"url":"https://github.com/collabh/onload-zookeeper","last_synced_at":"2026-04-22T13:32:24.806Z","repository":{"id":42557545,"uuid":"208849146","full_name":"collabH/onload-zookeeper","owner":"collabH","description":"在路上zookeeper  配合有道笔记和石墨食用","archived":false,"fork":false,"pushed_at":"2023-10-11T21:05:37.000Z","size":37,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-14T15:39:32.980Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/collabH.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-16T16:39:52.000Z","updated_at":"2021-08-09T10:34:26.000Z","dependencies_parsed_at":"2022-08-24T01:20:51.065Z","dependency_job_id":null,"html_url":"https://github.com/collabH/onload-zookeeper","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/collabH/onload-zookeeper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collabH%2Fonload-zookeeper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collabH%2Fonload-zookeeper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collabH%2Fonload-zookeeper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collabH%2Fonload-zookeeper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/collabH","download_url":"https://codeload.github.com/collabH/onload-zookeeper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collabH%2Fonload-zookeeper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32139224,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T13:27:12.868Z","status":"ssl_error","status_checked_at":"2026-04-22T13:26:44.791Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T00:10:40.325Z","updated_at":"2026-04-22T13:32:24.770Z","avatar_url":"https://github.com/collabH.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zookeeper的Java原生客户端使用\n\n## 获取连接\n```java\npublic class ZookeeperConnection implements Watcher {\n    final static Logger log = LoggerFactory.getLogger(ZookeeperConnection.class);\n\n    public static final String zkServerPath = \"127.0.0.1:2181\";\n    public static final Integer timeout = 5000;\n\n    public static void main(String[] args) throws Exception {\n        /**\n         * 客户端和zk服务端链接是一个异步的过程\n         * 当连接成功后后，客户端会收的一个watch通知\n         *\n         * 参数：\n         * connectString：连接服务器的ip字符串，\n         * \t\t比如: \"192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181\"\n         * \t\t可以是一个ip，也可以是多个ip，一个ip代表单机，多个ip代表集群\n         * \t\t也可以在ip后加路径\n         * sessionTimeout：超时时间，心跳收不到了，那就超时\n         * watcher：通知事件，如果有对应的事件触发，则会收到一个通知；如果不需要，那就设置为null\n         * canBeReadOnly：可读，当这个物理机节点断开后，还是可以读到数据的，只是不能写，\n         * \t\t\t\t\t       此时数据被读取到的可能是旧数据，此处建议设置为false，不推荐使用\n         * sessionId：会话的id\n         * sessionPasswd：会话密码\t当会话丢失后，可以依据 sessionId 和 sessionPasswd 重新获取会话\n         */\n        ZooKeeper zk = new ZooKeeper(zkServerPath, timeout, new ZookeeperConnection());\n\n        log.warn(\"客户端开始连接zookeeper服务器...\");\n        log.warn(\"连接状态：{}\", zk.getState());\n\n        Thread.sleep(2000);\n\n        log.warn(\"连接状态：{}\", zk.getState());\n    }\n\n    public void process(WatchedEvent watchedEvent) {\n        log.warn(\"接受到watch通知：{}\", watchedEvent);\n    }\n}\n\n```\n\n## Zk会话重连机制\n```java\npublic class ZkConnectionSessionWatcher implements Watcher {\n    final static Logger log = LoggerFactory.getLogger(ZkConnectionSessionWatcher.class);\n\n    public static final String zkServerPath = \"127.0.0.1:2181\";\n    public static final Integer timeout = 5000;\n\n    public static void main(String[] args) throws Exception {\n\n        ZooKeeper zk = new ZooKeeper(zkServerPath, timeout, new ZkConnectionSessionWatcher());\n        long sessionId = zk.getSessionId();\n        byte[] sessionPasswd = zk.getSessionPasswd();\n        log.warn(\"客户端开始连接zookeeper服务器...\");\n        log.warn(\"连接状态：{}session id:{},pwd:{}\", zk.getState(),sessionId,sessionPasswd);\n        Thread.sleep(2000);\n        log.warn(\"连接状态：{}session id:{},pwd:{}\", zk.getState(),sessionId,sessionPasswd);\n        zk = new ZooKeeper(zkServerPath, timeout, new ZkConnectionSessionWatcher(), sessionId, sessionPasswd);\n        log.warn(\"重新连接状态：{}\", zk.getState());\n        Thread.sleep(2000);\n        log.warn(\"重新连接状态：{}\", zk.getState());\n    }\n\n    public void process(WatchedEvent watchedEvent) {\n        log.warn(\"接受到watch通知：{}\", watchedEvent);\n    }\n}\n\n```\n\n## Zk基本节点增删改查操作\n### Zk封装的操作类\n```java\npublic class ZkNodeOperator implements Watcher {\n    private ZooKeeper zk = null;\n    private static final Integer timeout = 5000;\n    private static final String zkServerPath = \"127.0.0.1:2181\";\n\n    public ZkNodeOperator() {\n\n    }\n\n    public ZkNodeOperator(String connectString) {\n        try {\n            zk = new ZooKeeper(connectString, timeout, this);\n        } catch (IOException e) {\n            log.warn(\"e\", e);\n            if (zk != null) {\n                try {\n                    zk.close();\n                } catch (InterruptedException ex) {\n                    log.warn(\"e\", e);\n                }\n            }\n        }\n    }\n\n\n    public String createNode(String path, byte[] data, List\u003cACL\u003e aclList) {\n        String result = \"\";\n        /**\n         * 同步或者异步创建节点，都不支持子节点的递归创建，异步有一个callback函数\n         * 参数：\n         * path：创建的路径\n         * data：存储的数据的byte[]\n         * acl：控制权限策略\n         * \t\t\tIds.OPEN_ACL_UNSAFE --\u003e world:anyone:cdrwa\n         * \t\t\tCREATOR_ALL_ACL --\u003e auth:user:password:cdrwa\n         * createMode：节点类型, 是一个枚举\n         * \t\t\tPERSISTENT：持久节点\n         * \t\t\tPERSISTENT_SEQUENTIAL：持久顺序节点\n         * \t\t\tEPHEMERAL：临时节点\n         * \t\t\tEPHEMERAL_SEQUENTIAL：临时顺序节点\n         */\n        //同步创建临时节点\n//            result = zk.create(path, data, aclList, CreateMode.EPHEMERAL);\n        try {\n            String ctx = \"{'create':'success'}\";\n            zk.create(path, data, aclList, CreateMode.PERSISTENT, (rc, p, c, name) -\u003e {\n                log.warn(\"创建节点:{}\", path);\n                log.warn(\"rc:{},ctx:{},name:{}\", rc, c, name);\n            }, ctx);\n            log.warn(\"create result:{}\", result);\n            //fixme 睡眠为了防止节点还没创建成功，zk客户端就断开连接\n            Thread.sleep(2000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return result;\n\n    }\n\n    /**\n     * 修改节点数据\n     *\n     * @param path\n     * @param data\n     * @param version\n     */\n    public void setNode(String path, byte[] data, int version) {/*\n        try {\n\n            //同步修改\n            Stat stat = zk.setData(path, data, version);\n\n            log.warn(\"stat:{}\", stat);\n        } catch (KeeperException | InterruptedException e) {\n            e.printStackTrace();\n        }*/\n        //异步修改\n        String ctx = \"{'create':'success'}\";\n        zk.setData(path, data, version, (rc, p, c, name) -\u003e {\n            log.warn(\"创建节点:{}\", p);\n            log.warn(\"rc:{},ctx:{},name:{}\", rc, c, name);\n        }, ctx);\n        try {\n            Thread.sleep(10000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void deleteNode(String path, int version) {\n        try {\n            //同步删除\n            zk.delete(path, version);\n            //异步删除\n            //zk.delete(path, version, (i, s, o) -\u003e log.warn(\"创建节点:{},{}.{}\", i,s,o), \"zhangsan\");\n        } catch (InterruptedException | KeeperException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void process(WatchedEvent watchedEvent) {\n        log.warn(\"event:{}\", watchedEvent);\n    }\n\n    public static void main(String[] args) {\n        ZkNodeOperator zkNodeOperator = new ZkNodeOperator(zkServerPath);\n        //zkNodeOperator.createNode(\"/test1\", \"zhangsan\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE);\n        //zkNodeOperator.setNode(\"/test1\", \"luoquanwg\".getBytes(), 1);\n        zkNodeOperator.deleteNode(\"/test1\", 1);\n    }\n\n}\n```\n### zk节点查询和监听\n```java\npublic class QueryAndWatch{\n    private static final CountDownLatch LATCH = new CountDownLatch(1);\n     private static final Stat stat = new Stat();\n    \n     /**\n         * 查询\n         *\n         * @param path\n         * @param stat\n         * @return\n         */\n        public byte[] queryNode(String path, boolean watch, Stat stat) {\n            byte[] data = new byte[0];\n            try {\n                /**\n                 * 参数\n                 * path:节点路径\n                 * watch:true或false 注册一个watch事件\n                 * stat:状态\n                 */\n                data = zk.getData(path, watch, stat);\n                log.warn(new String(data, Charset.defaultCharset()));\n                log.warn(\"version :{}\", stat.getVersion());\n                LATCH.await();\n    \n            } catch (KeeperException e) {\n                e.printStackTrace();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n    \n            return data;\n        }\n    \n        @Override\n        public void process(WatchedEvent watchedEvent) {\n            log.warn(\"event:{}\", watchedEvent);\n            try {\n                switch (watchedEvent.getType()) {\n                    case NodeDataChanged:\n                        byte[] bytes = zk.getData(\"/name\", false, stat);\n                        log.warn(new String(bytes, Charset.defaultCharset()));\n                        log.warn(\"version变化:{}\", stat.getVersion());\n                        LATCH.countDown();\n                        break;\n                    case NodeCreated:\n                        break;\n                    case NodeDeleted:\n                        break;\n                    case NodeChildrenChanged:\n                        break;\n                    default:\n                        break;\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n}\n    \n```\n### zk子节点查询和监听\n```java\npublic class ZKGetChildrenList implements Watcher {\n\n    private ZooKeeper zookeeper = null;\n\n    public static final String zkServerPath = \"localhost:2181\";\n    public static final Integer timeout = 5000;\n\n    public ZKGetChildrenList() {\n    }\n\n    public ZKGetChildrenList(String connectString) {\n        try {\n            zookeeper = new ZooKeeper(connectString, timeout, new ZKGetChildrenList());\n        } catch (IOException e) {\n            e.printStackTrace();\n            if (zookeeper != null) {\n                try {\n                    zookeeper.close();\n                } catch (InterruptedException e1) {\n                    e1.printStackTrace();\n                }\n            }\n        }\n    }\n\n    private static CountDownLatch countDown = new CountDownLatch(1);\n\n    public static void main(String[] args) throws Exception {\n\n        ZKGetChildrenList zkServer = new ZKGetChildrenList(zkServerPath);\n\n        /**\n         * 参数：\n         * path：父节点路径\n         * watch：true或者false，注册一个watch事件\n         */\n//\t\tList\u003cString\u003e strChildList = zkServer.getZookeeper().getChildren(\"/name\", true);\n//\t\tfor (String s : strChildList) {\n//\t\t\tSystem.out.println(s);\n//\t\t}\n\n        // 异步调用\n        String ctx = \"{'callback':'ChildrenCallback'}\";\n//\t\tzkServer.getZookeeper().getChildren(\"/name\", true, new ChildrenCallBack(), ctx);\n        zkServer.getZookeeper().getChildren(\"/name\", true, (i, s, o, s1) -\u003e {\n            log.warn(\"{},{},{},{}\", i, s, o, s1);\n        }, ctx);\n\n        countDown.await();\n    }\n\n    @Override\n    public void process(WatchedEvent event) {\n        try {\n            //监听子节点变化\n            if (event.getType() == EventType.NodeChildrenChanged) {\n                System.out.println(\"NodeChildrenChanged\");\n                ZKGetChildrenList zkServer = new ZKGetChildrenList(zkServerPath);\n                List\u003cString\u003e strChildList = zkServer.getZookeeper().getChildren(event.getPath(), false);\n                for (String s : strChildList) {\n                    System.out.println(s);\n                }\n                countDown.countDown();\n            } else if (event.getType() == EventType.NodeCreated) {\n                System.out.println(\"NodeCreated\");\n            } else if (event.getType() == EventType.NodeDataChanged) {\n                System.out.println(\"NodeDataChanged\");\n            } else if (event.getType() == EventType.NodeDeleted) {\n                System.out.println(\"NodeDeleted\");\n            }\n        } catch (KeeperException e) {\n            e.printStackTrace();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public ZooKeeper getZookeeper() {\n        return zookeeper;\n    }\n\n    public void setZookeeper(ZooKeeper zookeeper) {\n        this.zookeeper = zookeeper;\n    }\n\n}\n```\n\n### zk权限控制 ACL\n```java\npublic class ZKNodeAcl implements Watcher {\n\n    private ZooKeeper zookeeper = null;\n\n    public static final String zkServerPath = \"127.0.0.1:2181\";\n    public static final Integer timeout = 5000;\n\n    public ZKNodeAcl() {\n    }\n\n    public ZKNodeAcl(String connectString) {\n        try {\n            zookeeper = new ZooKeeper(connectString, timeout, new ZKNodeAcl());\n        } catch (IOException e) {\n            e.printStackTrace();\n            if (zookeeper != null) {\n                try {\n                    zookeeper.close();\n                } catch (InterruptedException e1) {\n                    e1.printStackTrace();\n                }\n            }\n        }\n    }\n\n    public void createZKNode(String path, byte[] data, List\u003cACL\u003e acls) {\n\n        String result = \"\";\n        try {\n            /**\n             * 同步或者异步创建节点，都不支持子节点的递归创建，异步有一个callback函数\n             * 参数：\n             * path：创建的路径\n             * data：存储的数据的byte[]\n             * acl：控制权限策略\n             * \t\t\tIds.OPEN_ACL_UNSAFE --\u003e world:anyone:cdrwa\n             * \t\t\tCREATOR_ALL_ACL --\u003e auth:user:password:cdrwa\n             * createMode：节点类型, 是一个枚举\n             * \t\t\tPERSISTENT：持久节点\n             * \t\t\tPERSISTENT_SEQUENTIAL：持久顺序节点\n             * \t\t\tEPHEMERAL：临时节点\n             * \t\t\tEPHEMERAL_SEQUENTIAL：临时顺序节点\n             */\n            result = zookeeper.create(path, data, acls, CreateMode.PERSISTENT);\n            System.out.println(\"创建节点：\\t\" + result + \"\\t成功...\");\n        } catch (KeeperException e) {\n            e.printStackTrace();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        ZKNodeAcl zkServer = new ZKNodeAcl(zkServerPath);\n\n        /**\n         * ======================  创建node start  ======================\n         */\n        // acl 任何人都可以访问\n        //zkServer.createZKNode(\"/test\", \"test\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE);\n\n        // 自定义用户认证访问\n//\t\tList\u003cACL\u003e acls = new ArrayList\u003cACL\u003e();\n//\t\tId name1 = new Id(\"digest\", AclUtils.getDigestUserPwd(\"name:123456\"));\n//\t\tId name2 = new Id(\"digest\", AclUtils.getDigestUserPwd(\"name:123456\"));\n//\t\tacls.add(new ACL(ZooDefs.Perms.ALL, name1));\n//\t\tacls.add(new ACL(ZooDefs.Perms.READ, name2));\n//\t\tacls.add(new ACL(ZooDefs.Perms.DELETE | ZooDefs.Perms.CREATE, name2));\n//\t\tzkServer.createZKNode(\"/test/testdigest\", \"testdigest\".getBytes(), acls);\n\n        // 注册过的用户必须通过addAuthInfo才能操作节点，参考命令行 addauth\n//        zkServer.getZookeeper().addAuthInfo(\"digest\", \"name:123456\".getBytes());\n//        zkServer.createZKNode(\"/test/testdigest/childtest\", \"childtest\".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL);\n//        Stat stat = new Stat();\n//        byte[] data = zkServer.getZookeeper().getData(\"/test/testdigest\", false, stat);\n//        System.out.println(new String(data));\n//        zkServer.getZookeeper().setData(\"/test/testdigest\", \"now\".getBytes(), 0);\n\n        // ip方式的acl\n//        List\u003cACL\u003e aclsIP = new ArrayList\u003cACL\u003e();\n//        Id ipId1 = new Id(\"ip\", \"127.0.0.1\");\n//        aclsIP.add(new ACL(ZooDefs.Perms.ALL, ipId1));\n//        zkServer.createZKNode(\"/test/iptest6\", \"iptest\".getBytes(), aclsIP);\n\n        // 验证ip是否有权限\n        zkServer.getZookeeper().setData(\"/test/iptest6\", \"now\".getBytes(), 0);\n        Stat stat = new Stat();\n        byte[] data = zkServer.getZookeeper().getData(\"/test/iptest6\", false, stat);\n        System.out.println(new String(data));\n        System.out.println(stat.getVersion());\n    }\n\n    public ZooKeeper getZookeeper() {\n        return zookeeper;\n    }\n\n    public void setZookeeper(ZooKeeper zookeeper) {\n        this.zookeeper = zookeeper;\n    }\n\n    @Override\n    public void process(WatchedEvent event) {\n\n    }\n}\n```\n# Apache curator zk客户端\n## 相比于原生客户端的优势\n* 解决watcher的注册一次就失效\n* 提供更多解决方案并且实现简单：比如 分布式锁\n* 提供常用的Zookeeper工具类\n* 支持节点的递归创建\n\n\n## curator基本操作\n```java\npublic class CuratorOperator {\n    private CuratorFramework client = null;\n    private static final String zkConnection = \"127.0.0.1:2181\";\n\n    public CuratorOperator() {\n        /**\n         * 同步创建zk示例，原生api是异步的\n         * 重试策略，在重试之间增加睡眠时间，重试一组次数\n         * curator链接zookeeper的策略:ExponentialBackoffRetry\n         * baseSleepTimeMs：初始sleep的时间\n         * maxRetries：最大重试次数\n         * maxSleepMs：最大重试时间\n         */\n        //RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);\n\n        /**\n         * curator链接zookeeper的策略:RetryNTimes 重试n次\n         * n：重试的次数\n         * sleepMsBetweenRetries：每次重试间隔的时间\n         */\n        RetryPolicy retryPolicy = new RetryNTimes(3, 5000);\n\n        /**\n         * curator链接zookeeper的策略:RetryOneTime 重试一次\n         * sleepMsBetweenRetry:每次重试间隔的时间\n         */\n//\t\tRetryPolicy retryPolicy2 = new RetryOneTime(3000);\n\n        /**\n         * 永远重试，不推荐使用\n         */\n//\t\tRetryPolicy retryPolicy3 = new RetryForever(retryIntervalMs)\n\n        /**\n         * 重试策略，重试直到指定的时间过期为止\n         * curator链接zookeeper的策略:RetryUntilElapsed\n         * maxElapsedTimeMs:最大重试时间\n         * sleepMsBetweenRetries:每次重试间隔\n         * 重试时间超过maxElapsedTimeMs后，就不再重试\n         */\n//\t\tRetryPolicy retryPolicy4 = new RetryUntilElapsed(2000, 3000);\n\n        //重试策略，在重试之间以增加的睡眠时间(最多达到最大限度)重试一组次数\n        //RetryPolicy retryPolicy=new BoundedExponentialBackoffRetry();\n        client = CuratorFrameworkFactory.builder()\n                .connectString(zkConnection)\n                .sessionTimeoutMs(10000).retryPolicy(retryPolicy)\n                //根节点为namespace\n                .namespace(\"namespace\").build();\n        client.start();\n    }\n\n    private void close() {\n        client.close();\n    }\n\n    public static void main(String[] args) throws Exception {\n        /**\n         * creatingParentsIfNeeded递归创建节点\n         * /test/a/b/c\n         */\n        CuratorOperator curatorOperator = new CuratorOperator();\n        String path = \"/super/name\";\n        //add node\n//        curatorOperator.client.create()\n//                .creatingParentsIfNeeded()\n//                .withMode(CreateMode.PERSISTENT)\n//                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)\n//                .forPath(path);\n        //update node\n//        curatorOperator.client.setData()\n//                .withVersion(0)\n//                .forPath(path, \"zhangsan\".getBytes());\n        //delete node\n        /**\n         * guaranteed:防止发生网络抖动时，成功的请求可能没有返回客户端，guaranteed可以保证节点被删除\n         * deletingChildrenIfNeeded:如果有子节点，就删除\n         */\n        curatorOperator.client.delete()\n                .guaranteed()\n                .deletingChildrenIfNeeded()\n                .withVersion(2)\n                .forPath(path);\n        Thread.sleep(3000);\n        curatorOperator.close();\n        System.out.println(curatorOperator.client.isStarted());\n    }\n}\n```\n## add Watcher事件\n### 使用NodeCache监听节点信息\n优点:**解决原生添加一次Watcher只能触发一次问题**\n```java\npublic class WatcherListener {\n    public static void main(String[] args) throws Exception {\n        CuratorOperator operator = new CuratorOperator();\n        String path = \"/super/name\";\n        //watcher事件 当使用usingWatcher的时候，监听只会触发一次，监听完毕后就销毁\n      /*  byte[] curatorWatch = operator.client\n                .getData()\n                .usingWatcher(new MyCuratorWatcher())\n                .forPath(path);\n        byte[] watch = operator.client\n                .getData()\n                .usingWatcher(new MyCuratorWatcher())\n                .forPath(path);\n        log.warn(\"curatorWatch{}\", new String(curatorWatch, StandardCharsets.UTF_8));\n        log.warn(\"watch{}\", new String(watch, StandardCharsets.UTF_8));*/\n        /**\n         * 为节点添加watcher\n         * NodeCache:监听数据节点的变更，会触发事件\n         * 注册一次，触发多次\n         * dataIsCompressed:是否压缩数据，true为是，false为否\n         */\n        NodeCache nodeCache = new NodeCache(operator.client, path);\n        //buildInitial：初始化的时候获取node的值并且缓存到本地\n        nodeCache.start(true);\n        if (nodeCache.getCurrentData() != null) {\n            log.warn(\"节点初始化数据为:{}\", new String(nodeCache.getCurrentData().getData()));\n        } else {\n            log.warn(\"节点初始化数据为空\");\n        }\n        nodeCache.getListenable()\n                .addListener(() -\u003e log.warn(\"节点初始化数据为:{}\", new String(nodeCache.getCurrentData().getData())));\n        Thread.sleep(100000);\n    }\n\n}\n```\n### 使用PathChildrenCache监听父节点的增删改事件\n```java\npublic class PathChildrenCacheWatcherListener {\n    public static void main(String[] args) throws Exception {\n        CuratorOperator operator = new CuratorOperator();\n        String path = \"/super\";\n        /**\n         * cacheData:设置缓存节点的数据状态\n         * StartMode：初始化方式\n         * 异步方式不会有数据响应，所以数据无法得到\n         * POST_INITIALIZED_EVENT:异步初始化，初始化之后会触发事件\n         * NORMAL:异步初始化\n         * BUILD_INITIAL_CACHE: 同步初始化\n         */\n        PathChildrenCache cache = new PathChildrenCache(operator.client, path, true);\n        cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);\n        List\u003cChildData\u003e childDataList = cache.getCurrentData();\n        childDataList.forEach(\n                childData -\u003e {\n                    String data = new String(childData.getData(), StandardCharsets.UTF_8);\n                    log.warn(\"data:{}\", data);\n                }\n        );\n        cache.getListenable()\n                .addListener((curatorFramework, event) -\u003e {\n                    if (event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)) {\n                        System.out.println(\"子节点初始化ok...\");\n                    } else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)) {\n                        String path1 = event.getData().getPath();\n                        if (path1.equals(\"/super/aa\")) {\n                            System.out.println(\"添加子节点:\" + event.getData().getPath());\n                            System.out.println(\"子节点数据:\" + new String(event.getData().getData()));\n                        } else if (path1.equals(\"/super/namez\")) {\n                            System.out.println(\"添加不正确...\");\n                        }\n\n                    } else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {\n                        System.out.println(\"删除子节点:\" + event.getData().getPath());\n                    } else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {\n                        System.out.println(\"修改子节点路径:\" + event.getData().getPath());\n                        System.out.println(\"修改子节点数据:\" + new String(event.getData().getData()));\n                    }\n                });\n        Thread.sleep(100000);\n    }\n}\n```\n## Curator的Acl\n```java\npublic class CuratorAcl {\n\n    public CuratorFramework client = null;\n    public static final String zkServerPath = \"127.0.0.1:2181\";\n\n    public CuratorAcl() {\n        RetryPolicy retryPolicy = new RetryNTimes(3, 5000);\n        //add添加authInfo\n        client = CuratorFrameworkFactory.builder().authorization(\"digest\", \"name2:123456\".getBytes())\n                .connectString(zkServerPath)\n                .sessionTimeoutMs(10000).retryPolicy(retryPolicy)\n                .namespace(\"namespace\").build();\n        client.start();\n    }\n\n    public void closeZKClient() {\n        if (client != null) {\n            this.client.close();\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // 实例化\n        CuratorAcl cto = new CuratorAcl();\n        boolean isZkCuratorStarted = cto.client.isStarted();\n        System.out.println(\"当前客户的状态：\" + (isZkCuratorStarted ? \"连接中\" : \"已关闭\"));\n\n        String nodePath = \"/acl/father/child/sub/h\";\n\n        List\u003cACL\u003e acls = new ArrayList\u003cACL\u003e();\n        Id name1 = new Id(\"digest\", AclUtils.getDigestUserPwd(\"name1:123456\"));\n        Id name2 = new Id(\"digest\", AclUtils.getDigestUserPwd(\"name2:123456\"));\n        acls.add(new ACL(Perms.ALL, name1));\n        acls.add(new ACL(Perms.READ, name2));\n        acls.add(new ACL(Perms.DELETE | Perms.CREATE, name2));\n\n        /**\n         * withACL:\n         *\n         *applyToParents:如果applyToParents为true，则aclList应用于创建的父类。现有父节点不受影响。\n         */\n        // 创建节点\n//        byte[] data = \"spiderman\".getBytes();\n//        cto.client.create().creatingParentsIfNeeded()\n//                .withMode(CreateMode.PERSISTENT)\n//                .withACL(acls, true)\n//                .forPath(nodePath, data);\n\n        //修改权限\n       // cto.client.setACL().withACL(acls).forPath(\"/curatorNode\");\n\n        // 更新节点数据 name2没有权限\n\t\tbyte[] newData = \"batman\".getBytes();\n\t\tcto.client.setData().withVersion(0).forPath(nodePath, newData);\n\n        // 删除节点\n//\t\tcto.client.delete().guaranteed().deletingChildrenIfNeeded().withVersion(0).forPath(nodePath);\n\n        // 读取节点数据\n//\t\tStat stat = new Stat();\n//\t\tbyte[] data = cto.client.getData().storingStatIn(stat).forPath(nodePath);\n//\t\tSystem.out.println(\"节点\" + nodePath + \"的数据为: \" + new String(data));\n//\t\tSystem.out.println(\"该节点的版本号为: \" + stat.getVersion());\n\n\n        cto.closeZKClient();\n        boolean isZkCuratorStarted2 = cto.client.isStarted();\n        System.out.println(\"当前客户的状态：\" + (isZkCuratorStarted2 ? \"连接中\" : \"已关闭\"));\n    }\n\n}\n```\n\n## 基于Curator的分布式锁测试\n```\n根据jmeter测试得到\n线程组设置如下:\n线程数:2\nRamp-up:0\n结果如下:\n2019-09-22 21:13:57,405 [http-nio-9000-exec-3] [INFO] 获取锁成功\n2019-09-22 21:13:57,405 [http-nio-9000-exec-11] [INFO] 获取锁失败\n```\n\n**不足之处**\n* 获得锁通过CountDownLatch和死循环，每次计数器countDown后，就会new一个新的，如果突然大并发上来，就会new多个CountDownLatch对象，造成内存溢出危险\n* 并且全部都会阻塞在此，导致整个服务线程被打满，很有核心也会发生jvm线程阻塞，后期请求将会卡死在此","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcollabh%2Fonload-zookeeper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcollabh%2Fonload-zookeeper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcollabh%2Fonload-zookeeper/lists"}