zookeeper基本使用与集群搭建

1. ZK简介

​ 一个分布式的,开放源码的分布式应用程序协调服务。

2. ZK数据模型

2.1 模型结构

image-20220115193533781

2.2 模型的特点

  • 每个子目录如/node1都被称作一个znode(节点)。这个znode是它所在的路径唯一标识
  • znode可以有子节点目录,并且每个znode可以存储数据
  • znode是有有版本的,每个znode中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据
  • znode是可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端

3. 节点的分类

3.1 持久节点(PERSISTENT)

​ 指在节点创建后,就一直存在,知道有删除操作来主动删除这个节点–会因为创建该节点的客户端会话失效而消失

3.2 持久顺序节点(PERSISTENT_SEQUENTIAL)

​ 这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。

3.3 临时节点(EPHEMERAL)

​ 和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。

3.4 临时顺序节点(EPHEMERAL_SEQUENTIAL)

​ 具有临时节点特点额外的特性是,每个父节点会为他的第一级子节点维护一份时序。这点和刚才提到的持久顺序节点类似

4. 安装

4.1 linux系统安装

  • 安装JDK
1
2
tar -zxvf jdk-8u171-linux-x64.tar.gz 
mv ./jdk1.8.0_171/ /usr/java/
1
2
vim /etc/profile
source /etc/profile

image-20220115200800125

  • 安装ZK
1
tar -zxvf apache-zookeeper-3.6.3-bin.tar.gz

image-20220115201522943

1
cd conf/

image-20220115201545453

由于zk默认加载的是zoo.cfg,所以需要改名

1
mv zoo_sample.cfg zoo.cfg

image-20220115201752620

由于zookeeper加载要将节点加载到磁盘,所以需要预先新建一个磁盘目录

1
mkdir /tmp/zookeeper
  • 启动ZK

image-20220115201952338

1
2
3
4
5
6
7
[root@localhost bin]# ./zkServer.sh start /root/apache-zookeeper-3.6.3-bin/conf/zoo.cfg 
ZooKeeper JMX enabled by default
Using config: /root/apache-zookeeper-3.6.3-bin/conf/zoo.cfg
Starting zookeeper ... STARTED

# 查看是否启动
jps

image-20220115202134008

​ QuorumPeerMain就是zk

  • 连接ZK
1
./zkCli.sh -server 192.168.9.3:2181

如果是本机,-server后可不加

5. 配置文件说明

image-20220115202623979

  • tickTime:集群节点心跳时间,
  • initLimit:初始化集群时集群节点同步超时时间20s
  • syncLimit:集群在运行过程中,同步数据超时时间为10s(这里5是指5次心跳)
  • dataDir:默认数据存储位置
  • clientPort:zk服务监听端口号
  • maxClientCnxns:线程池线程数量

6. 客户端基本指令

  • 查看节点
1
ls / # 根节点

image-20220115203707976

  • 创建节点
1
2
3
4
5
create path data # 创建一个节点,并给节点绑定数据(默认是持久性节点)
- create path data # 持久节点
- create -s path data # 持久性顺序节点
- create -e path data # 临时性节点
- create -e -s path data # 临时顺序节点

image-20220115204244695

quit:会直接导致会话断开,会话失效,其他ctrl+c会导致触发倒计时

注:临时节点上不能创建任何节点

  • 查看节点状态
1
stat /node1

image-20220115204735555

cZxid:创建事务ID

ctime:创建时间

mZxid:修改ID

mtime:修改时间

pZxid:父结点版本号

cversion:创建版本号

dataVersion:数据版本号

aclVersion

ephemerslOwner:是否是临时节点

dataLength:存储数据长度

numChildren:子节点数量

  • 获得节点上绑定的数据信息
1
get /node1

image-20220115205118959

  • 删除节点
1
delete /node1

image-20220115205520902

只能删除没有子节点的节点,如果有子节点,则无法删除

若想删除有子节点的,则需要deleteall

image-20220115205748540

7. watch节点监听机制

监听分为节点目录监听节点数据监听

  • 目录监听是监听节点目录的变化
  • 数据监听是监听当前节点数据的变化

两种监听都是一次性的,也就是发现一个修改,下次修改则不会触发监听机制

  • 目录监听
1
ls -w /node

image-20220115210841507

image-20220115210831701

再次创建,无触发

image-20220115210951358

image-20220115210958554

  • 数据监听
1
get -w /node 

image-20220115211117526

image-20220115211125730

