低头凝望镜中月
不如关注木丘白
一步两步向前走
共同学习一起来
前言
这段时间事比较多,十一还回了趟老家,回顾一下上一篇简单讲了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
org.apache.curatorcurator-recipes4.2.0org.apache.zookeeperzookeeper
gradlecompile('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种节点类型
类型 | 描述 |
CONTAINER | znode将是一个容器节点。容器节点是对方法有用的特殊用途节点,如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,首先导入需要的依赖
org.springframework.bootspring-boot-starter-web2.1.0.RELEASEsnakeyamlorg.yaml
org.springframework.bootspring-boot-configuration-processortrue2.1.0.RELEASE
org.springframework.bootspring-boot-starter-aop2.1.0.RELEASE
org.yamlsnakeyaml1.26
org.apache.curatorcurator-recipes5.1.0slf4j-apiorg.slf4j
org.springframework.bootspring-boot2.1.0.RELEASEcompile
org.springframework.bootspring-boot-autoconfigure2.1.0.RELEASEcompile
junitjunit4.12test
org.springframeworkspring-test5.1.2.RELEASEtest
org.springframework.bootspring-boot-test2.1.0.RELEASEtest
org.projectlomboklombok1.18.12compile
org.projectlomboklombok1.18.12compile
②新建一个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)
@SpringBootTestpublic 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 recursive = curator.getChildren().forPath("/recursive");
System.out.println(recursive);
}/**
* 判断节点是否存在
*/@Testpublic void isExist() throws Exception {
Stat stat = curator.checkExists().forPath("/haha");
System.out.println(stat==null? "否" : "是");
}
}
好了,到这就结束了,快去试试吧,后面会分享分布式锁的实现哦,关注我,不迷路哈哈
![dd689f9a8ddb65639d9990f2040eac84.png](https://img-blog.csdnimg.cn/img_convert/dd689f9a8ddb65639d9990f2040eac84.png)
点在看~
![9f801eecae60c09cf89fa9c358e45ad7.gif](https://img-blog.csdnimg.cn/img_convert/9f801eecae60c09cf89fa9c358e45ad7.gif)
捧个人场就行~