1. Zookeeper概念

  • Zookeeper 是 Apache Hadoop 项目下的一个子项目,是一个树形目录服务
  • Zookeeper 是一个分布式的、开源的分布式应用程序的协调服务
  • Zookeeper 提供的主要功能包括
    • 配置管理
    • 分布式锁
    • 集群管理

2. ZooKeeper 命令操作

2.1 Zookeeper 数据模型

  • ZooKeeper 是一个树形目录服务,其数据模型和Unix的文件系统目录树很类似,拥有一个层次化结构
  • 这里面的每一个节点都被称为: ZNode,每个节点上都会保存自己的数据和节点信息
  • 节点可以拥有子节点,同时也允许少量(1MB)数据存储在该节点之下

节点可以分为四大类

  • PERSISTENT 持久化节点
  • EPHEMERAL 临时节点 :-e
  • PERSISTENT_SEQUENTIAL 持久化顺序节点 :-s
  • EPHEMERAL_SEQUENTIAL 临时顺序节点 :-es

2.2 Zookeeper 服务端常用命令

  • 启动 ZooKeeper 服务: ./zkServer.sh start
  • 查看 ZooKeeper 服务状态: ./zkServer.sh status
  • 停止 ZooKeeper 服务: ./zkServer.sh stop
  • 重启 ZooKeeper 服务: ./zkServer.sh restart

2.3 Zookeeper 客户端常用命令

指令 作用
./zkCli.sh –server ip:port 连接ZooKeeper服务端
quit 断开连接
help 查看命令帮助
ls 目录 显示指定目录下节点
create /节点path value 创建节点
get /节点path 获取节点值
set /节点path value 设置节点值
delete /节点path 删除单个节点
deleteall /节点path 删除带有子节点的节点
create -e /节点path value 创建临时节点
create -s /节点path value 创建顺序节点
ls –s /节点path 查询节点详细信息

详细信息含义

名称 含义
czxid 节点被创建的事务ID
ctime 创建时间
mzxid 最后一次被更新的事务ID
mtime 修改时间
pzxid 子节点列表最后一次被更新的事务ID
cversion 子节点的版本号
dataversion 数据版本号
aclversion 权限版本号
ephemeralOwner 用于临时节点,代表临时节点的事务ID,如果为持久节点则为0
dataLength 节点存储的数据的长度
numChildren 当前节点的子节点个数

3. ZooKeeper JavaAPI 操作

3.1 Curator 介绍

  • Curator 是 Apache ZooKeeper 的Java客户端库

  • 常见的ZooKeeper Java API :

    • 原生Java API
    • ZkClient
    • Curator
  • Curator 项目的目标是简化 ZooKeeper 客户端的使用

Curator 最初是 Netfix 研发的,后来捐献了 Apache 基金会,目前是 Apache 的顶级项目

3.2 Curator API 常用操作

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
<dependencies>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>

<!--curator-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<!--日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>

</dependencies>
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
//建立连接
@Before
public void testConnect() {
/*
* @param connectString 连接字符串。zk server 地址和端口 "192.168.149.135:2181,192.168.149.136:2181"
* @param sessionTimeoutMs 会话超时时间 单位ms
* @param connectionTimeoutMs 连接超时时间 单位ms
* @param retryPolicy 重试策略
*/
//重试策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);
//1.第一种方式
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.149.135:2181",
60 * 1000, 15 * 1000, retryPolicy);
//重试策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
//2.第二种方式 链式编程 namespace表示只使用该名称下的空间
//CuratorFrameworkFactory.builder();
client = CuratorFrameworkFactory.builder()
.connectString("192.168.149.135:2181")
.sessionTimeoutMs(60 * 1000)
.connectionTimeoutMs(15 * 1000)
.retryPolicy(retryPolicy)
.namespace("itheima")
.build();

//开启连接
client.start();
}
//最后要关闭连接
@After
public void close() {
if (client != null) {
client.close();
}
}

创建节点:create 持久 临时 顺序 数据

  1. 基本创建 :create().forPath(“”)

  2. 创建节点 带有数据:create().forPath(“”,data)

  3. 设置节点的类型:create().withMode().forPath(“”,data)

  4. 创建多级节点 /app1/p1 :create().creatingParentsIfNeeded().forPath(“”,data)

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
@Test
public void testCreate2() throws Exception {
//1. 基本创建
//如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储
String path = client.create().forPath("/app1");
System.out.println(path);
}

@Test
public void testCreate() throws Exception {
//2. 创建节点 带有数据
//如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储
String path = client.create().forPath("/app2", "hehe".getBytes());
System.out.println(path);
}

@Test
public void testCreate3() throws Exception {
//3. 设置节点的类型
//默认类型:持久化 可以设置临时节点 如果要用linux查看需要用个while(true)循环保证节点不关闭
String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");
System.out.println(path);
}

@Test
public void testCreate4() throws Exception {
//4. 创建多级节点 /app1/p1
//creatingParentsIfNeeded():如果父节点不存在,则创建父节点
String path = client.create().creatingParentsIfNeeded().forPath("/app4/p1");
System.out.println(path);
}

查询节点:

  1. 查询数据:get: getData().forPath()
  2. 查询子节点: ls: getChildren().forPath()
  3. 查询节点状态信息:ls -s:getData().storingStatIn(状态对象).forPath()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testGet1() throws Exception {
//1. 查询数据:get
byte[] data = client.getData().forPath("/app1");
System.out.println(new String(data));
}

@Test
public void testGet2() throws Exception {
// 2. 查询子节点: ls
List<String> path = client.getChildren().forPath("/");
System.out.println(path);
}

@Test
public void testGet3() throws Exception {
Stat status = new Stat();
System.out.println(status);
//3. 查询节点状态信息:ls -s 版本升级后get不能查询状态信息但api没有变还是用getData
client.getData().storingStatIn(status).forPath("/app1");
System.out.println(status);
}