Zookeeper学习笔记

目录

Zookeeper 介绍

Zookeeper是一个分布式应用程序协调服务,主要负责集中维护配置信息的服务,提供分布式的同步机制。其所有的服务都是做为其他分布式应用的基础。Zookeeper是Google Chubby的一个开源实现,是现在很多分布式应用的重要组件,包括诸如Hadoop、HBase、Kafka等,可以说现在Zookeeper是大家必须掌握的一门软件。

Zookeeper主要提供以下几种服务:

  1. 命名服务
  2. 配置管理
  3. 集群管理
  4. 分布式锁
  5. 队列管理

Zookeeper的特点

  • 简单:Zookeeper的核心是一个精简的文件系统,它支持一些简单的操作和一些抽象操作,例如,排序和通知。
  • 丰富:Zookeeper的原语操作是很丰富的,可实现一些协调数据结构和协议。例如,分布式队列、分布式锁和一组同级别节点中的“领导者选举”。
  • 高可用:Zookeeper支持集群模式,可以很容易的解决单点故障问题。
  • 松耦合式交互:不同进程间的交互不需要了解彼此,甚至可以不必同时存在,某进程在zookeeper中留下消息后,该进程结束后其它进程还可以读这条消息。
  • 资源库:Zookeeper实现了一个关于通用协调模式的开源共享存储库,能使开发者免于编写这类通用协议。

常用操作

为了熟悉Zookeeper的常用操作,最简单的办法就是使用Docker。

1
2
3
4
5
6
7
8
$ docker pull zookeeper
# 完成后启动zookeeper
$ docker run -p 2181:2181 zookeeper
# 重新打开一个Terminal界面,查找到当前容器的ID,登陆到容器中
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
63c3aa117fca zookeeper "/docker-entrypoint.…" About a minute ago Up About a minute 2888/tcp, 0.0.0.0:2181->2181/tcp, 3888/tcp infallible_saha
$ docker exec -it 63c3aa117fca bash

现在一个单机版的Zookeeper就运行起来了,可以尝试常用的命令了。

查看Server运行状态

1
2
3
4
bash-4.4# ./zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Mode: standalone

客户端连接服务器

1
2
bash-4.4# ./zkCli.sh 
Connecting to localhost:2181

常用命令

  • 查看:ls

  • 获取节点数据和更新信息:get /zookeeper

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [zk: localhost:2181(CONNECTED) 3] get /zookeeper

    cZxid = 0x0
    ctime = Thu Jan 01 00:00:00 GMT 1970
    mZxid = 0x0
    mtime = Thu Jan 01 00:00:00 GMT 1970
    pZxid = 0x0
    cversion = -1
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 0
    numChildren = 1
  • 获取节点的更新信息:stat /zookeeper

  • 创建节点:craete [-s] [-e] path data acl-s表示创建顺序节点,-e表示创建临时节点。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [zk: localhost:2181(CONNECTED) 6] create /spring hello
    Created /spring
    [zk: localhost:2181(CONNECTED) 9] get /spring
    hello
    cZxid = 0x4
    ctime = Fri Apr 05 09:30:55 GMT 2019
    mZxid = 0x4
    mtime = Fri Apr 05 09:30:55 GMT 2019
    pZxid = 0x4
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 5
    numChildren = 0
  • 修改节点:set path data [version],可以看到dataVersion变成了1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [zk: localhost:2181(CONNECTED) 11] set /spring spring-v1
    cZxid = 0x4
    ctime = Fri Apr 05 09:30:55 GMT 2019
    mZxid = 0x5
    mtime = Fri Apr 05 09:34:19 GMT 2019
    pZxid = 0x4
    cversion = 0
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 9
    numChildren = 0
  • 删除节点:delete path [version]

    1
    2
    3
    [zk: localhost:2181(CONNECTED) 17] delete /spring
    [zk: localhost:2181(CONNECTED) 18] get /spring
    Node does not exist: /spring
  • 设置watch事件:stat path [watch]

    1
    2
    3
    4
    5
    6
    7
    8
    [zk: localhost:2181(CONNECTED) 33] stat /spring/bootx watch
    Node does not exist: /spring/bootx
    [zk: localhost:2181(CONNECTED) 34] create /spring/bootx bootx
    Created /spring/bootx

    WATCHER::
    [zk: localhost:2181(CONNECTED) 35]
    WatchedEvent state:SyncConnected type:NodeCreated path:/spring/bootx
  • 设置watch事件:get path [watch]

    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
    [zk: localhost:2181(CONNECTED) 38] get /spring/booty watch
    new-boot-y
    cZxid = 0xc
    ctime = Fri Apr 05 13:38:36 GMT 2019
    mZxid = 0xd
    mtime = Fri Apr 05 13:38:48 GMT 2019
    pZxid = 0xc
    cversion = 0
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 10
    numChildren = 0
    [zk: localhost:2181(CONNECTED) 39] set /spring/booty nnew-boot-y

    WATCHER::

    WatchedEvent state:SyncConnected type:NodeDataChanged path:/spring/booty
    cZxid = 0xc
    ctime = Fri Apr 05 13:38:36 GMT 2019
    mZxid = 0xe
    mtime = Fri Apr 05 13:39:26 GMT 2019
    pZxid = 0xc
    cversion = 0
    dataVersion = 2
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 11
    numChildren = 0

