暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

zookeeper系列-客户端的骚操作& Curator使用

QB木丘白 2021-06-21
3609





低头凝望镜中月

不如关注木丘白

一步两步向前走

共同学习一起来



前言


       这段时间事比较多,十一还回了趟老家,回顾一下上一篇简单讲了zookeeper的简介以及安装,当然关于zookeeper还有好多你不知道的事,后面打算再写一篇番外篇,属于扩展了解内容。本编主要讲一下zookeeper客户端的操作,以及Curator框架的使用。


zkCli


上篇安装完成之后简单介绍了一下客户端的操作,那就书接上回吧。

登录客户端操作
./zkCli.sh -server localhost:2181
查看节点信息
ls
随便创建一个节点
create -e test hello
登录其他服务节点查看是否同步
get test

NO.1


创建临时节点
create -e tmp hello
创建顺序节点
create -s gogo hello
顺序节点会在后面加上一个10位的编号,0000000001这种,顺序递增
不添加-e或者-s参数时,默认是持久节点


NO.1


删除节点
delete tmp
如果删除的节点下面还有子节点,则无法删除,会提示Node not empty


NO.1


修改节点
set tmp heihei


NO.1


查询可以使用ls命令和get命令
查看节点下有多少子节点
ls
查看某个节点的value值
get tmp


这里这是简单的介绍了一下zkCli客户端的基本操作,下面讲解一下Java中API的使用。


Curator


Java操作zk,这里要提到非常强大的框架
CuratorFramework,这个框架已经被收录在Apache当中,提供了非常丰富的操作,超时重连,分布式锁,分布式计数器等等。

使用curator需要注意与zk的版本对应,目前curator的最新大版本为5.0版本,不再支持zookeeper 3.4.x版本,因为zk的3.4.x版本已经停产,如果您希望将Curator与ZooKeeper 3.4.x一起使用,则应固定到Curator的4.2.x版本。Curator 4.2.x在软兼容模式下支持ZooKeeper 3.4.x集成。要使用此模式,在将Curator添加到依赖管理工具时,必须排除ZooKeeper。

maven
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>


gradle
compile('org.apache.curator:curator-recipes:$curatorVersion')
{
exclude group: 'org.apache.zookeeper', module: 'zookeeper'
}

本篇以zk 3.6.2版本与curator 5.1.0版本结合使用,不涉及上面说的兼容问题哦。

首先我们来了解一下zookeeper的节点类型CreateMode,以3.6.2为例,这个是zookeeper的官方文档https://zookeeper.apache.org/doc/r3.6.2/apidocs/zookeeper-server/index.html

3.6版本后有7种节点类型

类型描述
CONTAINERznode将是一个容器节点。容器节点是对方法有用的特殊用途节点,如leader、lock等。当容器的最后一个子节点被删除时,容器将成为服务器在将来某个时候删除的候选节点。考虑到这个属性,当在此类节点下创建子节点时,可能返回KeeNonException.KeeNonException
EPHEMERAL临时节点,当客户端断开连接时,znode将被删除
EPHEMERAL_SEQUENTIAL临时序列节点,当客户端断开连接时,znode将被删除,其名称将附加一个递增的数字
PERSISTENT持久化节点,客户端断开连接时,znode不会自动删除
PERSISTENT_SEQUENTIAL持久化序列节点,客户端断开连接时,znode不会自动删除,它的节点名称会附加一个递增的数字
PERSISTENT_SEQUENTIAL_WITH_TTL持久化序列节点,客户端断开连接时,znode不会自动删除,它的节点名称会附加一个递增的数字,如果znode没有在给定的TTL(生命周期)中被修改,那么一旦它没有子对象,它就会被删除
PERSISTENT_WITH_TTL持久化节点,客户端断开连接时,znode不会自动删除,如果znode没有在给定的TTL(生命周期)中被修改,那么一旦它没有子对象,它就会被删除


了解了zk的节点类型后,接下来开始上代码喽

①这里使用的springboot,首先导入需要的依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.0.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>2.1.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.1.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>compile</scope>
</dependency>

②新建一个zk的配置类

/**
* zk配置信息
* @author QB
* @date 2020-10-09 15:26
*/

@Data
@ConfigurationProperties(prefix = "zk")
public class ZkProps {
/**
* 连接地址
*/

private String url;

/**
* 超时时间(毫秒),默认1000
*/

private int timeout = 1000;

/**
* 重试次数,默认3
*/

private int retry = 3;
}

③初始化配置

/**
* zk配置
* @author QB
* @date 2020-10-09 15:44
*/

@Configuration
@EnableConfigurationProperties(ZkProps.class)
public class ZkConfig
{

private final ZkProps zkProps;

@Autowired
public ZkConfig(ZkProps zkProps) {
this.zkProps = zkProps;
}

@Bean
public CuratorFramework curatorFramework() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(zkProps.getTimeout(), zkProps.getRetry());
CuratorFramework client = CuratorFrameworkFactory.newClient(zkProps.getUrl(), retryPolicy);
client.start();
return client;
}
}

④springboot启动类

/**
* 启动类
* @author QB
* @date 2020-10-09 15:56
*/

@SpringBootApplication
public class SpringBootZookeeperDemoApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootZookeeperDemoApplication.class, args);
}

}


测试一波


package com.qbnever.zookeeper;

import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.UnsupportedEncodingException;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ZookeeperClientTest
{

@Autowired
CuratorFramework curator;

/**
* 添加节点
* @throws Exception
*/

@Test
public void addNode() throws Exception {

//不指定节点类型,默认是持久化节点PERSISTENT
curator.create().forPath("/test1");

//指定类型,创建一个临时节点,这里可以替换createMode创建不同类型的节点
curator.create().withMode(CreateMode.EPHEMERAL).forPath("/haha");
//创建节点同时赋值
curator.create().withMode(CreateMode.PERSISTENT).forPath("/hello", "你好".getBytes("UTF-8"));
//递归创建
curator.create().creatingParentContainersIfNeeded().forPath("/parent/child/child2");
}

/**
* 删除节点
*/

@Test
public void deleteNode() throws Exception {
//删除单个节点,如果存在子节点会报错 KeeperException$NotEmptyException
curator.delete().guaranteed().forPath("/haha");
//递归删除,同时删除所有子节点
curator.delete().deletingChildrenIfNeeded().forPath("/recursive");
}

/**
* 更新节点
*/

@Test
public void updateNode() throws Exception {
curator.setData().forPath("/haha", "哈哈".getBytes("UTF-8"));

}

/**
* 查询节点
*/

@Test
public void getNode() throws Exception {
//获取某个节点的值
byte[] bytes = curator.getData().forPath("/haha");
System.out.println(new String(bytes, "UTF-8"));

//获取节点下的一级子节点,不会递归获取
List<String> recursive = curator.getChildren().forPath("/recursive");
System.out.println(recursive);


}

/**
* 判断节点是否存在
*/

@Test
public void isExist() throws Exception {
Stat stat = curator.checkExists().forPath("/haha");

System.out.println(stat==null? "否" : "是");
}

}


好了,到这就结束了,快去试试吧,后面会分享分布式锁的实现哦,关注我,不迷路哈哈


在看~

捧个人场行~

文章转载自QB木丘白,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论