zookeeper之Curator

Curator客户端

  1. Curator包含了几个包:
    • curator-framework:对zookeeper的底层api的一些封装
    • curator-client:提供一些客户端的操作,例如重试策略等
    • curator-recipes:封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等
  2. 版本
    • The are currently two released versions of Curator, 2.x.x and 3.x.x:
    • Curator 2.x.x - compatible with both ZooKeeper 3.4.x and ZooKeeper 3.5.x
    • Curator 3.x.x - compatible only with ZooKeeper 3.5.x and includes support for new features such as dynamic reconfiguration, etc.
  3. Curator主要解决了以下问题
    • 封装ZooKeeper clientZooKeeper server之间的连接处理
    • 提供了一套Fluent风格的操作API
    • 提供ZooKeeper各种应用场景(recipe, 比如共享锁服务, 集群领导选举机制)的抽象封装
  4. 这里使用的版本
    • 服务端Zookeeper版本:3.4.6
    • Curator版本:compile "org.apache.curator:curator-recipes:2.11.0"

创建会话

  1. 创建会话

         @Test
        public void testCreateClient() throws Exception{
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            /**
             *   失去连接重试策略
             *    baseSleepTimeMs 初始sleep时间
             *    maxRetries    最大重试次数
             *    maxSleepMs    最大sleep时间
             *    当前sleep时间=baseSleepTimeMs*Math.mac(1,random.next(1)) << (retryCount+1)
             */
            int baseSleepTimeMs;
            int maxRetries;
            int maxSleepMs;
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
    
            //第一种方式,使用Builder fluent风格的API方式创建
            CuratorFramework curatorFramework1 = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .build();
            CuratorFrameworkState state1 = curatorFramework1.getState();
            //zk-curator - LATENT
            logger.info(state1.toString());
    
            //当连接状态变化时触发
            curatorFramework1.getConnectionStateListenable().addListener(new ConnectionStateListener() {
                @Override
                public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
                    //连接状态事件:true
                    logger.info("连接状态事件:{}",connectionState.isConnected());
                }
            });
    
            //完成会话的创建
            curatorFramework1.start();
    
    
    
            //第二种方式,使用静态工厂方式创建,此方式本质上还是通过第一种方式创建
            CuratorFramework curatorFramework2 =
                    CuratorFrameworkFactory.newClient(
                            connectString,
                            sessionTimeoutMs,
                            connectionTimeoutMs,
                            retryPolicy);
            CuratorFrameworkState state2 = curatorFramework2.getState();
            //zk-curator - LATENT
            logger.info(state2.toString());
    
    
            /**
             * 临时客户端:
             *      一定时间不活动后连接会被关闭,使用buildTemp()创建
             */
            CuratorTempFramework curatorFramewor3 = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .buildTemp(2000,TimeUnit.SECONDS);
                    //.buildTemp();
            TimeUnit.SECONDS.sleep(20);
    
        }
    

