zookeeper安装与使用

zookeeper 介绍

zookeeper,它是一个分布式服务框架,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

简单来说zookeeper=文件系统+监听通知机制

举例说明

这里拿比较简单的分布式应用配置管理为例来说明:
假设我们的程序是分布式部署在多台机器上,如果我们要改变程序的配置文件,需要逐台机器去修改,非常麻烦,现在把这些配置全部放到zookeeper上去,保存在 zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 zookeeper 的通知,然后从 zookeeper 获取新的配置信息应用到系统中。

安装zookeeper依赖

安装JDK1.8

安装过程参考 《JDK1.8安装与配置》

zookeeper 单机模式安装(zookeeper-3.7.1)

  1. 下载并解压zookeeper到安装目录/usr/local/zookeeper (安装目录自定义)

    wget https://mirrors.bfsu.edu.cn/apache/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz --no-check-certificate
    
    mkdir -p /usr/local/zookeeper
    
    tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /usr/local/zookeeper
    
    mkdir -p /usr/local/zookeeper/data
    
    cd /usr/local/zookeeper/apache-zookeeper-3.7.1-bin
    

      zookeeper-3.7.1 网盘下载: https://pan.baidu.com/s/1CjMTlK2XTj1XKEvIhIyMZQ?pwd=7vpr

  2. 重命名配置文件zoo_sample.cfg

    cp conf/zoo_sample.cfg conf/zoo.cfg

      zoo.cfg 默认配置如下:

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

      修改zoo.cfg的数据存放目录为自己设置的地方

    dataDir=/usr/local/zookeeper/data
  3. 启动zookeeper

    bin/zkServer.sh start
  4. 检测是否成功启动,用zookeeper客户端连接服务端

    bin/zkCli.sh

zookeeper 使用

使用客户端命令操作zookeeper

bin/zkCli.sh 进入 zk 客户端, 默认连接本地 2181 端口
bin/zkCli.sh -server host:port 指定要连接的服务器和端口

create 创建子节点

[zk: localhost:2181(CONNECTED) 2] create /apps
Created /apps
[zk: localhost:2181(CONNECTED) 3] create /apps/cache
Created /apps/cache
[zk: localhost:2181(CONNECTED) 4] create /apps/cache/users
Created /apps/cache/users
[zk: localhost:2181(CONNECTED) 5] create /apps/cache/users/p1 zhansan
Created /apps/cache/users/p1
[zk: localhost:2181(CONNECTED) 0] create /apps/cache/users/p2 lisi
Created /apps/cache/users/p2

ls 查看子节点

