zookeeper 知识点汇总

Zookeeper 是什么

zookeeper 是软件世界里的管理者,被用来 提供分布式环境的协调服务。zookeeper 是 yahoo 公司使用 java 语言开发的,是 Hadoop 项目中的子项目,基于 Google 的 Chubby 的开源实现,在 Hadoop,Hbase,Kafka 等技术中充当核心组件的角色。

它的设计目标就是 将那些复杂并且容易出错的分布式一致性服务加以封装,构成高效且可靠的服务,并为用户提供一系列简单易用的接口

Zookeeper 是一个经典的 分布式数据一致性 解决方案,分布式应用程序可以基于它实现

  • 数据的发布和订阅
  • 负载均衡
  • 命名服务
  • 分布式协调与通知
  • 集群管理
  • 领导选举
  • 分布式锁
  • 分布式队列

zookeeper 一般都以 集群的方式 对外提供服务,一个集群包含多个节点,每个节点都对应一台 Zookeeper 服务器,所有的节点共同对外提供服务。具体包括以下五大特性:

  1. 顺序性
  2. 原子性
  3. 一致性
  4. 可靠性
  5. 实时性

Zookeeper 树状模型

Zookeeper 内部拥有树状的内存模型,与文件系统非常类似。

  • 在 Zookeeper 中将这些目录与文件统称为 ZNode
  • 每个 ZNode 都有对应的路径及其包含的数据
  • ZNode 可由 Zookeeper 客户端来创建
  • 当客户端与服务端建立连接后,服务端将为客户端创建一个 Session (会话),客户端对 ZNode 的所有操作均在这个会话中来完成

树状模型图如下所示

ZNode 包含 4 类节点

  • persistent 持久节点
  • persistent sequential 持久性顺序节点
  • ephemeral 临时性节点
  • ephemeral sequential 临时性顺序节点

Zookeeper 集群结构

Zookeeper 设计了一个轻量级的协议 Zab (ZooKeeper Atomic Broadcast, Zookeeper 广播协议)。Zab 协议分为两个阶段:

  • Leader Election 领导选举

    Zookeeper 集群启动时,会选出一台节点为 Leader,而其他节点均为 Follower。当 Leader 出现故障时,会自动选举出新的 Leader 节点,并让所有节点恢复到一个正常的状态。选举结束后,会进入 原子广播阶段。

  • Atomic Broadcase 原子广播

    该阶段会同步 Leader 节点与 Follower 节点之间的数据,确保 Leader 与 Follower 节点具有相同的状态。所有的写操作都会发送到 Leader 节点,并通过广播的方式同步到 Follower 节点。

一个 Zookeeper 集群通常由一组节点组成,一般情况下 3 ~ 5 个就可以组成可用的 Zookeeper 集群。

每个节点都会在内存中维护当前的服务器状态,并在每个节点之间都会保持通信,目的就是告诉其他节点“自己还活着”。我们一般会提供奇数个节点比较节省资源。此外, Zookeeper 客户端可以选择集群中任意一个节点来建立连接,而一旦客户端与某个节点之间断开联系,客户端会自动连接到集群的其他节点。

如何使用 ZooKeeper

zookeeper 官方地址:http://zookeeper.apache.org/

zookeeper 使用 java 语言开发,使用前需要先安装 jdk。下文是在 linux 环境下运行 zookeeper 的指导。

运行 Zookeeper

步骤1 修改 ZooKeeper 配置文件

Zookeeper 默认提供了一份名为 zoo_sample.cfg 的示例配置文件,需要复制一下,并将其重命名为 zoo.cfg 。配置文件的重要配置项如下

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181

详细解释下以上配置项

  • tickTime 滴答时间,用于配置 Zookeeper 中最小时间单元的长度。单位为 ms。默认值是 3000 ms。
  • initLimit 用于配置 Leader 节点等待 Follower 节点启动并完成数据同步的时间, 默认值是 10 ,也就是 10 * tickTime
  • syncLimit 用来配置 Leader 节点与 Follower 节点之间心跳检测的最大延时时间,默认值是 5,也就是 5 * tickTime
  • dataDir 用来配置 Zookeeper 服务器存储快照文件的目录,不建议将其指定到 /tmp 目录下,因为该目录下的所有文件可能被自动删除。在 Zookeeper 环境中,将生成一个名为 myid 的文件,用来存放 zk 集群节点的 ID。
  • clientPort 用于配置当前 zk 服务器对外暴露的接口