创建节点

  1. 创建节点

      @Test
      public void testCreateZnode() throws Exception {
    
          String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
          int sessionTimeoutMs = 25000;
          int connectionTimeoutMs = 5000;
          String rootPath = "jannal-create";
          RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
          CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                  .connectString(connectString)
                  .sessionTimeoutMs(sessionTimeoutMs)
                  .connectionTimeoutMs(connectionTimeoutMs)
                  .retryPolicy(retryPolicy)
                  .namespace(rootPath) //客户端对zk上的数据节点的操作都是基本此根节点进行的
                  .build();
          //完成会话创建
          curatorFramework.start();
    
          //创建一个初始内容为空的znode,默认创建的是持久节点
          curatorFramework.create().forPath("/userEmpty");
          //创建一个附带内容的znode
          curatorFramework.create().forPath("/userData", "我是jannal".getBytes(Charsets.UTF_8));
          //创建一个临时节点
          curatorFramework.create().
                  withMode(CreateMode.EPHEMERAL).
                  forPath("/userTemp", "jannal".getBytes(Charsets.UTF_8));
          //自动递归创建父节点creatingParentsIfNeeded()
          curatorFramework.create()
                  .creatingParentsIfNeeded()
                  .withMode(CreateMode.PERSISTENT)
                  .forPath("/user/password", "123456".getBytes(Charsets.UTF_8));
    
    
          curatorFramework.getCuratorListenable().addListener(new CuratorListener() {
              @Override
              public void eventReceived(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
    
              }
          });
    
          ExecutorService executorService = Executors.newFixedThreadPool(2);
          CountDownLatch countDownLatch = new CountDownLatch(1);
          /**
           * 在原生的zookeeper客户端中,所有异步通知事件处理都是通过EventThread这个
           * 线程处理的(串行处理所有事件的通知)。一旦发生复杂的处理单元就会消耗很长事件
           * 从而影响其他事件的处理,Curator可以使用线程池来处理,如果不指定线程池
           * 则默认使用EventThread来处理
           */
          curatorFramework.create()
                  .creatingParentsIfNeeded()
                  .withMode(CreateMode.EPHEMERAL)
                  .inBackground(new BackgroundCallback() {
                      @Override
                      public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                          logger.info(event.toString());
                          countDownLatch.countDown();
                      }
                  },executorService)
                  .forPath("/user2","jannal2".getBytes(Charsets.UTF_8));
    
    
    
          countDownLatch.await();
          executorService.shutdown();
    
      }
    

获取节点和数据

  1. 获取节点和数据

        @Test
        public void testGetZnode() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-get";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath("/user/username/jannal", "jannal123".getBytes(Charsets.UTF_8));
    
            //获取数据
            byte[] bytes = client.getData().forPath("/user/username/jannal");
    
            Assert.assertEquals("jannal123", new String(bytes, Charsets.UTF_8));
    
            //读取一个节点的数据内容,同时获取到该节点的stat
            Stat stat = new Stat();
            bytes = client.getData().storingStatIn(stat).forPath("/user/username/jannal");
            logger.info(ToStringBuilder.reflectionToString(stat));
    
            client.create().creatingParentsIfNeeded().forPath("/user/username1", "abc".getBytes(Charsets.UTF_8));
            client.create().creatingParentsIfNeeded().forPath("/user/username2", "def".getBytes(Charsets.UTF_8));
            //获取节点的子节点路径
            List<String> strings = client.getChildren().forPath("/user");
            //[username2, username1, username]
            logger.info(strings.toString());
    
        }
    
    

更新数据

  1. 更新数据

        @Test
        public void testSetZnode() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-update";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath) //客户端对zk上的数据节点的操作都是基本此根节点进行的
                    .build();
            curatorFramework.start();
    
            String path = "/user/password";
    
            curatorFramework.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.PERSISTENT)
                    .forPath("/user/password", "123456".getBytes(Charsets.UTF_8));
            byte[] bytes = curatorFramework.getData().forPath(path);
            Assert.assertEquals("123456", new String(bytes, Charsets.UTF_8));
    
            Stat stat = curatorFramework.setData().forPath(path, "abcd".getBytes(Charsets.UTF_8));
            bytes = curatorFramework.getData().forPath(path);
            Assert.assertEquals("abcd", new String(bytes, Charsets.UTF_8));
    
            //更新一个节点的数据内容,强制指定版本进行更新
            curatorFramework.setData().withVersion(stat.getVersion()).forPath(path, "abcde".getBytes());
    
        }
    
    
    

