基本概念
角色
zookeeper 集群中的节点共有三种角色,每个节点同时只能是一种角色。集群中的所有机器通过一个 Leader 选举过程来选定一台被称为 Leader 的机器。
Leader:接受所有 Follower 的提案请求并统一协调发起提案的投票,负责与所有的 Follower 进行内部的数据交换
Follower:直接为客户端服务并参与提案的投票,同时与 Leader 进行数据交换
Observer:直接为客户端服务但不参与提案的投票,同时也与 Leader 进行数据交换会话
zookeeper 中客户端启动时会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期就开始了,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向服务器发送请求并接受响应,还能够接收来自服务器的 watch 事件通知。节点
一般在分布式语境下的节点是指组成集群的每一台服务器,在 zookeeper 中还有另外一层意思,称之为数据节点(ZNode)。
zookeeper 的整个名字空间的结构是层次化的,和 Linux 文件系统结构相似,是一颗树。名字空间的层次由斜杠(/)来进行分割,在名称空间里面的每一个节点的名字空间由这个结点的路径来确定。
每个 ZNode 上都会保存自己的数据内容,同时还会保存一系列属性信息。版本
对于每个 ZNode ,zookeeper 都会为它维护一个叫 Stat 的数据结构,Stat 中记录了 ZNode 的三个数据版本,version(当前ZNode数据内容的版本号)、cversion(当前ZNode子节点的版本号)、aversion(当前ZNode的ACL变更版本号)watcher
zookeeper 允许用户在指定节点上注册一些 watcher,并且在特定事件触发的时候,zookeeper 服务端会将事件通知到感兴趣的客户端,该机制是 zookeeper 实现分布式协调服务的重要特性。
客户端命令
这里列出常用的客户端命令,所谓客户端命令指使用 zkCli 连接到 zookeeper 服务器之后使用的命令,zkCli 连接的语法如下:
zkCli -server host:port cmd args
zkCli 是客户端可执行文件名,根据具体操作系统环境可能是 zkCli.sh 或 zkCli.cmd
host 是服务器IP或域名,port 是服务器端口号,如果有多个服务器地址则用逗号分隔
cmd 是具体命令、args 是命令的参数,也可以连接上服务器之后再执行命令。
查看节点
ls /path
查看名为 /path 的子节点,但只能查看指定节点下的第一级的所有子节点。
ls2 /path
查看名为 /path 的子节点,并且能看到更新次数等属性信息。创建节点
create [-s] [-e] /path data
创建一个名叫 /path 的节点,并包含数据 data。加上 -s 表示创建的是顺序节点,加上 -e 表示创建的是临时节点,如果都不加则默认为创建持久节点。删除节点
delete /path
删除名为 /path 的节点设置节点数据
set /path data
设置名为 /path 的节点的数据为 data返回节点数据
get /path
返回名为 /path 的节点的数据和属性信息强制同步数据
sync /path
将名为 /path 的节点强制同步为最新的数据帮助信息
help
帮助命令,显示客户端支持的命令及语法格式退出
quit
退出当前客户端,会话结束。
运维命令
zookeeper 提供了一些四字命令用于获取 zookeeper 服务端的当前状态及相关信息,这些命令在系统运维时很有用。用户在客户端可以通过 telnet 或 nc 向zookeeper 提交相应的命令,比如 nc 方式:
echo cmd|nc host port
cmd 是具体的命令(因为一般是四个字母所以又叫做四字命令),host 是zookeeper 服务器 IP 地址或域名,port 是 zookeeper 端口号
conf
显示服务配置的详细信息,比如数据文件目录、日志文件目录、间隔单位时间、选举算法、选举端口等。cons
列出所有连接到服务器的客户端的完全的连接/会话的详细信息。包括”接受 / 发送”的包数量、会话 id 、操作延迟、最后的操作执行等。crst
重置所有连接。dump
列出未经处理的会话和临时节点。envi
显示关于服务器环境的详细信息,比如 zookeeper 版本、操作系统版本、jdk 地址等。reqs
列出未经处理的请求。ruok
测试服务是否处于正确状态。如果确实如此,那么服务返回“imok ”,否则不做任何相应。stat
输出关于性能和连接的客户端的列表。wchs
列出服务器 watch 的详细信息。wchc
通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。wchp
通过路径列出服务器 watch 的详细信息,它的输出是一个与 session 相关的路径。
上面列出的是一些常用的四字命令,更详细信息可以参考zookeeper的官方文档,里面的【ZooKeeper Commands】一节有具体介绍。
特性
- 一致性
zookeeper 很好地保证在分布式高并发情况下节点的创建一定是全局唯一性,即保证客户端无法重复创建一个已经存在的数据节点。
根据 CAP 理论,分布式系统只能满足一致性(Consistence)、可用性(Availability)、分区容错性(partitioning)三项中的两项而不可能满足全部三项。对于 zookeeper 来说,其实现了 A 可用性、P 分区容错性、C 中的写入强一致性,丧失的是 C 中的读取一致性。
更进一步解释,zookeeper 的一致性保证包括以下几点:
- 顺序一致性
一个客户端的更新将按照发送的顺序被写入到服务端。 - 原子性
更新要么成功,要么失败,没有部分结果。 - 单一系统镜像
客户端只会连接 host 列表中状态最新的那些实例。如果正在连接到的实例挂了,客户端会尝试重新连接到集群中的其他实例,那么此时滞后于故障实例的其它实例都不会接收该连接请求,只有和故障实例版本相同或更新的实例才接收该连接请求。 - 持久性
写操作完成之后将会被持久化存储,不受服务器故障影响。 - 并发一致性
zookeeper 并不保证在某个时刻两个不同客户端具有一致的数据视图,因为网络的延迟一个客户端可能在另一个客户端得到修改通知之前进行更新。如果不同客户端读取到相同的值很重要,那么客户端应该在执行读取操作之前调用 sync() 方法,使得读操作的连接所连的 zookeeper 实例能与 leader 进行同步,从而能读到最新的类容。
watcher 监听
客户端如果对一个节点注册 watcher 监听,那么当该节点的内容或其子节点发生变更时,zookeeper 服务器会向订阅的客户端发送变更通知。临时节点
对在 zookeeper 上创建的临时节点,一旦客户端与服务器之间的会话失效,那么该临时节点就被自动清除。顺序节点
客户端申请创建该节点时 zookeeper 会自动在节点路径末尾添加递增序号
应用场景
数据订阅发布
将应用中的配置信息放在 zookeeper 中集中管理。应用在启动时主动到zk服务端进行一次配置信息的获取,同时在指定节点注册一个 watcher 监听。这样只要配置信息发生变更,服务端都会实时通知到所有订阅的客户端。域名服务
将域名配置信息放在 zookeeper 上,对外提供一套域名注册、域名解析、域名可用性检测的服务。基于此提供一套动态的 DNS 服务。全局唯一 ID
可以利用顺序节点的特性生成全局唯一的 ID。分布式协调通知
利用 watcher 监听实现系统间的协调和通知,从而实现数据变更的处理。不同客户端都对 zookeeper 上同一个数据节点进行 watcher 注册,如果数据节点发生变化,那么所有订阅的客户端都能受到通知。Master 选举
利用 zookeeper 创建节点时的强一致性,由客户端集群定时往 zookeeper 上创建同一个名字的临时节点。在这个过程中只有一个客户端能够创建成功,那么该客户端就成了 Master,同时其他没有创建成功的客户端都在该节点注册一个节点变更的 watcher,用于监控当前 Master 机器是否存活,一旦发现 Master 挂掉其余客户端重新进行 Master 选举。分布式锁
排他锁
利用强一致性,将 zookeeper 上的一个临时节点表示为一个排他锁,所有客户端同时创建该节点,最终只有一个客户端能创建成功,那么就认为该客户端获得了锁,同时注册该节点的 watcher 监听。当移除该节点就认为释放了锁。共享锁
利用强一致性,将 zookeeper 上的一个临时顺序节点表示为一个共享锁,并注册同级子节点的 watcher 监听。判断读写顺序时根据不同需求关注比自己序号小的同级子节点类型。