步骤 2, 启动 Zookeeper 服务器

启动 Zookeeper 服务器非常简单,只需执行 Zookeeper 提供的脚本程序即可。

 bin/zkServer.sh start

执行上面脚本,默认会在后台启动 Zookeeper 服务器。

zkServer.sh 可以传入以下参数

  • start
  • start-foreground
  • stop
  • restart
  • status
  • upgrade
  • print-cmd

步骤 3, 验证 Zookeeper 服务是否有效

bin/zkServer.sh status

还可以使用 telnet 命令来验证 ZooKeeper 服务是否有效

telnet 127.0.0.1 2181

zookeeper 当前处于 standard alone 模式下,一般情况下我们使用单机模式作为开发环境,而使用集群模式作为生产环境。

搭建 Zookeeper 集群环境

在本地搭建一个伪集群模式的 Zookeeper 集群环境(3 个节点)

修改 Zookeeper 配置文件

配置如下

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/app-data/zookeeper/data
dataLogDir=/usr/local/zookeeper-3.4.6/logs
clientPort=2181
server.0=127.0.0.1:2888:3888
server.1=127.0.0.1:2889:3889
server.2=127.0.0.1:2890:3890

与单机模式的区别就在于添加了一组 server 配置,表示集群中包含的三个节点,需要注意的是 server 配置需要满足一定的格式:

server.<id>=<ip>:<port1>:<port2>
  • id 表示节点编号,表示该节点在集群中的唯一编号,取值在 0 ~ 255 之间。
    • 必须在 dataDir 目录下创建一个名为 myid 的文件,其内容是该节点的编号
  • ip 表示节点所在的 IP 地址,本机为 127.0.0.1 或者是 localhost
  • port1 表示 Leader 节点与 Follower 节点心跳检测与数据同步时使用的接口
  • port2 表示在领导选举过程中,用于投票通信的端口

启动 ZooKeeper 集群

与单机模式的启动方法相同,只需一次启动所有的 ZooKeeper 节点即可启动整个集群

验证 Zookeeper 集群环境是否有效

和 standard alone 模式一样,也可以通过 zkServer.sh 脚本与 telnet 命令来查看每个节点的状态,此时会看到 Mode:leader 或者 Mode:follower 的信息,表示该节点是 Leader 还是 Follower。

ZooKeeper 提供了一系列脚本程序,全部存放在 bin 目录下,如

  • zkServer.sh 用于启动 Zookeeper 服务器
  • zkCli.sh 用于连接 ZooKeeper 服务器的命令行客户端
  • zkCleanup.sh 用于清理 ZooKeeper 的历史数据,包括
    • 事务日志文件
    • 快照数据文件
  • zkEnv.sh 用于设置 ZooKeeper 的环境变量

连接 zookeeper

使用 zkCli 连接 Zookeeper

连接 ZooKeeper 只需要执行以下脚本:

bin/zkCli.sh

如果想要连接远程的 ZooKeeper, 则在 zkCli.sh 脚本中添加 -server 选项

bin/zkCli.sh -server <ip>:<port>

连接成功后,就可以输入相关的命令来操作 zookeeper 了。当输入 help 命令后,将输出 zookeeper 相关客户端命令的使用帮助。

ZooKeeper -server host:port cmd args
        stat path [watch]
        set path data [version]
        ls path [watch]
        delquota [-n|-b] path
        ls2 path [watch]
        setAcl path acl
        setquota -n|-b val path
        history
        redo cmdno
        printwatches on|off
        delete path [version]
        sync path
        listquota path
        rmr path
        get path [watch]
        create [-s] [-e] path data acl
        addauth scheme auth
        quit
        getAcl path
        close
        connect host:port

列出子节点

命令格式如下

ls path [watch]

ls 命令中可设置一个 watch 参数,用于指定客户端监视器,在 zooKeeper 中被称为 Watcher, Watcher 用于监控节点的状态变化,默认情况下可不带有任何 Watcher。