删除节点

  1. 在删除一个节点时,由于网络原因,导致删除操作失败。这个异常在有些场景下是致命的,比如Master选举(先创建后删除),针对这个问题Curator引入了一种重试机制,即如果我们调用了guaranteed(),那么只要客户端有效,就会在后台反复重试,直到节点删除成功。

  2. 删除节点示例

        @Test
        public void testDeleteZnode() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-delete";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath("/user/username/jannal", "jannal123".getBytes(Charsets.UTF_8));
    
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath("/user2/username/jannal", "jannal123".getBytes(Charsets.UTF_8));
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath("/user3/username/jannal", "jannal123".getBytes(Charsets.UTF_8));
    
    
    
            //删除节点且递归删除其所有的子节点
            client.delete().deletingChildrenIfNeeded().forPath("/user");
            //强制指定版本进行删除
            client.delete().deletingChildrenIfNeeded().withVersion(0).forPath("/user2");
            //强制保证删除,只要客户端有效,Curator会在后台持续进行删除操作,直到节点删除成功
            client.delete().guaranteed().forPath("/user3/username/jannal");
    
        }
    

事务

  1. 事务

     /**
         * inTransaction()开启事务,可以复合create, setData, check, and/or delete
         * 等操作然后调用commit()作为一个原子操作提交
         *
         * @throws Exception
         */
        @Test
        public void testTransaction() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-transaction";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
    
            client.inTransaction()
                    .create().withMode(CreateMode.EPHEMERAL).forPath("/transaction", "事务".getBytes(Charsets.UTF_8))
                    .and()
                    .delete().forPath("/transaction")
                    .and()
                    .commit();
        }
    
    

节点存在

  1. 判断节点是否存在

     @Test
        public void testExist() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-Exist";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            //节点不存在返回null
            Stat stat = client.checkExists().forPath("/jannal");
            Assert.assertEquals(null, stat);
            logger.info(ToStringBuilder.reflectionToString(stat));
        }
    
    
    

