zookeeper 介绍
zookeeper,它是一个分布式服务框架,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
简单来说zookeeper=文件系统+监听通知机制
举例说明
这里拿比较简单的分布式应用配置管理为例来说明:
假设我们的程序是分布式部署在多台机器上,如果我们要改变程序的配置文件,需要逐台机器去修改,非常麻烦,现在把这些配置全部放到zookeeper上去,保存在 zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 zookeeper 的通知,然后从 zookeeper 获取新的配置信息应用到系统中。
安装zookeeper依赖
安装JDK1.8
安装过程参考 《JDK1.8安装与配置》
zookeeper 单机模式安装(zookeeper-3.7.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
重命名配置文件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
启动zookeeper
bin/zkServer.sh start
检测是否成功启动,用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地址不同,搭建方法没有区别
下载并解压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
重命名配置文件zoo_sample.cfg
cp conf/zoo_sample.cfg conf/zoo-1.cfg
修改配置文件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
- 再从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)可设置相同值
标识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
启动三个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
检测集群状态,也可以直接用命令
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出来。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。