ZooKeeper使用教程
一、概述
官⽹网
介绍
ZooKeeper是一个开源的分布式应⽤协调服务系统,主要⽤用来完成统一命名服务、状态同步服务、集群管理理、分布式应⽤用配置项的管理理等⼯工作。
ZooKeeper(分布系统基础服务)
介绍:分布式服务协调系统
内部结构:树形层次空间(类似linux文件系统)
a. 层次结构
b. 节点ZNode
c. 目录和存储数据
节点类型:
a. 临时节点(重要):生命周期依赖于会话 会话终止 临时节点删除
b. 永久节点:生命周期不依赖于会话 只有客户端执行删除指令时才会被删除
c. 顺序节点: 创建的节点的名称后面+序列化(10位)
监视器
监视节点信息改变
a. 子节点数量改变
b. 数据改变
c. 状态改变
特点
- ZooKeeper有⼀一个层次化的名称空间,很像⼀一个分布式⽂文件系统(树形层次结构)
- ZooKeeper树中的每个节点被称为——Znode
- Znode,兼具⽂文件和⽬目录两种特点。既像⽂文件⼀一样维护着数据、元信息、ACL、时间戳等数据结
构,⼜又像⽬目录⼀一样可以作为路路径标识的⼀一部分
ZNode类型
ZooKeeper中的节点分为临时节点、永久节点和顺序节点。节点的类型在创建时即被确定,并且不不能改变。
-
临时节点(Ephemeral Node):该节点的⽣生命周期依赖于创建它们的会话。一旦会话
(Session)结束,临时节点将被自动删除,ZooKeeper的临时节点不不允许拥有⼦子点。 -
永久节点(Persistent Node):该节点的生命周期不依赖于会话,并且只有在客户端执行删除操作的时候,他们才能被删除。
-
顺序节点(Sequential Node):顺序节点可以是持久的或临时的。当一个新的Znode被创建为⼀个顺序节点时,ZooKeeper通过将10位的序列列号附加到原始名称来设Znode的路径。例如,如果将具有路路径 /myapp 的znode创建为顺序节点,则ZooKeeper会将路径更改为 /myapp0000000001 ,并将下⼀一个序列列号设置为0000000002。
Watches
客户端可以在节点上设置watch,我们称之为监视器器。当节点状态发生改变时(ZNode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知。
ZooKeeper的应用场景
分布式系统基础组件
-
统一命名服务(Apache Dubbo)
使用zk作为dubbo服务的注册中心,好处:服务消费者可以通过注册中心感知服务提供者调用信息的改变(临时节点+子节点数量改变的监视器)
直接使用服务消费者端调用服务的提供者容易出现单点故障的问题 使用zk作为注册中心,所有的服务提供者,将在注册临时节点,并且使用节点数量变化监视器进行监控,如果有服务器发生故障其对应的临时节点就会消失,监视器会监空到节点数量的变化避免单点故障问题
-
分布式配置中心
Spring Cloud Config(Git)
使用监视器(监视数据改变)配置信息一旦改变,就是用新的配置项替换原有的配置内容
利用数据变化监控器监控配置文件的改变进行配置文件的统一管理配置
- 集群管理
- 集群选举(master/slave)
ES集群(高可用)
- 集群选举(master/slave)
shell 利用顺序节点进行排序,如果出现主机问题最小的节点顶替
-
Hadoop集群、HBase集群、Kafka集群(集群管理)
-
元数据存储
- HBase中通过java api 操作,需要连接zkServer获取HBase集群的信息
- Kafka topic(主题)元数据存储在ZK
-
HA集群(高可用) …
-
分布式锁
二、环境搭建
安装
注:单机模式为例例
-
配置JDK的环境变量量
rpm -ivh jdk-8u181-linux-x64.rpm
-
下载安装包
wget http://mirrors.shu.edu.cn/apache/zookeeper/zookeeper3.4.11/zookeeper-3.4.11.tar.gz
3.解压
tar -zxvf zookeeper-3.4.11.tar.gz -C /usr
-
修改配置文件
修改配置⽂文件 cp /usr/zookeeper-3.4.11/conf/zoo_sample.cfg /usr/zookeeper-3.4.11/conf/zoo.cfg # 修改配置⽂文件 vi /usr/zookeeper-3.4.11/conf/zoo.cfg tickTime=2000 dataDir=/root/zkData clientPort=2181
启动
-
启动ZK Server
cd /usr/zookeeper-3.4.11/bin ./zkServer.sh start ../conf/zoo.cfg
-
启动成功
-
三、ZooKeeper指令操作
使用客户端脚本连接ZK Server
cd /usr/zookeeper-3.4.11/bin
./zkCli.sh -server 192.168.21.147:2181
常⽤用指令
- help 帮助
- connect host:port 连接到指定zk server
- get path [watch] 获取指定节点数据
- ls path [watch] 查看指定节点所有⼦子节点
- set path data [version] 给指定节点设置数据
- rmr path 递归删除指定节点
- quit 退出客户端
- create [-s][-e] path data acl 创建节点 -s 顺序节点 -e 临时节点
- close 关闭连接
- delete path [version] 删除节点
四、JAVA API操作
Maven依赖坐标
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.8</version>
</dependency>
增、删、改、查操作
package com.baizhi.zookeeper;
import org.I0Itec.zkclient.ZkClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Date;
import java.util.List;
/**
* @author gaozhy
* @date 2018/3/5.16:26
*/
public class ZkClientOperation {
private ZkClient zkClient = null;
@Before
public void before(){
zkClient = new ZkClient("192.168.128.160");
}
/**
* 增删改查
*/
@Test
public void zkCRUD(){
// 创建持久节点
zkClient.createPersistent("/tencent",true);
// 创建临时节点
zkClient.createEphemeral("/zpark","bzjy");
// 创建临时顺序节点
String e1 = zkClient.createEphemeralSequential("/tencent/league-of-legends", "lol");
String e2 = zkClient.createEphemeralSequential("/tencent/cross-fire", "cf");
System.out.println("创建的临时顺序节点e1:"+e1);
System.out.println("创建的临时顺序节点e2:"+e2);
// 获取节点列列表
List<String> list = zkClient.getChildren("/tencent");
list.forEach(n -> System.out.println(n));
// 删除节点
boolean result = zkClient.deleteRecursive("/tencent");
System.out.println("删除结果:"+result);
// 获取节点内容
Object data = zkClient.readData("/zpark");
System.out.println("/zpark 保存的数据为:"+data);
// 更更新节点内容
zkClient.writeData("/zpark",new Date());
Object newData = zkClient.readData("/zpark");
System.out.println("/zpark 更更新后数据为:"+newData);
}
@After
public void after(){
zkClient.close();
}
}
注册监听
在ZkClient中客户端可以通过注册相关的事件监听来实现对Zookeeper服务端事件的订阅,其中
ZkClient提供的常⽤用监听事件接口有以下几种:
监听接口 | 订阅方法 | 取消订阅方法 |
---|---|---|
IZkZhildListenner | subscribeChildChanges | unsubscribeChildChanges |
IAkDatalistenner | subscribeDataChanges | unsubscribeDataChanges |
测试代码
package com.baizhi.zookeeper;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import java.io.IOException;
import java.util.List;
/**
* @author gaozhy
* @date 2018/4/20.17:32
*/
public class ZKListener {
public static void main(String[] args) throws IOException {
ZkClient zkClient = new ZkClient("192.168.128.160:2181");
// 订阅⼦子节点改变
zkClient.subscribeChildChanges("/tencent", new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String>
currentChilds) throws Exception {
System.out.println("parentPath: "+parentPath);
currentChilds.forEach( n -> System.out.println("child node:"+n));
System.out.println("-----------------------------------");
}
});
// 订阅数据改变
zkClient.subscribeDataChanges("/tencent", new IZkDataListener() {
@Override
public void handleDataChange(String dataPath, Object data)
throws Exception {
System.out.println("data change: "+dataPath + ",change
data: "+data);
}
@Override
public void handleDataDeleted(String dataPath) throws Exception{
System.out.println("delete node path: "+dataPath);
}
});
System.in.read();
}
}