事件监听

  1. 原生客户端支持通过注册Watch来进行事件监听,但是收到事件通知后每次都需要手动再次注册Watch。Curator引入了Cache来实现对Zookeeper服务端事件的监听,并且自动处理反复注册监听,简化了原生API的繁琐。

  2. Cache分为两类监听

    • 节点监听
    • 子节点监听
  3. NodeCache用于监听指定Zookeeper数据节点本身的变化,数据内容发生变化时,就会回调此方法。

      @Test
        public void testNodeCacheEventListener() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-listener";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            String path = "/user/username/jannal";
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath(path, "jannal123".getBytes(Charsets.UTF_8));
            //是否进行数据压缩
            boolean dataIsCompressed = false;
            final NodeCache cache = new NodeCache(client, path, dataIsCompressed);
            cache.start(true);
            CountDownLatch countDownLatch = new CountDownLatch(2);
            cache.getListenable().addListener(new NodeCacheListener() {
                @Override
                public void nodeChanged() throws Exception {
                    ChildData currentData = cache.getCurrentData();
                    if (currentData != null) {
                        logger.info("数据发生变更,新数据:{}", new String(currentData.getData(), StandardCharsets.UTF_8));
                    }else{
                        logger.info("数据发生变更,新数据:{},节点可能被删除", currentData, StandardCharsets.UTF_8);
                    }
    
                    countDownLatch.countDown();
                }
            });
    
            client.setData().forPath(path, "jannal".getBytes(Charsets.UTF_8));
            client.delete().deletingChildrenIfNeeded().forPath(path);
            countDownLatch.await();
        }
    
    
  4. PathChildrenCache用于监听指定Zookeeper数据节点的子节点变化情况。当指定节点的子节点发生变化时,就会回调Listener。Curator无法对二级子节点触发变更事件。比如对/zk-jannal子节点进行监听,当/zk-jannal/user/password节点被创建或者删除的时候,无法触发子节点变更事件

        @Test
        public void testPathChildrenCacheEventListener() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-parent-listener";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            String path = "/user";
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath(path, "jannal123".getBytes(Charsets.UTF_8));
            //是否进行数据压缩
            boolean dataIsCompressed = false;
            /**
             * 是否把节点内容缓存起来,如果配置为true,则client在接收
             * 到节点列表变更的同时,也能够获取到节点的数据内容,如果为false
             * 则无法获取节点的数据内容
             */
            boolean cacheData = true;
            ExecutorService executorService = Executors.newFixedThreadPool(2);
            CountDownLatch countDownLatch = new CountDownLatch(3);
            final PathChildrenCache cache = new PathChildrenCache(client, path, cacheData, dataIsCompressed, executorService);
    
            /**
             * BUILD_INITIAL_CACHE 同步初始化客户端的cache,及创建cache后,就从服务器端拉入对应的数据(这个是NodeCache使用的方式)
             * NORMAL 异步初始化cache
             * POST_INITIALIZED_EVENT 异步初始化,初始化完成触发事件PathChildrenCacheEvent.Type.INITIALIZED
             */
            cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
            cache.getListenable().addListener(new PathChildrenCacheListener() {
                @Override
                public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                    ChildData currentData = pathChildrenCacheEvent.getData();
                    //事件类型,可通过判断事件类型来做相应的处理
                    PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
                    switch (type) {
                        //初始化会触发这个事件
                        case INITIALIZED:
                            logger.info("子类缓存系统初始化完成");
                            break;
                        case CHILD_ADDED:
                            //新增子节点/user/username
                            logger.info("新增子节点{}", currentData.getPath());
                            break;
                        case CHILD_UPDATED:
                            // 子节点数据变更[106, 97, 110, 110, 97, 108]
                            logger.info("子节点数据变更{}", new String(currentData.getData(),Charsets.UTF_8));
                            break;
                        case CHILD_REMOVED:
                            //子节点数据删除/user/username
                            logger.info("子节点数据删除{}", currentData.getPath());
                            break;
                    }
                    countDownLatch.countDown();
                }
    
    
            });
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath(path+"/username", "jannal123".getBytes(Charsets.UTF_8));
            TimeUnit.SECONDS.sleep(1);
            client.setData().forPath(path+"/username", "jannal".getBytes(Charsets.UTF_8));
            TimeUnit.SECONDS.sleep(1);
            client.delete().deletingChildrenIfNeeded().forPath(path);
            countDownLatch.await();
        }
    
    
  5. TreeCache可以监听整个树上的所有节点。即可以监控节点的状态,还监控节点的子节点的状态

        @Test
        public void testTreeCache() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "jannal-tree-listener";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            String path = "/user";
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath(path, "jannal123".getBytes(Charsets.UTF_8));
    
            CountDownLatch countDownLatch = new CountDownLatch(1);
            TreeCache cache = new TreeCache(client, path);
            cache.getListenable().addListener(new TreeCacheListener() {
                @Override
                public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                    TreeCacheEvent.Type type = treeCacheEvent.getType();
                    ChildData childData = treeCacheEvent.getData();
    
                    switch (type) {
                        //子类缓存系统初始化完成
                        case INITIALIZED:
                            logger.info("子类缓存系统初始化完成");
                            break;
                        case NODE_ADDED:
                            //新增子节点/user/username
                            logger.info("新增子节点{}", childData != null ? childData.getPath() : null);
                            break;
                        case NODE_UPDATED:
                            // 子节点数据变更jannal
                            // 子节点数据变更jannal2
                            logger.info("子节点数据变更{}", childData != null ? new String(childData.getData(), Charsets.UTF_8) : null);
                            break;
                        case NODE_REMOVED:
                            //子节点数据删除/user
                            logger.info("子节点数据删除{}", childData != null ? childData.getPath() : null);
                            break;
                    }
                    countDownLatch.countDown();
                }
            });
            cache.start();
            client.setData().forPath(path, "jannal".getBytes());
            Thread.sleep(1000);
            client.setData().forPath(path, "jannal2".getBytes());
            Thread.sleep(1000);
            client.delete().deletingChildrenIfNeeded().forPath(path);
            Thread.sleep(1000 * 2);
            countDownLatch.await();
    
        }
    

