api 创建zookeeper客户端_你还在使用复杂的 zkclient 开发 zookeeper 么?是时候用 Curator 了 !...

a292ab1b24e0f491385584ce790ef002.png

什么是 Curator

Curator是netflix公司开源的一套zookeeper客户端,目前是Apache的顶级项目。与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量。Curator解决了很多zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册watcher和NodeExistsException 异常等,对于我们日常 ZooKeeper 服务开发进行了详细的封装,例如 Leader 选举、分布式计数器、分布式锁。这就减少了技术人员在使用 ZooKeeper 时的大部分底层细节开发工作。

下面我们常用的绘画创建以及节点的管理,一起来看看如何去使用 Curator 去代替原生的 ZooKeeper 开发。

引入依赖

Curator 主要又两个关键包,curator-framework 包和 curator-recipes 包。

  • curator-framework,该包是对 ZooKeeper 底层 API 的一些封装,基础功能 API 均在这个包下;
  • curator-recipes,该包封装了一些 ZooKeeper 服务的高级特性,如:Cache 事件监听、选举、分布式锁、分布式 Barrier。
<dependency>
 <groupId>org.apache.curator</groupId>
 <artifactId>curator-framework</artifactId>
 <version>2.12.0</version>
</dependency>
<dependency>
 <groupId>org.apache.curator</groupId>
 <artifactId>curator-recipes</artifactId>
 <version>2.12.0</version>
</dependency>

通过上面 Maven 引入依赖之后,我们就具备了使用 Curator 去操作 zookeeper 的能力。Curator 框架提供了的 API 是相当于流式的编码风格,主要是按照逻辑的先后顺序,采用调用的方式,在代码方式以及逻辑上更清晰一些。

下面,我们先来感受下这种编码风格,例如,我们要在 zookeeper 服务中创建一个 “/test/path” 的节点,然后,节点内容为 testData ,使用 Curator 框架编码如下:

client.create().forPath(“/test/path”, testData)

创建会话

通过上面,我们已经引入了 Curator 框架,并且已经知道了其编码风格,接下来,我们来看看该如何使用 Curator 去创建一个会话。

在这之前,我们先来复习下,使用zookeeper 原生客户端如何去创建会话:

try {
            zk = new ZooKeeper(zkServers, Constants.SESSION_TIMEOUT,this);
            logger.info(">>> connect to zookeeper,zkServers:" + zkServers);
            latch.await();
        } catch (Exception e) {
            e.printStackTrace();        }

使用 Curator 来创建会话:

RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);
CuratorFramework client = CuratorFrameworkFactory.builder()                .connectString(zkServers) //zk 服务地址
                .sessionTimeoutMs(5000)  // 会话超时时间
                .connectionTimeoutMs(5000) // 连接超时时间
                .retryPolicy(retryPolicy)
                .namespace("base") // 包含隔离名称
                .build();
client.start();

在定义 CuratorFramework 对象实例的时候,我们使用了 CuratorFrameworkFactory 工厂方法,下面我们来看下其关键信息:

  • connectString,zookeeper 服务地址列表,如果是多个地址则用逗号分隔,如:192.168.1.1:2181,192.168.1.2:2181 ;
  • retryPolicy,重试策略,当客户端发生异常退出或者与服务端失去连接的时候,可以通过设置客户端重新连接 zookeeper 服务端;
  • sessionTimeoutMs,会话超时时间,作用在服务端,用来设置该条会话在 zookeeper 服务端的失效时间;
  • connectionTimeoutMs,客户端连接超时时间,作用在客户端,用来限制客户端发起一个会话连接到接收 zookeeper服务端应答的时间。

现在,我们已经完成了客户端与服务端会话的建立,即证明两端具备了通信的能力下面,我们就再来看看使用 Curator 框架该如何去创建、删除以及更新节点等。

创建节点

我们知道在创建节点的时候,是需要描叙该节点是临时节点、持久节点等节点相关数据信息,使用 Curator 创建节点代码如下:

