文章目录
Zookeeper初步认识
Zookeeper介绍
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它是一个为分布式应用提供一致性服务的软件,ZooKeeper和Redis一样,也是C/S结构(分成客户端和服务端)
ZooKeeper提供的常见服务如下 :
- 命名服务 : 按名称标识集群中的节点。它类似于DNS,但仅对于节点。
- 配置管理 :加入节点的最近的和最新的系统配置信息。
- 集群管理 :实时地在集群和节点状态中加入/离开节点。
- 选举算法 : 选举一个节点作为协调目的的leader。
- 锁定和同步服务 : 在修改数据的同时锁定数据。此机制可帮助你在连接其他分布式应用程序(如Apache HBase)时进行自动故障恢复。
- 高度可靠的数据注册表 :即使在一个或几个节点关闭时也可以获得数据。
分布式应用程序提供了很多好处,但它们也抛出了一些复杂和难以解决的挑战。ZooKeeper框架提供了一个完整的机制来克服所有的挑战。竞争条件和死锁使用故障安全同步方法进行处理。另一个主要缺点是数据的不一致性,ZooKeeper使用原子性解析。
ZooKeeper主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集,提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在$zookeeper_home\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。
Zookeeper原理
ZooKeeper是以Fast Paxos算法为基础的,Paxos 算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxos做了一些优化,通过选举产生一个leader (领导者),只有leader才能提交proposer,具体算法可见Fast Paxos。
ZooKeeper的基本运转流程:
1、选举Leader。
2、同步数据。
3、选举Leader过程中算法有很多,但要达到的选举标准是一致的。
4、Leader要具有最高的执行ID,类似root权限。
5、集群中大多数的机器得到响应并接受选出的Leader。
Zookeeper的特性
- 全局数据的一致:每个 server 保存一份相同的数据副本,client 无论链接到哪个 server,展示的数据都是一致的
- 可靠性:如果消息被其中一台服务器接受,那么将被所有的服务器接受
- 顺序性:包括全局有序和偏序两种,全局有序是指如果在一台服务器上消息 a 在消息 b 前发布,则在所有 server 上消息 a 在消息 b 前被发布,偏序是指如果一个消息 b 在消息 a 后被同一个发送者发布,a 必须将排在 b 前面
- 数据更新原子性:一次数据更新要么成功,要么失败,不存在中间状态
- 实时性:ZooKeeper 保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息
在Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据。如果在创建znode时Flag设置为EPHEMERAL,那么当创建这个znode的节点和Zookeeper失去连接后,这个znode将不再存在在Zookeeper里,Zookeeper使用Watcher察觉事件信息。当客户端接收到事件信息,比如连接超时、节点数据改变、子节点改变,可以调用相应的行为来处理数据。Zookeeper的Wiki页面展示了如何使用Zookeeper来处理事件通知,队列,优先队列,锁,共享锁,可撤销的共享锁,两阶段提交。
那么Zookeeper能做什么事情呢?
简单的例子:假设我们有20个搜索引擎的服务器(每个负责总索引中的一部分的搜索任务)和一个总服务器(负责向这20个搜索引擎的服务器发出搜索请求并合并结果集),一个备用的总服务器(负责当总服务器宕机时替换总服务器),,一个web的cgi(向总服务器发出搜索请求)。搜索引擎的服务器中的15个服务器提供搜索服务,5个服务器正在生成索引。这20个搜索引擎的服务器经常要让正在提供搜索服务的服务器停止提供服务开始生成索引,或生成索引的服务器已经把索引生成完成可以提供搜索服务了。使用Zookeeper可以保证总服务器自动感知有多少提供搜索引擎的服务器并向这些服务器发出搜索请求,当总服务器宕机时自动启用备用的总服务器。
分布式应用的优点
- 可靠性 :单个或几个系统的故障不会使整个系统出现故障。
- 可扩展性 :可以在需要时增加性能,通过添加更多机器,在应用程序配置中进行微小的更改,而不会有停机时间。
- 透明性 - 隐藏系统的复杂性,并将其显示为单个实体/应用程序。
分布式应用的挑战
- 竞争条件 :两个或多个机器尝试执行特定任务,实际上只需在任意给定时间由单个机器完成。例如,共享资源只能在任意给定时间由单个机器修改。
- 死锁 :两个或多个操作等待彼此无限期完成。
- 不一致 :数据的部分失败。
安装下载Zookeeper
环境准备
ZooKeeper服务器是用Java创建的,它运行在JVM之上。需要安装JDK 7或更高版本。
安装JDK参考:https://blog.youkuaiyun.com/hjq_ku/article/details/121440377
zookeeper下载地址
https://zookeeper.apache.org/releases.html
上传(安装在Linux系统上)
使用Xftp将下载的ZooKeeper放到自己较为熟悉的目录下
解压zookeeper安装包
- 解压到当前文件夹:tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz
- 解压到指定目录: tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz -C /stu/module
解压得到一个 tar -zxvf apache-zookeeper-3.7.0-bin 文件,嫌弃名字太长 mv apache-zookeeper-3.7.0-bin zookeeper3.7.0修改即可
配置与启动
进入apache-zookeeper-3.7.0-bin中的conf目录下
-
修改zoo_sample.cfg名字为zoo.cfg
mv zoo_sample.cfg zoo.cfg
-
配置zoo.cfg
进入编辑模式:vim zoo.cfg 得到如下,修改该位置即可
# the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just 说明不建议使用 /tmp/zookeeper 这是一个临时目录,因此修改为我们自己存放的目录 # example sakes. #修改前 #dataDir=/tmp/zookeeper #修改为 dataDir=/home/wp990/zookeeper/zkData
-
启动服务端
bin/zkServer.sh start
jps 查看进程
[root@192 zookeeper3.7.0]# jps 4963 Jps 4940 QuorumPeerMain 此处多了一个QuorumPeerMain进程
-
启动客户端
[root@192 zookeeper3.7.0]# bin/zkCli.sh
注:启动客户端不需要start,启动服务端需要
查看根节点: ls /
-
退出zk
quit
-
查看zk的状态
bin/zkServer.sh status
解读配置参数
进入配置文件(zoo.cfg)
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/wp990/zookeeper/zkData
clientPort=2181
可以看到只有五个参数没有被注释,因此解读这五个参数即可
-
tickTime=2000
表示通信心跳时间。zookeeper服务器与客户端(服务器)的心跳时间,单位毫秒
-
initLimit=10
Leader和Follower初始连接时能容忍的最多心跳次数(tickTime的数量)
-
syncLimit=5
Leader和Follower经过初始连接后最大任容的同步通信时限,Leader和Follower之间通信时间如果超过sysncLimit*tickTime,Leader认为Follwer死亡,从服务器列表中删除Follower
-
dataDir=/home/wp990/zookeeper/zkData
保存zk中的数据,注意:默认的时temp目录,容易被Linux系统定期删除,所以一般不用默认的temp目录
-
clientPort=2181
客户端连接端口,通常不做修改
操作命令
ZooKeeper服务器的常见操作命令有:
-
重命名conf中的文件
zoo_sample.cfg->zoo.cfg
-
启动zk服务器
./bin/zkServer.sh start ./conf/zoo.cfg
-
查看zk服务器的状态
./bin/zkServer.sh status ./conf/zoo.cfg
-
停止zk服务器
./bin/zkServer.sh stop ./conf/zoo.cfg
-
创建节点
create /test1
-
创建子节点
create /test1/son1
-
节点添加数据
create /test2 aaa (创建test2节点并添加数据aaa)
-
获取当前节点
ls /
-
获取节点数据
get /test2
-
删除节点的内容
delete /test2
-
删除包括节点的所有内容
deleteall /test2
注:可以输入一条错误命令,可以显示所有的命令以及格式
内部的数据模型
ZooKeeper的数据结构,跟Unix文件系统非常类似,可以看做是一颗树,每个节点叫做ZNode。每一个节点可以通过路径来标识。zk中的数据就是保存在节点上的。
Znode分为两种类型:
- 临时/短暂(Ephemeral):当客户端和服务端断开连接后,所创建的Znode(节点)会自动删除
- 持久(Persistent):当客户端和服务端断开连接后,所创建的Znode(节点)不会删除
znode的结构
zk中的znode,包含了四个部分
-
dat:保存数据
-
acl:权限,定义了什么样的用户能够操作这个节点,且能够进行怎样的操作
- c:create创建权限,允许在该节点下创建子节点
- w:write更新权限,允许更新该节点的数据
- r: read读取权限,允许读取该节点的内容以及子节点的列表信息
- d: delete 癣除权限,允许删除该节点的子节点
- a:admin管理者权限,允许对该节点进行acl权限设置
-
child:当前节点的子节点
-
stat:描述当前znode的元数据
查看znode节点的所有信息
get -s /test2
zonde节点类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HPpH96h9-1650258628713)(img/zookeeper节点.png)]
持久节点
创建出来的节点,在会话结束后依然存在,保存数据(默认创建节点的方式)
create /test3
持久序号节点
创建出来的节点,根据先后顺序,会在节点之后带上一个数值,越后执行的数值越大,适用于分布式锁的应用场景-单调递增
create -s /test3
临时节点
临时节点在会话结束后,自动删除,通过这个特性,zk可以实现服务注册与发现的效果
create -e /test4
临时序号节点
创建出来的临时节点,根据先后顺序,会在节点之后带上一个数值,越后执行的数值越大,适用于临时的分布式锁
create -e -s /test5
Container节点
Container节点(3.53版本新增):Container容器节点,当容器中没有任何子节点,该容器节点会自动被zk定期删除(60s)
create -c /testContainer
create -c /testContainer/son1
create -c /testContainer/
过一段时间testContainer节点消失
TTL节点
可以指定节点的到期时间,到期后被zk定时删除,只能通过系统配置zookeeper.extendedTypesEnabled=true开启
zk的数据持久化
zk的数据是运行在内存中,zk提供了两种持久化
-
事务日志
zk把执行的命令以日志形式保存在dataLogDir指定的路径中的文件中(如果没有指定dataLogDir,则按dataDir指定的路径)
-
数据快照
zk会在一定的时间间隔内做一次内存数据的快照,把该时刻的内存数据保存在快照的文件中
zk通过两种形式的持久化,在恢复时先恢复快照文件中的数据到内存中,再用日志文件中的数据做增量恢复,这样的恢复速度更快
Zookeeper服务端的使用
启动 ZK 服务
sh bin/zkServer.sh start
查看 ZK 服务状态
sh bin/zkServer.sh status
停止 ZK 服务
sh bin/zkServer.sh stop
sh bin/zkServer.sh stop
重启 ZK 服务: sh bin/zkServer.sh restart
ZooKeeper客户端的使用
创建节点
- 创建持久化节点
- 创建持久化序号节点
- 创建临时节点
- 创建临时序号节点
- 创建容器节点
如上
查询节点
-
普通查询
- ls path 查看某个路径下目录列表 ( / 是根节点)
create /test7/son1/son2 ls test7 输出:[son1]
-
ls2 / 命令: 显示了数据的一些状态信息
-
递归查询当前节点以及子孙节点
ls -R /test7 输出: /test7 /test7/son1 /test7/son1/son2
-
查询节点相应信息
ls -s
- cZxid:创建节点的事务ID
- mzxid:修改节点的事务ID
- pzxid:添加和删除子节点的事务ID
- ctime:节点创建的时间
- mtime:节点最近修改的时间
- dataVersion:节点内数据的版本,每更新一次数据,版本会+1aclVersion:此节点的权限版本
- ephemeralOwner:如果当前节点是临时节点,该值是当前节点所有者的session id。如果节点不是临时节点,则该值为零。
- dataLength:节点内数据的长度
- numChildren: 该节点的子节点个数
删除节点
-
普通删除
-
删除节点内容
delete /test1
-
删除包括节点目录的所有内容(递归删除)
deleteall /test2
-
-
乐观锁删除
权限设置
-
注册当前会话的账号和密码
addauth digest xiaowang:123456
-
创建节点并设置权限
create /test-node abc auth:xiaowang:123456:cdwra
-
在另外一个会话中必须先使用账号密码,才能拥有操作该节点的权限
监听器
原理
- 首先要有一个main()主线程
- 在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener)
- 通过connect线程将注册的监听事件发送给Zookeeper
- 在Zookeeper的注册监听器列表中将注册的监听器事件添加到列表中
- Zookeeper监听到数据或者路径变化,就会将这个消息发送给listener线程
注:一次注册监听只监听一次
实战
监控数据
语法: get -w 节点
[zk: localhost:2181(CONNECTED) 8] get -w /stu
aa
[zk: localhost:2181(CONNECTED) 9] set /stu bbb
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/stu
[zk: localhost:2181(CONNECTED) 10] [root@192 zookeeper3.7.0]#
[root@192 zookeeper3.7.0]# set /stu ccc
第二次修改数据不会触发监听,只注册一次监听只能触发一次
监控路径
语法: ls -w 路径
[zk: localhost:2181(CONNECTED) 3] ls -w /sti
Node does not exist: /sti
[zk: localhost:2181(CONNECTED) 4] ls -w /stu
[]
[zk: localhost:2181(CONNECTED) 5] delete /stu
WATCHER::
WatchedEvent state:SyncConnected type:NodeDeleted path:/stu
[zk: localhost:2181(CONNECTED) 6]
搭建zk集群
- 安装并添加myid文件
安装多台zk服务器,每一台的安装步骤如上,在此基础上,在zkData的目录下创建一个myid文件
vim myid
在myid中添加自己的id ,如1
比如三台服务器分别对应的myid文件内容分别为1,2,3
- 修改zoo.cfg文件
打开服务器自己的zoo.cfg文件添加如下配置
##########
server.2 = hadoop102:2888:3888
server.3 = hadoop102:2888:3888
server.4 = hadoop102:2888:3888
配置参数解读
格式: server.A = B:C:D
A :
是一个数字,表示这个是第几号服务器
集群模式下配置一个文件myid,这个文件在zkData(存放zk保存的数据目录)目录下下,这个文件里面有一个数据就是A值,zk启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较而判断到底是哪个server
B:
是这个服务器的地址
C:
是这个服务器Follower与集群中的Leader服务器交换信息的端口
D:
是万一哪个集群中的Leader服务器挂掉了,需要一个端口来重新进行选举,选举出一个新的Leader。而这个端口就是来执行选举时服务器相互通信的端口
ZK四种工作状态
LOOKING
寻找 Leader 状态。当服务器处于该状态时,它会认为当前服务器没有 Leader,因此需要进入 Leader 选举状态。
FOLLOWING
跟随者状态。表明当前服务器角色是 Follower。
LEADING
领导者状态。表明当前服务器角色是 Leader。
OBSERVING
观察者状态。表明当前服务器角色是 Observer。
zk选举机制
选举机制价绍
zk选举机制是以zk集群为前提
zookeeper是按照Paxos算法进行选举的,这个算法也称之为半数选举机制。
所有节点都有投票权,当一个几点票数过半,这个节点就是leader。
zookeeper机制规定,当有新的节点加入时,没有选举出leader时之前票数作废,重新投票。
leader产生后,其他节点投票给leader。
- 半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
- Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。
全新的集群选举
即第一次启动的集群,无数据状态下的选举
假设服务器1,2,3,4,5。。。。的myid都是设置依次递增
第一台服务器1启动:
发起一次选举,服务器1会先头自己一票,此时服务器1的票数一票,不够半数以上(三票),选举无法完成,服务器1的状态保持为LOOKING
第二台服务器2启动:
再发起一次选举,服务器1和服务器2分别投自己一票并交换选票信息,此时服务器一发现服务器2的myid比自己目前投票推荐的(服务器1)大,更改选票为推荐服务器2,此时服务器1票数0票,服务器2票数2票,没有半数以上的结果,选举无法完成,服务器1和服务器2状态保持LOOKING
第三台服务器3启动:
再次发起一次选举,此时服务器1和2都会因为myid更改选票为服务器3,此时选举结果服务器3有三票,票数超过半数通过,服务器3即为Leader。服务器1,2状态为FOLLOWING,服务器3状态为LEADING
第四台服务器4启动:
再次发起一次选举,此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息,交换选票信息结果:,服务器3为3票,服务器4为1票,少数服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING
第五台。。。第六台。。。。第七台。。。。启动,任然同理,第三台是老大
非全新的集群选举
在数据恢复下的选举,初始化的时候,是按照上述选举方式集进行选举,但是当遇到zookeeper运行一段时间后,有机器宕机,重新选举时,选举过程就相当复杂了
认识一些基础标识符
SID:服务器ID,用来唯一标识一台zookeeper集群中的机器,每台机器不能重复,和myid一致
ZXID:事务ID,ZXID是一个事务,用来标识一次服务器的状态的变更,在某一个时刻,集群中的每一台机器的ZXID值不一定完全一致,这和Zookeeper服务器对于客户端“更新请求”的处理逻辑有关
Epoch:逻辑时钟,每个Leader任期的代号,没有Leader时同一轮投票过程中的逻辑时钟值是相同的,每投完一次票这个数据就会增加
宕机 的两种情况
-
宕机的是非Leader
集群中存在Leader,机器会尝试去选举Leader时,被告知当前服务器的Leader信息,对于该机器来说仅仅需要和Leader机器建立连接,并进行状态同步即可
-
宕机的是Leader
即集群不存在Leader,则会使用如下Leader选举机制
- 存活的其他机器,EPOCH大的直接胜出
- XPOCH相同,事务ID大的胜出
- 事务ID相同,服务器ID大的胜出
集群的启动与关闭脚本
在上述启动和关闭脚本我们是去一台一台关闭,少量的服务器可行,当时当我们存在几百台几千台的服务器,我们仍然采取一台一台开启关闭?显然是费时费力的不必要工作,因此我们需要一个脚本来进行对集群的关闭和开启
zk.sh脚本框架
#!/bin/bash
case $1 in
"start"){
for i in hadoop102 hadoop103 hadoop104
do
echo -----------------zookeeper启动--------------------
ssh $i "/home/wp990/zookeeper/zookeeper/zookeeper3.7.0/bin/zkServer.sh start"
done
}
;;
"stop"){
for i in hadoop102 hadoop103 hadoop104
do
echo -----------------zookeeper启动--------------------
ssh $i "/home/wp990/zookeeper/zookeeper/zookeeper3.7.0/bin/zkServer.sh stop"
done
}
;;
"status"){
for i in hadoop102 hadoop103 hadoop104
do
echo -----------------zookeeper启动--------------------
ssh $i "/home/wp990/zookeeper/zookeeper/zookeeper3.7.0/bin/zkServer.sh status"
done
}
;;
esac
将该文件变为可执行
chmod 777 zk.sh