其他工具类

  1. Curator提供了一些工具类。比如ZKPathsEnsurePath

  2. ZKPaths提供更简单的API来构建Znode路径、递归创建和删除节点。

  3. EnsurePath提供了一种确保数据节点存在的机制。在分布式环境下,A和B机器都同时创建节点,由于并发操作的存在,可能抛出节点已经存在的异常EnsurePath内部实现就是试图创建指定节点,如果节点存在,那么就不进行任何操作,也不抛出异常,否则正常创建节点。从Curator 2.9.0版本开始此类已经过时,首选 CuratorFramework.create().creatingParentContainersIfNeeded() or CuratorFramework.exists().creatingParentContainersIfNeeded()

  4. 代码示例

        @Test
        public void testOther() throws Exception {
            String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";
            int sessionTimeoutMs = 25000;
            int connectionTimeoutMs = 5000;
            String rootPath = "zk-other";
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .sessionTimeoutMs(sessionTimeoutMs)
                    .connectionTimeoutMs(connectionTimeoutMs)
                    .retryPolicy(retryPolicy)
                    .namespace(rootPath)
                    .build();
            client.start();
            String path = ZKPaths.fixForNamespace(rootPath, "/user");
            // 输出:/zk-other/user
            logger.info(path);
            ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode("/zk-other/user/username");
            // path:/zk-other/user,node:username
            logger.info("path:{},node:{}", pathAndNode.getPath(), pathAndNode.getNode());
    
            CuratorZookeeperClient zookeeperClient = client.getZookeeperClient();
            //创建节点
            ZKPaths.mkdirs(zookeeperClient.getZooKeeper(), "/zk-other/user/password");
    
            //获取子节点
            List<String> sortedChildren = ZKPaths.getSortedChildren(zookeeperClient.getZooKeeper(), "/zk-other");
            logger.info(sortedChildren.toString());
    
    
    
    
        }
    

开发测试

  1. 为了便于开发人员进行zk的开发与测试,可以使用curator-test模块。依赖compile "org.apache.curator:curator-test:2.11.0"

  2. 单元测试

    
        @Test
        public void testSingleServer() throws Exception {
            File dataDir = new File(".");
            TestingServer server = new TestingServer(2000, dataDir);
            server.start();
            CuratorFramework curatorFramework = CuratorFrameworkFactory.
                    builder().
                    connectString(server.getConnectString()).
                    sessionTimeoutMs(1000).
                    retryPolicy(new RetryNTimes(3, 1000)).
                    build();
            curatorFramework.start();
            System.out.println(curatorFramework.getChildren().forPath("/"));
            curatorFramework.close();
            server.stop();
    
        }
    
  3. 集群测试

        @Test
        public void testClusterServer() throws Exception {
            TestingCluster server = new TestingCluster(3);
            server.start();
            Thread.sleep(2000);
            TestingZooKeeperServer leader = null;
            for (TestingZooKeeperServer zs : server.getServers()) {
                logger.info(zs.getInstanceSpec().getServerId() + "-");
                logger.info(zs.getQuorumPeer().getServerState() + "-");
                logger.info(zs.getInstanceSpec().getDataDirectory().getAbsolutePath());
                if (zs.getQuorumPeer().getServerState().equals("leading")) {
                    leader = zs;
                }
            }
            //模拟leader挂掉
            leader.kill();
            logger.info("leader 挂掉之后");
            for (TestingZooKeeperServer zs : server.getServers()) {
                logger.info(zs.getInstanceSpec().getServerId() + "-");
                logger.info(zs.getQuorumPeer().getServerState() + "-");
                logger.info(zs.getInstanceSpec().getDataDirectory().getAbsolutePath());
    
            }
            server.stop();
    
        }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值