您现在的位置是:首页 >技术教程 >Zookeeper网站首页技术教程
Zookeeper
简介Zookeeper
Zookeeper
- Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就会通知已经在Zookeeper上注册的那些观察者
数据结构
节点(ZNode)类型
- 节点分为两类,共四种
- 持久无序节点、持久有序节点
- 临时无序节点、临时有序节点
- 创建节点时,如果指定为有序号,则zookeeper会自动在znode名称后附加一个值
节点(ZNode)信息
- czxid:创建节点的事务ID(zxid)
- ctime:znode 被创建的毫秒数(从 1970 年开始)
- mzxid:znode 最后更新的事务 zxid
- mtime:znode 最后修改的毫秒数(从 1970 年开始)
- pZxid:znode 最后更新子节点的 zxid
- cversion:znode 子节点变化号,znode 子节点修改次数
- dataversion:znode 数据变化号
- aclVersion:znode 访问控制列表的变化号
- ephemeralOwner:如果是临时节点,这个是 znode 拥有者的 session id,如果不是临时节点则是 0
- dataLength:znode 中的数据长度,不包括znode子节点
- numChildren:znode 子节点数量
Zookeeper配置修改
- 从官网下载 bin 文件
配置参数解读
- tickTime = 2000:通信心跳时间,Zookeeper服务器与服务器之间,以及与客户端之间的心跳检测时间,单位毫秒
- 即每隔 2s ,Zookeeper服务器与服务器之间,以及与客户端之间发送一次心跳检测
- initLimit = 10:LF初始通信时限,即在 20s 内能够彼此连接上,就算连接成功了
- syncLimit = 5:LF同步通信时限,即每次同步通信,Leader要求能在10s内得到Follower回复
- dataDir:保存Zookeeper中的数据
- 注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录
- clientPort = 2181:zkServer用于接受客户端连接的端口,通常不做修改
Zookeeper 常用指令
对客户端/服务端的操作
- 需要注意的是zookeeper的客户端和服务器端启动的指令区别
- zkServer的启动,
bin/zkServer.sh start
- zkServer的停止,
bin/zkServer.sh stop
- zkClient的启动,
bin/zkCli.sh
,默认连接的是当前本地的zkServer- zkClient连接指定机器上的zkServer,
bin/zkCli.sh -server hadoop102:2181
hadoop102 为另外一台机器的域名 - zkClient的停止,
quit
- zkClient连接指定机器上的zkServer,
help
显示所有操作命令- 查看当前zkServer状态
bin/zkServer.sh status
对 ZNod 的操作
- 查看当前 znode 的详细信息,
ls -s /
- 查看指定节点(/sanguo)的信息,
ls -s /sanguo
- 创建znode
- 创建持久化不带序号的znode,
create /sanguo "diaochan"
,/sanguo
是被创建的节点,diaochan
是节点的内容 - 创建持久化带序号的znode,
create -s /sanguo/weiguo/zhangliao "zhangliao"
,/sanguo/weiguo/zhangliao
是一个子节点,上层有两个父节点,zhangliao
是节点的内容
如果上层父节点中没有序号节点,序号从 0 开始依次递增 如果上层父节点中 2 个节点都是序号节点,则再排序时从 2 开始,以此类推 [zk: localhost:2181(CONNECTED) 2] create -s /sanguo/weiguo/zhangliao "zhangliao" Created /sanguo/weiguo/zhangliao0000000000 [zk: localhost:2181(CONNECTED) 3] create -s /sanguo/weiguo/zhangliao "zhangliao" Created /sanguo/weiguo/zhangliao0000000001 [zk: localhost:2181(CONNECTED) 4] create -s /sanguo/weiguo/xuchu "xuchu" Created /sanguo/weiguo/xuchu0000000002
- 创建临时不带序号的znode ,
create -e /sanguo/wuguo "zhouyu"
,对于不带序号的znode ,不允许重复执行create -e /sanguo/wuguo "zhouyu"
,因为znode 的名字(路径)不允许重复 - 创建临时带序号的znode ,
create -e -s /sanguo/wuguo "zhouyu"
- 创建持久化不带序号的znode,
- 获得znode 的值和详细信息
get -s /sanguo
- 修改节点数据值,
set /sanguo/weiguo "simayi"
总结
- 指令后面带参数
-w
,表示执行指令的同时,开启监听器(watch)
Zookeeper 集群
- Zookeeper集群只有两种角色:Leader、Follower
- 作为Leader的zkServer,通过Zookeeper选举机制选出,有且仅有一个
- 每次对节点的C/U/D操作都是带有事务的,这种请求就是事务请求,标识该事务请求的事务ID就是zxid
- Zxid 是一个 64 位的数字,它高 32 位是 Epoch 用来标识朝代变化,比如每次选举 Epoch 都会改变低, 32 位用于递增计数
- 每个节点都会维护与自身相关的 zxid
- zxid达到最大值(64bit)后会触发集群重新选举,然后zxid会变为0
Zookeeper选举机制
- 不管是否为第一次启动,最核心的要求就是,要成为Leader必须获得超过半数的集群中其它zkServer的投票
- 超过半数,就是为了防止脑裂的发生
集群的第一次启动
集群非第一次启动
- 非第一次启动时的Leader选举和第一次启动时的Leader选举有类似的地方,也有不同的地方
- 类似的地方在于
- 各个zkServer总是先倾向于先把票投给自己,然后彼此交换投票信息,最后获得超过一半票数的zkServer成为Leader
- 如果没有zkServer能获得超过一半票数,集群此时不能对外提供服务,zkServer均处于LOOKING状态
- 不同的地方在于
- 第一次启动时,zkServer之间彼此交换投票信息后,是根据myid即sid判断是否要更改投票,然后把票投给sid最大的zkServer
- 而非第一次启动时,zkServer之间交换了投票信息后,先比较的是EPOCH,然后是zxid,最后才是sid,然后把票投给这三项比较中最大的那个胜出zkServer
向Zookeeper集群写入数据
写入请求直接发送给Leader节点
- 写入请求发送给Leader,Leader是集群中事务请求的唯一调度和处理者
- 所以可以直接修改自身的ZNode,同时,Leader发送写入指令给集群中的其它Follower
- Zookeeper集群遵循半数原则,当Leader收到Follower的ACK,并且发送ACK的Follower的数+1(Leader数) 超过集群中所有zkServer数量的一半,本次写入才算成功
- 写入成功后,Leader回复ACK给Client
写入请求直接发送给Follower节点
- 写入请求发送给Follower,Leader是集群中事务请求的唯一调度和处理者
- 所以此时,Follower会将接收到的写入请求转发给Leader,由Leader执行此次的客户端的写入请求
- Leader直接修改自身的ZNode,同时,Leader发送写入指令给集群中的其它Follower
- 依然遵循半数原则,当Leader收到Follower的ACK,并且发送ACK的Follower的数+1(Leader数) 超过集群中所有zkServer数量的一半,本次写入才算成功
- 写入成功后,Leader发送ACK给接收到Client写入请求的Follower,然后该Follower回复ACK给Client
Zookeeper 集群配置
- 首先需要修改配置文件中dataDir的值,新建一个目录专门用于存储Zookeeper中的数据,目录的路径就是dataDir的新值
- 在新指定的dataDir目录中创建一个名称为 myid 的文件,文件中输入数字(上下不要有空行,左右不要有空格)指定当前服务器中zkServer的标识id,意味该数字要求集群中唯一
- 拷贝配置好的 zookeeper 到其他机器上,在其他机器上进行同样的修改,只是改为不同的数字
- 在每个机器的zookeeper 配置文件中新增如下内容,指出当前zkServer集群的id、域名(IP)、通信端口、选举端口
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888
zkServer 集群启动停止脚本
- 设定:3台机器,每台机器的域名分别为hadoop102、hadoop103、hadoop104,3台机器都已经有装好的zookeeper,目录均为 /opt/module/zookeeper-3.5.7
- 在/opt/module/zookeeper-3.5.7/bin目录下,创建脚本文件
vim zk.sh
- 编写脚本内容,如下
#!/bin/bash
case $1 in
"start"){
for i in hadoop102 hadoop103 hadoop104
do
echo ---------- zookeeper $i 启动 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"
done
};;
"stop"){
for i in hadoop102 hadoop103 hadoop104
do
echo ---------- zookeeper $i 停止 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"
done
};;
"status"){
for i in hadoop102 hadoop103 hadoop104
do
echo ---------- zookeeper $i 状态 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh
status"
done
};;
esac
- 增加脚本的执行权限
chmod u+x zk.sh
- zkServer 集群启动脚本
zk.sh start
- zkServer 集群停止脚本
zk.sh stop
监听器
- 客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目录节点增加删除)时,ZooKeeper 会通知客户端
- 监听机制保证 ZooKeeper 保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序
监听器原理
命令行客户端注册watch
- 监听器(watch)仅能使用一次,即zkClient向zkServer注册对某个znode的值或其子节点的变化的watch,zkServer会在被watch的znode的值或其子节点的变化时通知注册该watch的zkClient,然后watch失效,要想再次使用,需要再次注册watch
java客户端注册watch
- 对于java客户端有两种方式注册watch
- 在初始化zkClient与zkServer连接的时候注册watch
- 在获取某个znode的值或子节点信息的时候注册watch
- java客户端通过对接口
Watcher
进行实现,接收zkServer的watch通知Watcher
接口中定义了监听的具体事件类型、事件状态,可以监听zkServer的状态、ZNode的状态- 最重要的是
process(WatchedEvent event)
方法,该方法用于接收zkServer的watch通知后实现具体业务逻辑 - 可以通过
process(WatchedEvent event)
方法,实现watch使用后失效<--->再次注册watch
应用场景
- 提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等
统一命名服务
- 利用的是Zookeeper的ZNode数据结构
统一配置管理
- 利用的是Zookeeper的watch监听器机制
统一集群管理
- 利用的是Zookeeper的watch监听器机制与Zookeeper的ZNode数据结构
服务器动态上下线
- 利用的是Zookeeper的watch监听器机制与Zookeeper的ZNode数据结构
软负载均衡
分布式锁
- 所有客户端获取分布式锁都是通过对Zookeeper集群中同一个的ZNode的下添加 or 删除子节点的方式实现
Curator
-
原生的Java API 实现分布式锁的问题
-
Curator 是一个专门解决分布式锁的框架,解决了原生 JavaAPI 开发分布式遇到的问题
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。