client.create().withMode(CreateMode.EPHEMERAL).forPath("path","data".getBytes());
  • 通过 create 函数创建数据节点
  • 通过 withMode 函数指定节点类型,是临时节点还是持久节点
  • 通过 forPath 函数指定节点路径以及所存放的数据

更新节点

接下来,我们再来看看节点更新代码该如何去编写:

client.setData().forPath("path","data_update".getBytes());
  • 更新节点是使用 setData 方法
  • 然后通过 forPath 函数指定所需要更新的路径以及要更新的数据信息

删除节点

上面我们已经知道了如何去创建会话、创建节点以及更新节点,下面,我们再来看看使用 Curator 如何去删除节点,代码如下:

client.delete().guaranteed().deletingChildrenIfNeeded().withVersion(10086).forPath("path");
  • 删除节点是通过 delete 函数来操作的;
  • guaranteed,主要是为了保障成功删除的,只要可河段会话有效,就会在后台持续发起删除请求,知道节点被成功删除;
  • deletingChildrenIfNeeded,递归删除节点以及子节点;
  • withVersion,指定删除节点的版本;
  • forPath,指定删除节点的位置

高级特性

我们在开发 zookeeper 服务的时候,经常会遇到这种情况,如果我们注册的节点异常断开或者是遇到其他网络问题导致的连接不可用,那这个时候我们怎么能立即感应呢?

在 Curator 中是通过 ConnectionStateListener 这个监听器去实现的,它主要是用来监控会话的连接状态,当状态发生改变的时候, zookeeper 服务就会启用不同的处理方式,其会话一共有六种基本状态:

  • CONNECTED,已连接,当客户端发起的会话成功连接到服务端后,该条会话的状态变为 CONNECTED 已连接状态;
  • SUSPENDED,会话连接挂起,当进行 Leader 选举和 lock 锁等操作时,需要先挂起客户端的连接。注意这里的会话挂起并不等于关闭会话,也不会触发诸如删除临时节点等操作;
  • RECONNECTED,重连,当已经与服务端成功连接的客户端断开后,尝试再次连接服务端后,该条会话的状态为 RECONNECTED,也就是重新连接;
  • LOST,会话丢失,客户端与服务器端因为异常或超时,导致会话关闭时,该条会话的状态就变为 LOST;
  • READONLY,只读,一个客户端会话调用 CuratorFrameworkFactory.Builder.canBeReadOnly() 的时候,该会话会一直处于只读模式,直到重新设置该条会话的状态类型。

接下来,我们来看看代码如何落地:

public class zkConnectionStateListener implements ConnectionStateListener {
        private String zkRegPathPrefix;
        private String regContent;
        public zkConnectionStateListener(String zkRegPathPrefix, String regContent) {
            this.zkRegPathPrefix = zkRegPathPrefix;
            this.regContent = regContent;
        }        @Override
        public void stateChanged(CuratorFramework client, ConnectionState newState) {
            if (newState == ConnectionState.LOST) {
                logger.info("zk client: {} disConnected...",regContent);
                while (true) {
                    try {
                        if (client.getZookeeperClient().blockUntilConnectedOrTimedOut()) {
                            client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)                                    .forPath(zkRegPathPrefix, regContent.getBytes("UTF-8"));
                            break;
                        }                    } catch (InterruptedException e) {
                        logger.error(">> [zkConnectionStateListener]-stateChanged InterruptedException,msg= {}", e);
                        break;
                    } catch (Exception e) {
                        logger.error(">> [zkConnectionStateListener]-stateChanged exception,msg= {}", e);
                    }                }            }        }    }

往期热门文章:

1,架构的本质:如何打造一个有序的系统?

2,分布式高可靠之负载均衡,今天看了你肯定会

3,分布式数据之缓存技术,一起来揭开其神秘面纱
4,分布式数据复制技术,今天就教你真正分身术

5,数据分布方式之哈希与一致性哈希,我就是个神算子

6 ,分布式存储系统三要素,掌握这些就离成功不远了

7 ,想要设计一个好的分布式系统,必须搞定这个理论

8 ,分布式通信技术之发布订阅,干货满满
9,分布式通信技术之远程调用:RPC

10 ,秒杀系统每秒上万次下单请求,我们该怎么去设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值