Zookeeper 学习笔记 (详细)
Posted 黑桃️
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zookeeper 学习笔记 (详细)相关的知识,希望对你有一定的参考价值。
Zookeeper
- 一、Zookeeper 入门
- 二、Zookeeper 安装
- 三、Zookeeper 内部原理
- 四、Zookeeper 实战 (★)
- 🔺 分布式安装部署
- (1) 配置服务器编号
- (2) 配置 zoo.cfg 文件
- (3) 集群操作
- 🔺 客户端命令行操作
- (1) 启动客户端
- (2) 显示所有操作命令
- (3) 查看当前znode中所包含的内容
- (4) 查看当前节点详细数据
- (5) 分别创建2个普通节点
- (6) 获得节点的值
- (7) 创建短暂节点
- (8) 创建带序号的节点
- (9) 修改节点数据值
- (10) 节点的值变化监听
- (11) 节点的子节点变化监听(路径变化)
- (12) 删除节点
- (13) 递归删除节点
- (14) 查看节点状态
- 🔺 API 应用
- (1) 创建一个 maven 工程
- (2) 添加 pom 文件
- (3) 拷贝log4j.properties文件到项目根目录
- (4) 创建ZooKeeper客户端
- (5) 创建子节点
- (6) 获取子节点并监听节点变化
- (7) 判断Znode是否存在
- 🔺 监听服务器节点动态上下线案例
- (1) 需求
- (2) 需求分析
- (3) 具体实现
- 五、企业面试真题
一、Zookeeper 入门
(1) 概述
Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。Zookeeper工作机制如下:
(2) 特点
(3) 数据结构
(4) 应用场景
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡 等。
统一命名服务
统一配置服务
统一集群管理
服务器节点动态上下线
软负载均衡
(5) 下载地址
二、Zookeeper 安装
(1) 本地模式安装部署
① 安装前准备
▲ 安装Jdk
▲ 拷贝Zookeeper安装包到Linux系统下
解压:tar -zxvf 压缩包名 目录 (解压到指定目录,不加目录默认当前目录)
② 配置修改
▲ 将/opt/zookeeper-3.4.10/conf这个路径下的zoo_sample.cfg修改为zoo.cfg;
mv zoo_sample.cfg zoo.cfg
▲ 打开zoo.cfg文件,修改dataDir路径:
需要手动创建 dataDir路径
③ 操作Zookeeper
▲ 启动Zookeeper
bin/zkServer.sh start
▲ 查看进程是否启动
jps
▲ 查看状态:
bin/zkServer.sh status
▲ 启动客户端:
bin/zkCli.sh
▲ 退出客户端:
quit
▲ 停止Zookeeper
bin/zkServer.sh stop
(2) 配置参数解读
三、Zookeeper 内部原理
(1) 选举机制 (★)
(2) 节点类型
(3) Stat 结构体
(4) 监听器原理 (★)
(5) 写数据流程
四、Zookeeper 实战 (★)
🔺 分布式安装部署
前提:解压后zookeeper后,新建三个zkData,然后在conf中将zoo_sample.cfg改名,复制三份zoo配置文件
(1) 配置服务器编号
在 zkData 文件夹下创建myid文件,内容分别为id值1,2,3
(2) 配置 zoo.cfg 文件
server.1=192.168.44.129:2887:3887
server.2=192.168.44.129:2888:3888
server.3=192.168.44.129:2889:3889
配置参数解读:server.A=B:C:D。
(3) 集群操作
▲ 分别启动Zookeeper
# 启动服务端
bin/zkServer.sh start conf/zoo1.cfg
# 启动对应服务端的客户端
bin/zkCli.sh -server localhost:2182
▲ 查看状态
( 根据之前的投票规则:正常情况下应该是 zookeeper-2 是 leader,1,3为follower )
bin/zkServer.sh status conf/zoo1.cfg
🔺 客户端命令行操作
(1) 启动客户端
bin/zkCli.sh
bin/zkCli.sh -server localhost:2182 #指定某台server的客户端
(2) 显示所有操作命令
(3) 查看当前znode中所包含的内容
(4) 查看当前节点详细数据
(5) 分别创建2个普通节点
(6) 获得节点的值
(7) 创建短暂节点
(8) 创建带序号的节点
(9) 修改节点数据值
(10) 节点的值变化监听
(11) 节点的子节点变化监听(路径变化)
(12) 删除节点
(13) 递归删除节点
(14) 查看节点状态
🔺 API 应用
(1) 创建一个 maven 工程
(2) 添加 pom 文件
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
</dependencies>
(3) 拷贝log4j.properties文件到项目根目录
需要在项目的src/main/resources目录下,新建一个文件命名为“log4j.properties”,在文件中填入。
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
(4) 创建ZooKeeper客户端
// 创建ZooKeeper客户端,客户端连接服务端
public static void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
public static void main(String[] args) throws Exception {
init();
}
(5) 创建子节点
如果是远程连接操作的虚拟机中的zk,一定要记得:
关闭 linux 环境中的防火墙!
关闭 linux 环境中的防火墙!
关闭 linux 环境中的防火墙!
// 创建子节点
public static void create() throws Exception {
// 参数1:要创建的节点的路径
String path = "/testCreate";
// 参数2:节点数据
byte[] data = "ht".getBytes();
// 参数3:节点权限
List<ACL> acls = Ids.OPEN_ACL_UNSAFE;
// 参数4:节点的类型
CreateMode createMode = CreateMode.PERSISTENT;
String nodeCreated = zkClient.create(path, data, acls, createMode);
System.out.println(nodeCreated);
}
public static void main(String[] args) throws Exception {
init();
create();
}
(6) 获取子节点并监听节点变化
获取节点
public static void getDataAndWatch() throws KeeperException, InterruptedException {
List<String> children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
// 延时阻塞
Thread.sleep(Long.MAX_VALUE);
}
// 创建ZooKeeper客户端,客户端连接服务端
public static void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
// 监听
@Override
public void process(WatchedEvent watchedEvent) {
List<String> children = null;
System.out.println("---------start---------");
try {
children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("---------end---------");
}
});
}
public static void main(String[] args) throws Exception {
init();
// create();
getDataAndWatch();
}
(7) 判断Znode是否存在
// 判断节点是否存在
public static void isExist() throws KeeperException, InterruptedException {
Stat exists = zkClient.exists("/sanguo", false);
System.out.println(exists==null ? "not exist" : "exist");
}
public static void main(String[] args) throws Exception {
init();
// create();
// getDataAndWatch();
isExist();
}
🔺 监听服务器节点动态上下线案例
(1) 需求
某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。
(2) 需求分析
(3) 具体实现
① 先在集群上创建/servers节点
create /servers "servers"
② 服务器端向Zookeeper注册代码
public class DistributeServer {
private String connectString = "192.168.44.129:2181,192.168.44.129:2182,192.168.44.129:2183";
private int sessionTimeout = 10000;
private ZooKeeper zk = null;
private String parentNode = "/servers";
private static String hostname = "ht";
public static void main(String[] args) throws Exception {
DistributeServer server = new DistributeServer();
// 服务端获取和zk的连接
server.getConnect();
// 注册服务器
server.registServer(hostname);
// 业务逻辑
server.businesss(hostname);
}
// 注册服务器
public void registServer(String hostname) throws Exception{
String create = zk.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname +" is online "+ create);
}
// 业务逻辑代码
private void businesss(String hostname) throws InterruptedException {
System.out.println(hostname+" is working ...");
// 延时阻塞
Thread.sleep(Long.MAX_VALUE);
}
// 创建到zookeeper的客户端连接
private void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
}
③ 客户端代码
public class DistributeClient {
private String connectString = "192.168.44.129:2181,192.168.44.129:2182,192.168.44.129:2183";
private int sessionTimeout = 10000;
private ZooKeeper zk = null;
private String parentNode = "/servers";
public static void main(String[] args) throws Exception {
DistributeClient client = new DistributeClient();
// 1获取zk连接
client.getConnect();
// 2获取servers的子节点信息,从中获取服务器信息列表
client.getServerList();
// 3业务进程启动
client.business();
}
// 3业务进程启动
private void business() throws InterruptedException {
System.out.println("client is working ...");
Thread.sleep(Long.MAX_VALUE);
}
private void getServerList() throws KeeperException, InterruptedException {
// 1获取服务器子节点信息,并且对父节点进行监听
List<String> children = zk.getChildren(parentNode, true);
// 2存储服务器信息列表
ArrayList<String> servers = new ArrayList<>();
// 3遍历所有节点,获取节点中的主机名称信息
for (String child : children) {
// byte[] data = zk.getData(parentNode + "/" + child, false, null);
//
// servers.add(new String(data));
servers.add(child);
}
// 4 打印服务器列表的信息
System.out.println(servers);
}
// 创建客户端和zookeeper的连接
private void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
// 再次启动监听
try {
getServerList();
} catch (Exception e) {
e.printStackTrace以上是关于Zookeeper 学习笔记 (详细)的主要内容,如果未能解决你的问题,请参考以下文章