Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。
Zookeeper工作机制
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负
责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化
Zookeeper将负责通知已经在Zookeeper上注册的观察者做出相应的反应
Zookeeper = 文件系统 + 通知机制
Zookeeper的特点
Zookeeper的数据模型
应用场景
提供的服务包括:
(1) 统一命名服务:在分布式环境下,经常需要对应用/服务进行统一命名,便于识别
(2) 统一配置管理
(1) 分布式环境下,配置文件同步非常常见
1) 一般要求一个集群中,所有节点的配置信息是一致的
2) 对配置文件修改后,希望能够快速同步到各个节点上
(2) 配置管理可交由Zookeeper实现
1) 可将配置信息写入Zookeeper上的一个Znode
2) 各个客户端服务器监听这个Znode
3) 一旦Znode中的数据修改,Zookeeper将通知各个客户端服务器
(3) 统一集群管理
(1) 分布式环境中,实时掌握每个节点的状态很重要
1) 可根据节点实时状态做出一些调整
(2) Zookeeper可以实现实时监控节点状态变化
1) 可将节点信息写入Zookeeper上的一个Znode
2) 监听这个Znode可获它的实时状态变化
(4) 服务器节点动态上下线通知
(5) 软负载均衡
在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求
Zookeeper安装(单点安装)
1.安装前准备
(1) 安装JDK
(2) 拷贝Zookeeper安装包到Linux系统上
(3) 解压到指定目录
~]# rz // 上传zookeeper-3.3.3.tar.gz软件包
~]# tar zxvf zookeeper-3.3.3.tar.gz -C /app
app]# cd zookeeper-3.3.3
2.配置修改
(1) 将/app/zookeeper-3.3.3/conf这个路径下的zoo.sample.cfg修改为zoo.cfg;
conf]# mv zoo.sample.cfg zoo.cfg
(2) 打开zoo.cfg文件,修改dataDir路径,修改如下内容
conf]# mkdir -pv /app/zookeeper/data
conf]# vim zoo.cfg
dataDir=/app/zookeeper/data //zookeeper存储数据的目录
3.操作Zookeeper
(1) 启动Zookeeper
conf]# cd /app/zookeeper-3.3.3/bin
bin]# ./zkStart.sh start
(2) 启动Zookeeper客户端
bin]# ./zkCli.sh
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] quit
Zookeeper配置参数介绍
ticktime=2000 // 心跳针(毫秒)
initLimit=10 // 10个心跳针,Leader和Follower刚开始通信时的最大延时时间
syncLimit=5 // 5个心跳针,leader和follower的通信(集群正常启动后的通信)
dataDir=/app/zookeeper/data //zookeeper存储数据的目录
clientPort=2181 // 客户端连接端口
Zookeeper内部原理
1.选举机制
1) 半数机制: 集群中半数以上的机器存活则集群可用。所以Zookeeper适合安装奇数台服务器
2) Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是
有一个节点为Leader,其他则为Follower;Leader是通过内部的选举机制临时产生的
3) 以一个简单的例子来说明整个选举过程
假设有5台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就
是没有什么历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依次启动;
Zookeeper节点类型
持久: 客户端和服务器端断开连接后,创建的节点不删除
(1) 持久化目录节点:客户端与Zookeeper断开连接后,该节点依旧存在
(2) 持久化顺序编号目录节点:客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序
短暂: 客户端和服务器端断开连接后,创建的节点自己删除
(1) 临时目录节点:客户端与Zookeeper断开连接后,该节点被删除
(2) 临时顺序编号目录节点:客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
Zookeeper分布式安装
1.集群规划
在hadoop1、hadoop2、hadoop3三个节点上部署Zookeeper
2.解压安装
(1) 解压Zookeeper安装包到/app目录下
~]# tar zxvf zookeeper-3.3.3.tar.gz -C /app
(2) 编写同步数据脚本(前提要已经做了免密)
vim /usr/bin/xsync
#!/bin/bash
#判断是否有传入参数
pcount=$#
if (($pcount==0));then
echo "Please input arg!" && exit 2;
fi
#取参数的文件名
f1=$1
fname=`basename $fname`
echo fname=$fname
#取参数的绝对路径
pdir=`cd -P $(dirname $f1)`
echo pdir=$pdir
#获取当前用户名称
user=`whoami`
#循环,这里host根据自己的节点数和主机名设置
for((host=1;host<=3;host++))
do
echo --------------- hadoop$host ----------------
rsync -rvl $pdir/$fname $user@node$host:$pdir
done
~]# chmod +x /usr/bin/xsync
(2) 同步/app/zookeeper-3.3.3目录内容到hadoop2,hadoop3上
~]# xsync /app/zookeeper-3.3.3
(3) 编辑同步命令脚本
~]# vim /usr/bin/xcall
#!/bin/bash
pcount=$#
if (($pcount==0));then
echo "Please input arg!" && exit 2;
fi
user=`whoami`
echo -------------localhost----------
$@
for ((host=1;host<=3;host++))
do
echo ----------node$host---------
ssh $user@node$host $@
done
~]# chmod +x /usr/bin/xcall
(4) 同时在服务器上创建zookeeper数据存储目录
~]# xcall mkdir -pv /app/zookeeper/data
3.配置服务器编号
(1) 在/app/zookeeper/data目录下创建一个myid的文件
~]# vim /app/zookeeper/data/myid //在各个主机都需更改,编号不允许相同,最好按照顺序
1
.....
4.配置zoo.cfg文件
增加如下配置
~]# vim /app/zookeeper-3.3.3/conf/zoo.cfg
server.1=hadoop1:2888:3888
server.2=hadoop2:2888:3888
server.3=hadoop3:2888:3888
2888: leader和follower的通信的端口,传递复本信息
3888: leader和follower的通信的端口,选举时使用的端口
~]# xsync /app/zookeeper-3.3.3/conf/zoo.cfg
5.集群操作
~]# cd /app/zookeeper-3.3.3/bin
bin]# ./zkServer.sh start
bin]# ./zkServer.sh status //只启动一台就查看状态就失败是正常的,因为集群中没有达到半数以上
Zookeeper_Shell命令操作
1.启动客户端
bin]# ./zkCli.sh
2.显示所有命令
[zk: localhost:2181(CONNECTED) 0] help
ZooKeeper -server host:port cmd args
stat path [watch]
set path data [version]
ls path [watch]
delquota [-n|-b] path
ls2 path [watch]
setAcl path acl
setquota -n|-b val path
history
redo cmdno
printwatches on|off
delete path [version]
sync path
listquota path
get path [watch]
create [-s] [-e] path data acl
addauth scheme auth
quit
getAcl path
close
connect host:port
3.查看当前Znode中包含的内容
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
4.查看当前Znode详细的数据
[zk: localhost:2181(CONNECTED) 2] ls2 /
[zookeeper, test]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x400000002
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2
5.创建两个普通的节点
[zk: localhost:2181(CONNECTED) 3] create /shuihu 108
Created /shuihu
[zk: localhost:2181(CONNECTED) 4] ls /
[zookeeper,shuihu]
[zk: localhost:2181(CONNECTED) 5] create /shuihu/baozitou "linchong"
Created /shuihu/baozitou
6.获取数据
[zk: localhost:2181(CONNECTED) 6] get /shuihu/baozitou
linchong
cZxid = 0x40000000b
ctime = Tue Mar 12 10:43:13 CST 2019
mZxid = 0x40000000b
mtime = Tue Mar 12 10:43:13 CST 2019
pZxid = 0x40000000b
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
7.创建临时节点
[zk: localhost:2181(CONNECTED) 7] create -e /shuihu/jishiyu "songjiang"
Created /shuihu/jishiyu
[zk: localhost:2181(CONNECTED) 8] ls /shuihu
[baozitou, jishiyu]
// 当客户端断开连接后再重新连接会发现"jishiyu"已经被删除了
8.创建带有序号的节点
[zk: localhost:2181(CONNECTED) 9] create -s /shuihu/xingzhe "wusong"
Created /shuihu/xingzhe0000000003
[zk: localhost:2181(CONNECTED) 10] ls /shuihu
[baozitou, xingzhe0000000003]
9.修改节点值
[zk: localhost:2181(CONNECTED) 11] set /shuihu/baozitou "hha"
cZxid = 0x40000000b
ctime = Tue Mar 12 10:43:13 CST 2019
mZxid = 0x400000015
mtime = Tue Mar 12 10:52:22 CST 2019
pZxid = 0x40000000b
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 12] get /shuihu/baozitou
"hah"
cZxid = 0x40000000b
ctime = Tue Mar 12 10:43:13 CST 2019
mZxid = 0x400000015
mtime = Tue Mar 12 10:52:22 CST 2019
pZxid = 0x40000000b
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
10.节点的值的变化监听
hadoop2:
[zk: localhost:2181(CONNECTED) 0] get /shuihu watch
hadoop3:
[zk: localhost:2181(CONNECTED) 0] set /shuihu "heh"
hadoop2:
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/shuihu // 变化提示只提醒一次
11.节点的子节点变化监听(路径变化)
hadoop2:
[zk: localhost:2181(CONNECTED) 0] ls /shuihu watch
hadoop3:
[zk: localhost:2181(CONNECTED) 0] create /shuihu/test "watch"
hadoop2:
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/shuihu
12.删除节点
[zk: localhost:2181(CONNECTED) 0] delete /shuihu/test
[zk: localhost:2181(CONNECTED) 1] ls /shuihu
[baozitou, xingzhe0000000003]
Stat结构体
(1) czxid-创建节点的事务zxid
每次修改Zookeeper状态都会收到一个zxid形式的时间戳,也就是Zookeeper的事务ID
事务ID是Zookeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid小于zxid2,那么zxid1在zxid2之前发生
(2) ctime-znode被创建的毫秒数(从1970年开始)
(3) mzxid-znode最后更新的事务ID
(4) mtime-znode最后修改的毫秒数(从1970年开始)
(5) pZxid-znode最后更新的子节点zxid
(6) cversion-znode子节点变化号,znode子节点修改次数
(7) dataversion-znode访问控制列表的变化号
(8) aclVersion-znode访问控制列表的变化号
(9) ephemeralOwner-如果是临时节点,这个是znode拥有者的session id。如果不是则是0
(10) dataLength-znode的数据长度
(11) numChildren-znode子节点数量
Zookeeper监听器原理
(1) 首先有一个main()线程
(2) 在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责连接通信(connect),一个负责监听(listener)
(3) 通过connect线程将注册的监听事件发送给Zookeeper
(4) 在Zookeeper的注册监听器列表中将注册的监听事件记录
(5) Zookeeper监听到有数据或路径变化,就会将这个消息发送给listen线程
(6) listener线程内部调用了process()方法