1. ZooKeeper是什么
Apache ZooKeeper是一个开源的分布式服务框架,为分布式应用提供协调服务,用来解决分布式应用中的数
据管理问题,如:配置管理、域名服务、分布式同步、集群管理等
概念:
- 分布式
将一个大型应用的不同业务部署在不同的服务器上,解决高并发的问题
- 集群
将同一个业务部署在多台服务器上,提高系统的高可用性
2. ZooKeeper组成
主要包括两部分:文件系统、通知机制
2.1 文件系统
ZooKeeper维护一个类似Linux文件系统的数据结构,用于存储数据
- 数据模型结构是一种树形结构,由许多节点构成
- 每个节点叫做ZNode(ZooKeeper Node)
- 每个节点对应一个唯一路径,通过该路径来标识节点,如 /app1/p_2
- 每个节点只能存储大约1M的数据
节点类型有四种:
- 持久化目录节点 persistent
客户端与服务器断开连接,该节点仍然存在
- 持久化顺序编号目录节点 persistent_sequential
客户端与服务器断开连接,该节点仍然存在,此时节点会被顺序编号,如:000001、000002.....
- 临时目录节点 ephemeral
客户端与服务器断开连接,该节点会被删除
- 临时顺序编号目录节点 ephemeral_sequential
客户端与服务器断开连接,该节点会被删除,此时节点会被顺序编号,如:000001、000002.....
2.2 通知机制
ZooKeeper是一个基于观察者模式设计的分布式服务管理框架
- ZooKeeper负责管理和维护项目的公共数据,并授受观察者的注册(订阅)
- 一旦这些数据发生变化,ZooKeeper就会通知已注册的观察者
- 此时观察者就可以做出相应的反应
简单来说,客户端注册监听它关心的目录节点,当目录节点发生变化时,ZooKeeper会通知客户端
ZooKeeper是一个订阅中心(注册中心)
3. 应用场景
3.1 配置管理
场景:集群环境、服务器的许多配置都是相同的,如:数据库连接信息,当需要修改这些配置时必须同时修改
每台服务器,很麻烦
解决:把这些配置全部放到ZooKeeper上,保存在ZooKeeper的某个目录节点中,然后所有的应用程序(客户
端)对这个目录节点进行监视Watch,一旦配置信息发生变化,ZooKeeper会通知每个客户端,然后从ZooKeeper获
取新的配置信息,并应用到系统中。
3.2 集群管理
场景:集群环境下,如何知道有多少台机器在工作?是否有机器退出或加入?需要选举一个总管master,让总管来管理集群
解决:在父目录GroupMembers下为所有机器创建临时目录节点,然后监听父目录节点的子节点变化,一旦有机器挂掉,该机器与ZooKeeper的连接断开,其所创建的临时目录节点被删除,所有其他机器都会收到通知。当有新机器加入时也是同样的道理。
选举master:为所有机器创建临时顺序编号目录节点,给每台机器编号,然后每次选取编号最小的机器
作为master
3.3 负载均衡
ZooKeeper本身是不提供负载均衡策略的,需要自己实现,所以准确的说,是在负载均衡中使用ZooKeeper来
做集群的协调(也称为软负载均衡)
实现思路:
- 将ZooKeeper作为服务的注册中心,所有服务器在启动时向注册中心登陆自己能够提供的服务
- 服务的调用者到注册中心获取能够提供所需要服务的服务器列表,然后自己根据负载均衡算法,从中选取一台服务器进行连接
- 当服务器列表发生变化时,如:某台服务器宕机下线,或新机器加入,ZooKeeper会自动通知调用者重新获取服务列表
实际上利用了ZooKeeper的特性,将ZooKeeper用为服务的注册和变更通知中心
4 客户端操作
4.1 常用命令
命令 | 作用 | 说明 |
get 节点路径 | 获取节点中的值 | |
create e 节点路径 内容 | 创建临时节点 | 当连接断开后,节点会被自动删除 |
create s 节点路径 内容 | 创建顺序编号节点 | 即带序号的节点 |
delete 节点路径 | 删除节点 | 只能删除空节点,即不能有子节点 |
rmr 节点路径 | 递归删除节点 | remove recursion |
stat 节点路径 | 查看节点状态 | |
set 节点路径 新值 | 修改节点内容 |
4.2 详解
查看指定节点的详细信息: ls2 /
# 子节点名称数组
[zookeeper]
# 节点的状态信息,也称为stat结构体
# 创建该znode的事务的zxid(ZooKeeper Transaction ID)
# 事务ID是ZooKeeper为每次更新操作/事务操作分配一个全局唯一的id,表示zxid,值越小,表示越先执行
cZxid = 0x0 # 0x0表示十六进制数0
# 创建时间
ctime = Thu Jan 01 08:00:00 CST 1970
# 最后一次更新的zxid
mZxid = 0x0
# 最后一次更新的时间
mtime = Thu Jan 01 08:00:00 CST 1970
# 最后更新的子节点的zxid
pZxid = 0x0
# 子节点的变化号,表示子节点被修改的次数,1表示从未被修改过
cversion = 1
# 当前节点的变化号,0表示从未被修改过
dataVersion = 0
# 访问控制列表的变化号 access control list
aclVersion = 0
# 如果临时节点,表示当前节点的拥有者的sessionId
# 如果不是临时节点,则值为0
ephemeralOwner = 0x0
# 数据长度
dataLength = 0
# 子节点数据
numChildren = 1
顺序编号节点:
- 顺序编号会紧跟在节点名称后面,节点最终名称为:节点名+序号,如/test0000000005
- 顺序编号是一个递增的计数器
- 顺序编号是由父节点维护,从已有的子节点个数开始(包括临时节点和被删除的节点)
- 如果子节点为空,则从0000000000开始,依次递增1
- 在分布式系统中,顺序编号可以被用于为所有的事件进行全局排序,这样客户端就可以根据序号推断事件的顺序
实际操作验证:
[zk: localhost:2181(CONNECTED) 7] create /wyl 1234
Created /wyl
[zk: localhost:2181(CONNECTED) 8] get /wyl
1234
cZxid = 0x40000000f
ctime = Sun May 05 08:52:18 CST 2018
mZxid = 0x40000000f
mtime = Sun May 05 08:52:18 CST 2018
pZxid = 0x40000000f
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
# 创建一个数据节点
[zk: localhost:2181(CONNECTED) 9] create -s /wyl/test 1234
Created /wyl/test0000000000
[zk: localhost:2181(CONNECTED) 11] ls /wyl
[test0000000000]
# 可以看到是依次递增的
[zk: localhost:2181(CONNECTED) 12] create -s /wyl/test2 1234
Created /wyl/test20000000001
[zk: localhost:2181(CONNECTED) 13] create /wyl/test3 1234
Created /wyl/test3
[zk: localhost:2181(CONNECTED) 14] create /wyl/test4 1234
Created /wyl/test4
[zk: localhost:2181(CONNECTED) 15] create -s /wyl/test5 1234
Created /wyl/test50000000004
[zk: localhost:2181(CONNECTED) 16] ls /
[jodis, dolphin, codis3, wyl, zookeeper]
[zk: localhost:2181(CONNECTED) 17] ls /wyl
[test4, test0000000000, test20000000001, test3, test50000000004]