文章目录
一、zookeeper概述
Apache ZooKeeper是由集群(节点组)使用的一种服务,用于在自身之间协调并使用鲁棒同步技术维护共享数据。 ZooKeeper本身是一个分布式应用程序,提供用于编写分布式应用程序的服务。
二、zookeeper特点
1)Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
2)集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器。
3)全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
4)更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行。
5)数据更新原子性,一次数据更新要么成功,要么失败。
6)实时性,在一定时间范围内,Client能读到最新数据
三、 zookeeper数据结构
ZooKeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看作是一棵树,每个节点称做一个 ZNode。每一个 ZNode 默认能够存储
1MB 的数据
,每个 ZNode 都可以通过其路径唯一标识
。
四、 应用场景
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
- 统一命名服务
- 统一配置管理
- 统一集群管理
- 服务器节点动态上下线
- 软负载均衡
五、zookeeper安装单机版
1、下载安装包
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz
2、解压、安装到 /opt/software目录下,修改文件名称
[root@ecs-431f-0003 software]# mv apache-zookeeper-3.7.1-bin/ zookeeper
解压目录如下所示:
3、增加环境变量,增加全局访问配置,并使配置文件生效
[root@ecs-431f-0003 zookeeper]# vim /etc/profile
# 设置zookeeper的环境变量
export ZOOKEEPER_HOME=/opt/software/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
[root@ecs-431f-0003 zookeeper]# source /etc/profile
4、修改配置文件
[root@ecs-431f-0003 zookeeper]# mkdir data
[root@ecs-431f-0003 zookeeper]# cd conf/
[root@ecs-431f-0003 conf]# mv zoo_sample.cfg zoo.cfg
[root@ecs-431f-0003 conf]# vim zoo.cfg
修改datadir的路径
5、启动服务
root@ecs-431f-0003 zookeeper]# zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/software/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@ecs-431f-0003 zookeeper]#
6、验证服务
7、启动客户端
[root@ecs-431f-0003 conf]# zkCli.sh
查看根节点下面有一个zookeeper节点
在根节点下面创建一个test节点,在test节点上存储数据hello
查看/test节点中的内容
删除节点
8、退出客户端
[zk: localhost:2181(CONNECTED) 0] quit
9、配置参数解读
1)tickTime = 2000:通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒
2)initLimit = 10:LF初始通信时限
3)syncLimit = 5:LF同步通信时限
Leader和Follower之间通信时间如果超过syncLimit * tickTime,Leader认为Follwer死
掉,从服务器列表中删除Follwer。
4)dataDir:保存Zookeeper中的数据
注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录
5)clientPort = 2181:客户端连接端口,通常不做修改。
六、zookeeper选举机制
1.1 第一次启动
首先现在集群中有5台zookeeper服务选举过程中要满足奇数的原则
选举过程中服务器的状态
LOOKING:
寻找leader状态。当服务器处于该状态时,它会认为当前集群中没有leader,因此需要进去leader选举状态。LEADING:
领导者状态。服务器角色为leaderFOLLOWING:
跟随者状态。服务器角色为follower。OBSERVING:
观察者状态。服务器角色是observer。
(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的myid比自己目前投票推举的(服务器1) 大,更改选票为推举服务器2
。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING。
(3)服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。
服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为 1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;
(5)服务器5启动,同服务器4一样
- SID:
服务器ID
。用来唯一标识一台ZooKeeper集群中的机器,每台机器不能重复
,和myid一致。 - ZXID:事务ID。
ZXID是一个事务ID,用来标识一次服务器状态的变更。在某一时刻,集群中的每台机器的ZXID值不一定完全一致,
这和ZooKeeper服务器对于客户端“更新请求”的处理逻辑有关。 - Epoch:
每个Leader任期的代号
。没有Leader时同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加。
1.2 非第一次启动
(1)当ZooKeeper集群中的一台服务器出现以下两种情况之一时,就会开始进入Leader选举:
• 服务器初始化启动。
• 服务器运行期间无法和Leader保持连接。
(2)而当一台机器进入Leader选举流程时,当前集群也可能会处于以下两种状态:
• 集群中本来就已经存在一个Leader。
对于第一种已经存在Leader的情况,机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器来说,仅仅需要和Leader机器建立连接,并进行状态同步即可。
• 集群中确实不存在Leader。
假设ZooKeeper由5台服务器组成,SID分别为1、2、3、4、5,ZXID分别为8、8、8、7、7,并且此时SID为3的服务器是Leader。某一时刻, 3和5服务器出现故障,因此开始进行Leader选举。 (EPOCH,ZXID,SID ) SID为1、2、4的机器投票情况: (1,8,1) (1,8,2) (1,7,4) (EPOCH,ZXID,SID ) (EPOCH,ZXID,SID )
选举Leader规则: ①EPOCH大的直接胜出 ②EPOCH相同,事务id大的胜出 ③事务id相同,服务器id大的胜出
七、客户端命令行操作
命令基本语法 | 功能描述 |
---|---|
ls path | 使用 ls 命令来查看当前 znode 的子节点 [可监听] -w 监听子节点变化-s 附加次级信息 |
create | 普通创建-s 含有序列-e 临时(重启或者超时消失) |
get | 获得节点的值 [可监听] -w 监听节点内容变化-s 附加次级信息 |
set | 设置节点的具体值 |
stat | 查看节点状态 |
delete | 删除节点 |
deleteall | 递归删除节点 |
- 查看znode 节点数据信息
[zk: localhost:2181(CONNECTED) 7] ls -s /zookeeper-operator/sample-default
[]
cZxid = 0x100000013
ctime = Sun Sep 04 03:13:05 UTC 2022
mZxid = 0x100000013
mtime = Sun Sep 04 03:13:05 UTC 2022
pZxid = 0x100000013
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 14
numChildren = 0
[zk: localhost:2181(CONNECTED) 8]
(1)czxid:创建节点的事务 zxid
每次修改 ZooKeeper 状态都会产生一个 ZooKeeper 事务 ID。事务 ID 是 ZooKeeper 中所
有修改总的次序。每次修改都有唯一的 zxid,如果 zxid1 小于 zxid2,那么 zxid1 在 zxid2 之
前发生。
注意:zookeeper采用了全局递增的事务ID来标识,zxid实际上是一个64位的数字,高32位是epoch 用来标识leader周期,如果有新的leader产生出来,epoch会自增,低32位用来递增计数,通过zxid来保证事务的顺序一致性
(2)ctime:znode 被创建的毫秒数(从 1970 年开始)
(3)mzxid:znode 最后更新的事务 zxid
(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 子节点数量
- 节点类型(持久/短暂/有序号/无序号)
(1)分别创建2个普通节点(永久节点 + 不带序号)
[zk: localhost:2181(CONNECTED) 17] create /permanent/unsort "unsort111"
Created /permanent/unsort
[zk: localhost:2181(CONNECTED) 18] get /permanent/unsort
unsort111
[zk: localhost:2181(CONNECTED) 19]
(2)创建带序号的节点(永久节点 + 带序号)
[zk: localhost:2181(CONNECTED) 21] create -s /permanent/sort "sort2222"
Created /permanent/sort0000000002
[zk: localhost:2181(CONNECTED) 22] create -s /permanent/sort "sort2222"
Created /permanent/sort0000000003
[zk: localhost:2181(CONNECTED) 23] create -s /permanent/sort "sort2222"
Created /permanent/sort0000000004
(3) 创建短暂的不带序号的节点
[zk: localhost:2181(CONNECTED) 11] create -e /temporarystorage "anzhijie"
Created /temporarystorage
[zk: localhost:2181(CONNECTED) 12] get -s /temporarystorage
anzhijie
cZxid = 0x10000001b
ctime = Sun Sep 04 07:52:29 UTC 2022
mZxid = 0x10000001b
mtime = Sun Sep 04 07:52:29 UTC 2022
pZxid = 0x10000001b
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x300242066850000
dataLength = 8
numChildren = 0
(4) 创建短暂的带序号的节点
[zk: localhost:2181(CONNECTED) 13] create -e -s /temporarystorage "anzhijie"
Created /temporarystorage0000000003
[zk: localhost:2181(CONNECTED) 14] get /temporarystorage
temporarystorage temporarystorage0000000003
[zk: localhost:2181(CONNECTED) 14] get /temporarystorage
- 监听器原理
1)首先要有一个main()线程
2)在main线程中创建Zookeeper客户端,这时就会创建两个线
程,一个负责网络连接通信(connet),一个负责监听(listener)。
3)通过connect线程将注册的监听事件发送给Zookeeper。
4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
5)Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程。
6)listener线程内部调用了process()方法
- 节点值的变化监听
先在一台服务上注册监听
在另外一台服务器上修改当前节点的值
在第一台服务器上监视到变化 - 节点的子节点变化监听(路径变化)
先在一台服务器上注册监听
在另外一台服务器上面创建子节点
在第一台服务器上面监视到变化
注册一次,只能监听一次。想再次监听,需要再次注册
zookeeper 对节点的watch 监听通知是一次性的,官方声明,一个Watcher事件就是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知他们。