[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]

默认情况下,根目录中有一个名为 zookeeper 的子节点,它作为 Zookeeper 的保留节点,我们一般不使用它。

此外,还可以使用 ls2 命令以更加详细的方式列出节点名称及其相关属性,命令格式如下

ls2 path [watch]

ls2 命令会输出当前节点的基本信息

[zk: localhost:2181(CONNECTED) 2] ls2 /
[zookeeper]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

在输出信息中包含了大量的统计属性:

  • cZxid 表示创建节点时的事务 ID (每个客户端请求都会形成一个事务)
  • ctime 表示创建节点的时间
  • mZxid 表示最后一次修改节点时的事务 ID
  • mtime 表示最后一次修改节点的时间
  • pZxid 表示最后一次修改父节点时的事务 ID
  • cversion 子节点的版本号
  • dataVersion 节点包含数据的版本号
  • aclVersion 表示节点的 ACL 权限版本号
  • ephemeralOwner 临时节点的会话 ID
  • dataLength 表示节点包含数据内容的长度
  • numChildren 当前节点的子节点数

判断节点是否存在

[zk: localhost:2181(CONNECTED) 8] stat /foo
Node does not exist: /foo

创建节点

使用 create 命令创建节点,命令格式如下

 create [-s] [-e] path data acl

其中

  • -s 用于指定该节点是否为顺序节点,即 Sequential 节点

  • -e 选项:用于指定该节点是否为临时节点,即 Ephemeral 节点

  • acl 用于权限控制, Zookeeper 内部提供了一个强大的 ACL 访问控制列表,默认情况下不做任何权限控制

    [zk: localhost:2181(CONNECTED) 13] create -e /foo hello
    Created /foo
    

获取节点数据

使用 get 命令获取节点数据,命令格式如下

get path [watch]

可以通过以下命令获取 /foo 节点包含的数据

[zk: localhost:2181(CONNECTED) 14] get /foo
hello
cZxid = 0xa
ctime = Wed Jan 02 15:27:44 CST 2019
mZxid = 0xa
mtime = Wed Jan 02 15:27:44 CST 2019
pZxid = 0xa
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x1680d4a324f0002
dataLength = 5
numChildren = 0

更新节点数据

使用 set 命令更新节点数据,命令格式如下

set path data [version]

在更新节点数据时,可指定 version 参数,表示节点包含数据的版本号。如果不指定 version 参数,则表示更新节点数据的最新版本。

删除节点

使用 delete 命令删除节点,命令格式如下

delete path [version]

当节点没有任何子节点时,才能删除成功,否则将给出 "node not empty" 的提示,但可以通过以下命令一次删除该节点及其所有的子节点。

rmr path

使用 Node.js Client 连接 Zookeeper

Node.js 连接 Zookeeper 中比较好用的客户端是 node-zookeeper-client

首先通过 NPM 来安装这个模块。

npm install node-zookeeper-client

先用一段代码来展示连接 Zookeeper, 后面再基于该代码,将 nodejs 针对 zookeeper 客户端的操作执行一遍。

var zookeeper = require('node-zookeeper-client')

var CONNECTION_STRING = 'localhost:2181'

var OPTIONS = {
  sessionTimeout: 5000
}

var zk = zookeeper.createClient(CONNECTION_STRING, OPTIONS)

zk.on('connected', function() {
  console.log(zk);
  zk.close();
});

zk.connect();

如果 zk 可以正常输出,说明可成功连接 Zookeeper 服务器并建立了正常的会话, 下面所有的操作都在该会话中进行。Node.js 客户端仅提供了异步方式,我们不能通过同步方式来调用。

node-zookeeper-client 的官方文档地址为: https://www.npmjs.com/package/node-zookeeper-client

可执行的常见操作包括:

  • 列出子节点
  • 判断节点是否存在
  • 创建节点
  • 获取节点数据
  • 更新节点数据
  • 删除节点

参考

  • 《架构探险—轻量级微服务架构》
posted @ 2018-12-26 14:58  ReyCG  阅读(703)  评论(0编辑  收藏  举报