[zk: localhost:2181(CONNECTED) 1] ls /
[apps, zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /apps
[cache]
[zk: localhost:2181(CONNECTED) 3] ls /apps/cache
[users]
[zk: localhost:2181(CONNECTED) 4] ls /apps/cache/users
[p1, p2]
[zk: localhost:2181(CONNECTED) 5] ls /apps/cache/users/p1
[]

get 获取节点数据

[zk: localhost:2181(CONNECTED) 9] get /apps/cache/users
null
[zk: localhost:2181(CONNECTED) 7] get /apps/cache/users/p1
zhansan
[zk: localhost:2181(CONNECTED) 8] get /apps/cache/users/p2
lisi

set 编辑节点数据

[zk: localhost:2181(CONNECTED) 10] set /apps/cache/users/p1 zs
[zk: localhost:2181(CONNECTED) 11] get /apps/cache/users/p1
zs

delete 删除节点

[zk: localhost:2181(CONNECTED) 13] delete /apps/cache/users/p1
[zk: localhost:2181(CONNECTED) 14] ls /apps/cache/users
[p2]

deleteall 删除非空节点

[zk: localhost:2181(CONNECTED) 13] deleteall /apps/cache/users/pNode

使用Python API操作zookeeper

安装Python API pip install kazoo

# encoding:utf-8

from kazoo.client import KazooClient

# 创建zk连接
zk = KazooClient(hosts='127.0.0.1:2181')  # hosts可连接多个服务,逗号分隔
zk.start()

# 创建节点,makepath设置为True,父节点不存在则创建
node = zk.create('/apps/cache/component/toolkits', b'toolkits:v8.1', makepath=True)
print("[create /apps/cache/component/toolkits]-->:", node)
print("")

# 查看子节点
nodes = zk.get_children('/apps/cache/component')
print("[ls /apps/cache/component]-->:", nodes)
print("")

# 获取节点对应值
value = zk.get('/apps/cache/component/toolkits')
print("[get /apps/cache/component/toolkits]-->:", value)
print("")

# 更改节点的值
zk.set('/apps/cache/component/toolkits', b'toolkits:v8.2')
print("[set /apps/cache/component/toolkits 'toolkits:v8.2']")
value = zk.get('/apps/cache/component/toolkits')
print('[get /apps/cache/component/toolkits]-->:', value)
print("")

# 删除节点,参数recursive 若为False,当需要删除的节点存子节点,会抛异常NotEmptyError,若为True,则删除此节点及其所有子节点
zk.delete('/apps/cache/component/toolkits', recursive=False)
print("[delete /apps/cache/component/toolkits]")
nodes = zk.get_children('/apps/cache/component')
print("[ls /apps/cache/component]-->:", nodes)

# 关闭zk连接
zk.stop()

运行日志如下:

[create /apps/cache/component/toolkits]-->: /apps/cache/component/toolkits

[ls /apps/cache/component]-->: ['toolkits']

[get /apps/cache/component/toolkits]-->: (b'toolkits:v8.1', ZnodeStat(czxid=73, mzxid=73, ctime=1656853494489, mtime=1656853494489, version=0, cversion=0, aversion=0, ephemeralOwner=0, dataLength=13, numChildren=0, pzxid=73))

[set /apps/cache/component/toolkits 'toolkits:v8.2']
[get /apps/cache/component/toolkits]-->: (b'toolkits:v8.2', ZnodeStat(czxid=73, mzxid=74, ctime=1656853494489, mtime=1656853494598, version=1, cversion=0, aversion=0, ephemeralOwner=0, dataLength=13, numChildren=0, pzxid=73))

[delete /apps/cache/component/toolkits]
[ls /apps/cache/component]-->: []

watch监听节点数据变化:

# encoding:utf-8

from kazoo.client import KazooClient

# 创建zk连接
zk = KazooClient(hosts='127.0.0.1:2181')
zk.start()


# 定义监听事件
def changed(event):
    print("触发事件:", event)


if __name__ == '__main__':
    value = zk.get("/apps/cache/component/toolkits", watch=changed)
    print("第一次获取value:", value)
    zk.set("/apps/cache/component/toolkits", b"hello world!")
    print("已更新节点数据,接着重新获取value....")
    value = zk.get("/apps/cache/component/toolkits", watch=changed)
    print("第二次获取value:", value)

日志输出如下:

第一次获取value: (b'hello hello!', ZnodeStat(czxid=78, mzxid=100, ctime=1656854524798, mtime=1656854988128, version=8, cversion=0, aversion=0, ephemeralOwner=0, dataLength=12, numChildren=0, pzxid=78))
触发事件: WatchedEvent(type='CHANGED', state='CONNECTED', path='/apps/cache/component/toolkits')
已更新节点数据,接着重新获取value....
第二次获取value: (b'hello world!', ZnodeStat(czxid=78, mzxid=103, ctime=1656854524798, mtime=1656855056180, version=9, cversion=0, aversion=0, ephemeralOwner=0, dataLength=12, numChildren=0, pzxid=78))

zookeeper集群模式安装

本例搭建的是伪集群模式,即一台机器上启动三个zookeeper实例组成集群,真正的集群模式无非就是实例IP地址不同,搭建方法没有区别

  1. 下载并解压zookeeper到安装目录/usr/local/zookeeper (安装目录自定义)

    wget https://mirrors.bfsu.edu.cn/apache/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz --no-check-certificate
    
    tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /usr/local/zookeeper
    
    cd /usr/local/zookeeper/apache-zookeeper-3.7.1-bin
  2. 重命名配置文件zoo_sample.cfg

    cp conf/zoo_sample.cfg conf/zoo-1.cfg
  3. 修改配置文件zoo-1.cfg,原配置文件里有的,修改成下面的值,没有的则加上

    dataDir=/usr/local/zookeeper/data-1
    clientPort=2181
    server.1=127.0.0.1:2888:3888
    server.2=127.0.0.1:2889:3889
    server.3=127.0.0.1:2890:3890

配置说明:

  • tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。

  • initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒

  • syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10秒

  • dataDir:顾名思义就是 Zookeeper 保存数据的目录

  • dataLogDir: 事务日志的存储路径,如果不配置这个那么事务日志会默认存储到dataDir指定的目录,这样会严重影响zk的性能,当zk吞吐量较大的时候,产生的事务日志、快照日志太多

  • clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

  • secureClientPort:使用SSL侦听安全客户端连接的端口。clientPort指定明文连接的端口,而secureClientPort指定SSL连接的端口。指定两者都启用混合模式,而忽略将禁用该模式。请注意,当用户将zookeeper.serverCnxnFactory,zookeeper.clientCnxnSocket作为Netty插件时,将启用SSL功能。

  • server.A=B:C:D

    • A 是一个数字,表示这个是第几号服务器, 这个标识要和下面我们配置的 myid 的标识一致

    • B 是这个服务器的 ip 地址;

    • C 表示的是集群中 master 与 slave 之间的通信接口,默认是 2888

    • D 表示的是leader选举的端口,集群刚启动的时候选举或者leader挂掉之后进行新的选举的端口,默认是 3888

      如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号C,D 不能一样,所以要给它们分配不同的端口号。在真实场景,服务器ip B 不一样时,C,D端口可一样,如下:

      server.1=112.74.110.129:12887:13887
      server.2=112.74.110.130:12887:13887
      server.3=112.74.110.131:12887:13887
  1. 再从zoo-1.cfg复制两个配置文件zoo-2.cfg和zoo-3.cfg,只需修改dataDir和clientPort不同即可
    dataDir=/usr/local/zookeeper/data-2
    clientPort=2182
    dataDir=/usr/local/zookeeper/data-3
    clientPort=2183

    在真实场景,服务器ip B 不一样时,dataDir,clientPort(secureClientPort)可设置相同值

  1. 标识Server ID
    创建三个文件夹/usr/local/zookeeper/data-1,/usr/local/zookeeper/data-2,/usr/local/zookeeper/data-3,在每个目录中创建myid 文件,写入当前实例的server id,即1.2.3

    # cat data-1/myid
    1
    # cat data-2/myid 
    2
    # cat data-3/myid 
    3
  2. 启动三个zookeeper实例

    # bin/zkServer.sh start conf/zoo-1.cfg
    # bin/zkServer.sh start conf/zoo-2.cfg
    # bin/zkServer.sh start conf/zoo-3.cfg
  3. 检测集群状态,也可以直接用命令zkCli.sh -server IP:PORT连接zookeeper服务端检测

    # bin/zkServer.sh  status conf/zoo-1.cfg 
    ZooKeeper JMX enabled by default
    Using config: conf/zoo-1.cfg
    Client port found: 2181. Client address: localhost. Client SSL: false.
    Mode: follower
    
    # bin/zkServer.sh  status conf/zoo-2.cfg 
    ZooKeeper JMX enabled by default
    Using config: conf/zoo-2.cfg
    Client port found: 2182. Client address: localhost. Client SSL: false.
    Mode: leader
    
    # bin/zkServer.sh  status conf/zoo-3.cfg 
    ZooKeeper JMX enabled by default
    Using config: conf/zoo-3.cfg
    Client port found: 2183. Client address: localhost. Client SSL: false.
    Mode: follower
    # bin/zkCli.sh -server 127.0.0.1:2181
    
    # bin/zkCli.sh -server 127.0.0.1:2182
    
    # bin/zkCli.sh -server 127.0.0.1:2183

zk集群一般只有一个leader,多个follower,leader一般是响应客户端的读写请求,而follower从leader同步数据,当leader挂掉之后就会从follower里投票选举一个leader出来。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
My Show My Code