ZooKeeper 是一个开源的分布式协调框架,主要用来解决分布式集群中应用系统的一致性问题。
zookeeper官网https://zookeeper.apache.org/doc/current/index.html
目录
一、zookeeper的数据结构
二、下载zookeeper
三、windows上安装zookeeper
四、linux上安装zookeeper
五、启动zookeeper
六、使用zookeeper客户端
创建节点
临时节点
容器节点
限时节点
设置节点数据
获取节点数据
事件监听机制
删除节点
获取节点状态
七、zookeeper集群架构
八、通过Java连接zookeeper
使用zookeeper客户端
springboot整合zookeeper
一、zookeeper的数据结构
zookeeper的结构类似于文件系统,其中每一个目录叫做zookeeper的节点(znode),znode有以下几种类型:
- 持久化节点:节点不会被自动删除,会一直存在。
- 临时节点:一次会话结束后,临时节点会被删除。在创建节点的时候通过参数-e指定为临时节点。
- 顺序节点:一般情况下,节点名已经存在,是无法创建同名节点的,但是顺序节点允许同名,创建的同名节点会被按顺序编号。在创建节点的时候通过参数-s指定为顺序节点。
- 容器节点:容器节点是一种特殊的znode,当他下面的所有子节点都被删除时,该节点会被删除,每60秒会删除一次空的容器节点。在创建节点的时候通过参数-c指定为顺序节点。
二、下载zookeeper
首先,需要下载zookeeper,点击链接打开zookeeper官网Apache ZooKeeper,在官网首页点击Getting Started下面的Download进入下载页面
选择下载最新的稳定版本
然后点击任意链接开始下载zookeeperzook的de压缩包
如果下载很慢,博主提前下载好了之前的很多个稳定版本
百度网盘zookeeper下载链接https://pan.baidu.com/s/1EU8UEi_MYLm6v8xIk1-BRw?pwd=gawp
三、windows上安装zookeeper
下载完成后,解压到D盘,然后打开刚刚解压的zookeeper安装目录下的config目录,复制一份zoo_sample.cfg,然后重命名为zoo.cfg,修改里面的内容,dataLogDir是新增的,原来文件里没有
dataDir:zookeeper的安装目录\\data
dataLogDir:zookeeper的安装目录\\log
tickTime=2000
initLimit=10
syncLimit=5
clientPort=2181
dataDir=D:\\program\\apache-zookeeper-3.8.3-bin\\data
dataLogDir=D:\\program\\apache-zookeeper-3.8.3-bin\\log
然后在zookeeper的安装目录下新建两个目录data和log
经过以上的步骤,zookeeper就算安装完了。
启动zookeeper:双击zookeeper安装目录下的bin目录下的zkServer.bat
使用zookeeper:使用zookeeper的客户端,只需要双击zkCli.bat即可
四、linux上安装zookeeper
文章使用linux版本为Ubuntu-22.04.3,通过finalshell上传刚刚下载的压缩包到服务器,并解压。
比如上传到/usr目录下,通过以下命令解压
tar -zvxf apache-zookeeper-3.8.3-bin.tar.gz
然后进入zookeeper安装目录下的conf目录,复制一份zoo_example.cfg,建议文件名为zoo.cfg,因为启动zk服务器的时候默认通过zoo.cfg配置文件启动,不需要指定配置文件名。
cd apache-zookeeper-3.8.3-bin/
cp conf/zoo_sample.cfg conf/zoo.cfg
修改zoo.cfg的dataDir
dataDir=/usr/local/zookeeper
然后添加以下配置
# 默认是8080,因为8080可能被web应用使用,Springboot项目中tomcat的默认启动端口就是8080
admin.serverPort=9099
# 添加这个配置才能使用create -t ttl /node_name
extendedTypesEnabled=true
五、启动zookeeper
切换到zookeeper安装目录,通过以下命令之一启动zookeeper服务器
bin/zkServer.sh start
如果配置文件名不是zoo.cfg,需要指定配置文件名
bin/zkServer.sh start conf/配置文件名.cfg
输入bin/zkServer.sh会提示后面还可以带很多个命令
常用的几个命令
bin/zkServer.sh stop # 停止zookeeper
bin/zkServer.sh start # 启动zookeeper
bin/zkServer.sh status # 查看zookeeper状态
bin/zkServer.sh restart # 重启zookeeper
bin/zkServer.sh start-foreground # 在前台启动zookeeper
六、使用zookeeper客户端
要使用zk客户端的命令之前,需要通过以下命令启动zookeeper的客户端
bin/zkCli.sh
然后通过help命令查看zookeeper有哪些命令
创建节点
可以通过zk客户端提供的的create命令创建znode。
create /test
可以看到这个命令后面可以带很多个参数,当不带任何参数时,该节点默认为持久化节点。
接下来介绍这些参数的作用:
命令参数 | 作用 |
-s | 指定节点类型为顺序节点 |
-e | 指定节点类型为临时节点 |
-c | 指定节点类型为容器节点 |
-t | 指定节点的过期时间,使用该参数创建节点时,检查一下配置文件是否加了以下配置:extendedTypesEnabled=true |
临时节点
演示创建临时节点效果,依次在终端输入以下命令
create -e /test
get /test
quit
然后重新连接客户端,再次获取/test节点的内容,提示节点不存在。
get /test
这时候通过get命令获取节点的数据,提示节点test不存在,是因为临时节点只在本次会话中有效,主动断开连接之后临时节点会被删除。
容器节点
create -c /node_name
创建一个容器节点,并创建其子节点
create -c /container
create /container/test
然后删除容器节点的唯一一个子节点
delete /container/test
然后等大概60秒,再次获取的时候,发现节点已经别自动删除了
限时节点
create -t 30 /test
注意,这里的节点并不会到了指定时间就删除,可能和znode过期删除策略有关。
设置节点数据
set [-s] [-v version] /node_name data
-s修改该节点,并查看节点的状态,相当于以下两个命令的组合
set /test abc
get -s /test
-v指定版本号,只有当前数据的版本号和指定版本一样才会修改成功
比如接着上面的命令,再修改一次/test,让它的版本号dataVersion变成2,然后再次修改时通过-v指定版本号为1,此时会提示该版本号不存在,版本号机制是CAS操作中为了避免ABA问题而设置的。
获取节点数据
get [-s] [-w] /node_name
参数说明:
可选参数-s表示查看节点状态信息;
可选参数-w表示给节点添加一个监听器,这个监听器只会生效一次。
事件监听机制
通过命令中指定的参数-w可以为创建/指定的节点添加一个监听器,监听节点的增删改操作,监听一次后将会移除该监听器。
通过addWatch命令可以给节点添加一个永久的监听器
addWatch [-m mode] /node_name
mode表示监听的模式,有两种取值:
PERSISTENT:监听该节点的变化,以及子节点的增删,不能监听到子节点数据的修改;
PERSISTENT_RECURSIVE:(默认)监听该节点和其子节点的变化,包括子节点数据的变化;
删除节点
delete:可以指定版本号删除
delete -v version /node_name
deleteall:递归删除当前节点和它的所有子节点
deleteall /node_name
获取节点状态
stat [-w] /node_name
该命令返回的几个字段及其含义:
字段 | 说明 |
cZxid |
znode创建的事务id
|
ctime |
节点创建时的时间戳
|
mZxid |
znode被修改的事务id,每次对znode的修改都会更新mZxid
|
pZxid |
表示该节点的子节点列表最后一次修改的事务ID,添加子节点或删除子节点就会影响子节点列表,
修改子节点的数据内容则不影响该ID
|
mtime | 节点最后一次修改时的时间戳 |
cversion |
子节点的版本号,当znode的子节点有变化时,cversion 的值就会增加1。
|
dataVersion |
数据版本号,每次对节点进行set操作,dataVersion的值都会增加1
|
ephemeralOwner |
如果该节点为临时节点, ephemeralOwner值表示与该节点绑定的session id。如果不是,
ephemeralOwner值为0(持久节点)。
|
dataLength |
节点数据的长度
|
numChildren |
节点的直接子节点的数量
|
七、zookeeper集群架构
事务:对于create、setData、delete等有写操作的请求,则要统一转发给leader处理,leader需要决定编号、执行操作,这个过程称为事务。
zookeeper集群的几种角色:leader、follower、observer
- leader:处理读写请求,保证集群事务处理的顺序性;
- follower:只处理读请求,读请求会转发给Leader,参与集群Leader选举投票;
- observer:只处理读请求,读请求会转发给Leader,不会参与集群Leader选举;
八、通过Java连接zookeeper
使用zookeeper客户端
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author heyunlin
* @version 1.0
*/
public class ZookeeperExample {
public static void main(String[] args) {
try {
ZooKeeper zooKeeper = new ZooKeeper("localhost:2181", 5000, new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println(event);
}
});
String node = "/test";
// 获取节点信息
Stat stat = zooKeeper.exists(node, true);
// 如果节点不存在,则创建
if (stat == null) {
zooKeeper.create(node, "123".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// 重新获取节点信息
stat = zooKeeper.exists(node, true);
// 获取节点的dataVersion
int version = stat.getVersion();
// 获取节点数据
byte[] data = zooKeeper.getData(node, true, null);
System.out.println(new String(data));
// 设置节点数据
zooKeeper.setData(node, "789".getBytes(StandardCharsets.UTF_8), version);
data = zooKeeper.getData(node, true, null);
System.out.println(new String(data));
} catch (IOException | KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
}
springboot整合zookeeper
1、在IntelliJ IDEA里新建一个springboot项目,命名为zookeeper
2、在项目的pom.xml文件中引入zookeeper和相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.9</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>zookeeper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、修改application.xml配置文件,只需要指定项目启动端口号和zookeeper的服务器地址
server:
port: 8085
zookeeper:
host: localhost:2181
4、项目根目录下创建config包,新建一个zookeeper的配置类
package com.example.zookeeper.config;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author heyunlin
* @version 1.0
*/
@Configuration
public class ZookeeperConfig {
@Value("${zookeeper.host}")
private String host;
@Bean
public CuratorFramework curatorFramework() {
CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
.connectString(host)
.sessionTimeoutMs(5000)
.retryPolicy(new ExponentialBackoffRetry(500, 5))
.build();
curatorFramework.start();
return curatorFramework;
}
}
5、使用zookeeper的API文章来源:https://www.toymoban.com/news/detail-569897.html
package com.example.zookeeper.controller;
import com.example.zookeeper.restful.JsonResult;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* @author heyunlin
* @version 1.0
*/
@RestController
@RequestMapping(path = "/zookeeper", produces = "application/json;charset=utf-8")
public class ZookeeperController {
private final CuratorFramework curatorFramework;
@Autowired
public ZookeeperController(CuratorFramework curatorFramework) {
this.curatorFramework = curatorFramework;
}
/**
* 判断znode是否存在
* @param node 节点名称
*/
@RequestMapping(value = "/exist", method = RequestMethod.GET)
public JsonResult<Stat> exist(String node) throws Exception {
Stat stat = curatorFramework.checkExists().forPath(node);
return JsonResult.success(null, stat);
}
/**
* 创建一个znode
* @param node 节点名称
*/
@RequestMapping(value = "/create", method = RequestMethod.GET)
public JsonResult<Void> create(String node) throws Exception {
curatorFramework.create()
.creatingParentContainersIfNeeded()
/*
创建模式:常用的有
PERSISTENT:持久化节点,客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除,该节点就会永远存在。
PERSISTENT_SEQUENTIAL:持久化顺序编号目录节点,客户端与zookeeper断开连接后,该节点依旧存在,只是zookeeper给该节点名称进行顺序编号。
EPHEMERAL:临时目录节点,客户端与zookeeper断开连接后,该节点被删除。
EPHEMERAL_SEQUENTIAL:临时顺序编号目录节点,客户端与zookeeper断开连接后,该节点被删除,只是zookeeper给该节点名称进行顺序编号。
*/
.withMode(CreateMode.EPHEMERAL)
.forPath(node);
return JsonResult.success("创建成功");
}
/**
* 设置znode节点的数据
* @param node 节点名称
* @param data 节点的数据
*/
@RequestMapping(value = "/setData", method = RequestMethod.GET)
public JsonResult<Void> setData(String node, String data) throws Exception {
curatorFramework.setData().forPath(node, data.getBytes(StandardCharsets.UTF_8));
return JsonResult.success("设置成功");
}
/**
* 删除节点
* @param node 节点名称
*/
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public JsonResult<Void> delete(String node) throws Exception {
curatorFramework.delete().forPath(node);
return JsonResult.success("删除成功");
}
/**
* 删除节点及其子节点的数据
* @param node 节点名称
*/
@RequestMapping(value = "/deleteDeeply", method = RequestMethod.GET)
public JsonResult<Void> deleteDeeply(String node) throws Exception {
curatorFramework.delete().deletingChildrenIfNeeded().forPath(node);
return JsonResult.success("删除成功");
}
/**
* 获取节点的数据
* @param node 节点名称
*/
@RequestMapping(value = "/getData", method = RequestMethod.GET)
public JsonResult<String> getData(String node) throws Exception {
byte[] bytes = curatorFramework.getData().forPath(node);
return JsonResult.success(null, new String(bytes));
}
/**
* 获取当前节点的子节点数据
* @param node 节点名称
*/
@RequestMapping(value = "/getChildren", method = RequestMethod.GET)
public JsonResult<List<String>> getChildren(String node) throws Exception {
List<String> list = curatorFramework.getChildren().forPath(node);
return JsonResult.success(null, list);
}
}
好了,文章就分享到这里了~文章来源地址https://www.toymoban.com/news/detail-569897.html
到了这里,关于SpringBoot整合ZooKeeper完整教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!