ACL权限

ZK的节点有5种操作权限:CREATE、READ、WRITE、DELETE、ADMIN也就是 增、删、改、查、管理权限。

注:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作权限。

身份的认证有4种方式:

  • world:默认方式,相当于全世界都能访问
  • auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)
  • digest:即用户名:密码这种方式认证,这也是业务系统中最常用的
  • ip:使用Ip地址认证
    1
    2
    3
    4
    5
    6
    [zk: localhost:2181(CONNECTED) 42] getAcl /spring
    'world,'anyone
    : cdrwa
    [zk: localhost:2181(CONNECTED) 43] getAcl /zookeeper
    'world,'anyone
    : cdrwa

四字命令

ZooKeeper 支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息。用户在客户端可以通过telnetnc向 ZooKeeper 提交相应的命令。 ZooKeeper 常用四字命令如下表所示。

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ echo stat | nc 127.0.0.1 2181
Zookeeper version: 3.4.13-2d71af4dbe22557fda74f9a9b4309b15a7487f03, built on 06/29/2018 04:05 GMT
Clients:
/172.17.0.1:53548[0](queued=0,recved=1,sent=0)
/127.0.0.1:56306[1](queued=0,recved=483,sent=485)

Latency min/avg/max: 0/0/45
Received: 500
Sent: 501
Connections: 2
Outstanding: 0
Zxid: 0xe
Mode: standalone
Node count: 8

Zookeeper API 及编程

API简介

ZooKeeper API 共包含 5 个包,分别为: org.apache.zookeeper , org.apache.zookeeper.data , org.apache.zookeeper.server , org.apache.zookeeper.server.quorum 和 org.apache.zookeeper.server.upgrade 。

其中 org.apache.zookeeper 包含 ZooKeeper 类,它我们编程时最常用的类文件。这个类是 ZooKeeper 客户端库的主要类文件。如果要使用 ZooKeeper 服务,应用程序首先必须创建一个 Zookeeper 实例,这时就需要使用此类。一旦客户端和 ZooKeeper 服务建立起连接, ZooKeeper 系统将会分配给此连接回话一个 ID 值,并且客户端将会周期地向服务器发送心跳来维持会话的连接。只要连接有效,客户端就可以调用 ZooKeeper API 来做相应的处理。

下表是一些常用的方法
| 功能 | 描述 |
|—|—|
| create | 在本地目录树中创建一个节点 |
| delete | 删除一个节点 |
| exists | 测试本地是否存在目标节点 |
| get/set data | 从目标节点上读取 / 写数据 |
| get/set ACL | 获取 / 设置目标节点访问控制列表信息 |
| get children | 检索一个子节点上的列表 |
| sync | 等待要被传送的数据 |

API的使用

使用了Spring Boot,连接Docker中启动的ZK,具体代码可以参考我的GITHUB。

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
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;

@RestController
public class MeetingController implements Watcher {
private static final int SESSION_TIMEOUT = 1000; // 回话超时时间
private static CountDownLatch latch = new CountDownLatch(1);
private ZooKeeper zk;
private static final String REGISTRY_PATH = "/registry";

@Autowired
private MeetingRepository meetingRepository;

Watcher wh = new Watcher(){
public void process(org.apache.zookeeper.WatchedEvent event){
System.out.println(event.toString());
}
};

// ZK测试
@RequestMapping("/zk")
public String testZk() throws InterruptedException, KeeperException {

try {
zk = new ZooKeeper("localhost:2181", SESSION_TIMEOUT, this.wh);
// latch.await();

if(zk.exists(REGISTRY_PATH, false) == null){
zk.create(REGISTRY_PATH, "hello registry".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

System.out.println(new String(zk.getData(REGISTRY_PATH, false, null)));
}else{
zk.setData(REGISTRY_PATH, "hello zk".getBytes(), 0);

System.out.println(new String(zk.getData(REGISTRY_PATH, false, null)));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// ZooKeeper zk = null;

return "zk test";
}
}

参考资料

  1. Apache Zookeeper
  2. 百度百科 Zookeeper
  3. Zookeeper的功能以及工作原理
  4. Zookeeper系列一:Zookeeper基础命令操作
  5. ZooKeeper系列之六:ZooKeeper四字命令
  6. ZooKeeper系列之九:ZooKeeper API简介及编程

参考资料

  1. Apache Zookeeper
  2. 百度百科 Zookeeper
  3. Zookeeper的功能以及工作原理
  4. Zookeeper系列一:Zookeeper基础命令操作
  5. ZooKeeper系列之六:ZooKeeper四字命令

cocowool

A FULL STACK DREAMER!