8. Java操作ZK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package com.w1nd.test;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class TestZKClient {

private ZkClient zkClient;

// 1. 在zk创建节点
@Test
public void testCreateNode() {
// 1. 持久节点
zkClient.create("/node1", "xiaochen", CreateMode.PERSISTENT);
// 2. 持久顺序节点
zkClient.create("/node1/names", "zhangsan", CreateMode.PERSISTENT_SEQUENTIAL);
// 3. 临时节点
zkClient.create("/node1/lists", "xiaoxiao", CreateMode.EPHEMERAL);
// 4. 临时顺序节点
zkClient.create("/node1/lists1", "xiaoming", CreateMode.EPHEMERAL_SEQUENTIAL);

}

// 2. 删除节点
@Test
public void testDeleteNode() {
// 删除没有子节点的节点,返回值:是否成功
boolean delete = zkClient.delete("/node1");
// 递归删除节点信息,返回值:是否删除成功
boolean b = zkClient.deleteRecursive("/node1");
}

// 3. 查询当前节点下所有子节点
@Test
public void testFindNodes() {
// 获取指定路径的节点信息
List<String> children = zkClient.getChildren("/");
for (String child : children) {
System.out.println(child);
}
}

// 4. 查看某个节点数据,注意:通过java客户端操作需要保证节点存储的数据和节点时序列化方式一致
// shell中的数据序列化方式和java中的不一致
@Test
public void testFindNodeData() {
Object readData = zkClient.readData("/node3");
System.out.println(readData);
}

// 5. 查看节点状态信息
@Test
public void testFindNodeDataAndStat() {
Stat stat = new Stat();
Object readData = zkClient.readData("/node1", stat);
System.out.println(readData);
System.out.println(stat);
}

// 6. 修改节点数据
@Test
public void testWriteData() {
// User user = new User();
// user.setId(1);
// zkClient.writeData("/node1", user);
}

// 监听节点数据的变化
@Test
public void testOnNodeDataChange() throws IOException {
zkClient.subscribeDataChanges("/node1", new IZkDataListener() {
// 当节点数据变化时触发对应这个方法
@Override
public void handleDataChange(String s, Object o) throws Exception {
System.out.println("当前节点路径:" + s);
System.out.println("当前节点变化后数据:" + o);
}
// 当前节点删除时触发这个方法
@Override
public void handleDataDeleted(String s) throws Exception {
System.out.println("当前节点路径:" + s);
}
});
System.in.read(); // 阻塞当前监听
}

// 监听节点目录的变化
@Test
public void testOnNodesChange() throws IOException {
zkClient.subscribeChildChanges("/node1", new IZkChildListener() {
// 当节点的发生变化时,会自动调用这个方法
// 参数1:父节点名称
// 参数2:父节点中的所有子节点名称
@Override
public void handleChildChange(String s, List<String> list) throws Exception {
System.out.println("父节点名称:" + s);
System.out.println("发生变更后孩子节点名称:");
for (String name: list) {
System.out.println(name);
}
}
});
System.in.read(); // 阻塞当前监听
}

@Before
public void before() {
// 参数1:Server服务器ip地址
// 参数2:会话超时时间
// 参数3:连接超时时间
// 参数4:序列化方式
zkClient = new ZkClient("192.168.9.3:2181", 60000 * 30, 60000, new SerializableSerializer());
}

@After // 释放资源
public void after() {
zkClient.close();
}

// 获取连接
public static void main(String[] args) {

}
}

9. ZK集群

9.1 集群(cluster)

​ 集群是指同一种软件服务的多个节点同时提供服务

​ 集群解决了什么问题?

  • 单节点的并发访问的压力问题
  • 单节点故障问题

9.2 集群架构

image-20220126170237466

9.3 集群搭建

  1. 在~目录下新建三个文件夹
1
mkdir zkdata1 zkdata2 zkdata3
  1. 建立myid文件
1
touch zkdata1/myid zkdata2/myid zkdata3/myid
  1. 为每个zk指定id
1
2
3
echo "1" >> zkdata1/myid 
echo "2" >> zkdata2/myid
echo "3" >> zkdata3/myid
  1. 添加配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
vim zkdata1/zoo.cfg
vim zkdata2/zoo.cfg
vim zkdata3/zoo.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/root/zkdata1
clientPort=3001
server.1=196.168.9.3:3002:3003
server.2=192.158.9.3:4002:4003
server.3=192.168.9.3:5002:5003

  1. 相关操作
1
2
3
4
5
6
7
8
# 启动
./bin/zkServer.sh start /root/zkdata1/zoo.cfg
./bin/zkServer.sh start /root/zkdata2/zoo.cfg
./bin/zkServer.sh start /root/zkdata3/zoo.cfg
# 查看状态
./bin/zkServer.sh status /root/zkdata1/zoo.cfg
# 停止
./bin/zkServer.sh stop /root/zkdata1/zoo.cfg

zookeeper基本使用与集群搭建
https://2w1nd.github.io/2022/02/04/框架/zookeeper基本使用与集群搭建/
作者
w1nd
发布于
2022年2月4日
许可协议