一、Zookeeper入门
1.1 概述
Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
1.2 Zookeeper工作机制
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,他负责存储和管理大家都关系的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。
1.3 特点
- Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
- 集群中只要有半数以上节点在存货,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器。
- 全局数据一致性:每个Server保存一份相同的数据副本,CLient无论连接到哪个Server,数据都是一致的。
- 更新请求顺序执行,来自同一个Client的更新请求按器发送顺序依次执行。
- 数据更新原子性:一个数据更新要么成功,要么失败。
- 实时性:在一定时间范围内,Client能读到最新数据。
1.4 数据结构
Zookeeper数据模型的结构于Unix文件系统很类似,整体上可以看成一棵树,每个节点称作一个ZNode.没一个ZNode默认能够存储1MB的数据,每个ZNode度可以通过其路径唯一标识。
1.5 应用场景
提供的服务报错:统一命名服务、同一个配置管理、同一个集群管理、服务器节点动态上下线、阮负载均衡等。
统一命名服务:在分布式环境下,经常需要对应用、服务进行统一明明,便于标识。例如:IP不容易记住,而域名容易记住。
统一配置管理:
- 分布式环境下,配置文件同步非常常见
(1)一般要求一个集群中,所有节点的配置信息是一致的,比如kafka集群
(2)对配置文件修改后,希望能够快速同步到各个节点上。
- 配置管理科交由ZooKeeper实现
(1)可将配置信息写入到Zookeeper上的一个ZNode
(2)各个客户端服务器监听这个ZNode
(3)一旦ZNode中的数据丠修改,Zookeeper将同志各个客户端服务器。
统一集群管理:
- 分布式环境中,实时掌握每个节点的状态是必要的
(1) 可以根据节点实时状态做出一些调整。
- Zookeeper可以实现实时监控节点状态变化
(2) 可将节点信息写入Zookeeper上的一个ZNode.
(2) 监听这个ZNode可获取他的实时状态变化。
服务器动态上下线:
软负载均衡:
二、Zookeeper的安装使用
2.1 Zookeeper本地模式安装
2.2 Zookeeper使用docker搭建集群
1、拉取镜像
docker pull zookeeper:3.5.7
2、创建映射目录,三台服务器都创建
mkdir -p /opt/local/zookeeper/conf
mkdir -p /opt/local/zookeeper/data
3、在conf目录下创建并配置zoo.cfg文件
vim zoo.cfg
#客户端连接端口,监听客户端连接的端口clientPort=2181#数据文件目录+数据持久化路径dataDir=/data
#日志文件目录dataLogDir=/data/log
# 通信心跳数,Zookeeper服务器心跳时间,单位毫秒。 Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒。它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2\*tickTime)tickTime=2000#初始通信时限,集群中的follower跟随者服务器(F)与leader领导者服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。投票选举新leader的初始化时间
Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader允许F在initLimit时间内完成这个工作。
#leader(L)-follower(F)同步通信时限集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit \* tickTime, Leader认为Follwer死掉,从服务器列表中删除Follwer。在运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。如果L发出心跳包在syncLimit之后,还没有从F那收到响应,那么就认为这个F已经不在线了syncLimit=2
autopurge.snapRetainCount=3
autopurge.purgeInterval=0maxClientCnxns=60#server.A=B:C:D:其中 A 是一个数字,表示这个是第几号服务器。B 是这个服务器的 IP 地址。C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口(2888);D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口(3888)。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。
server.126=0.0.0.0:2888:3888
server.123=192.168.223.123:2888:3888
server.120=192.168.223.120:2889:3889
clientPort=2181dataDir=/data
dataLogDir=/data/log
tickTime=2000initLimit=5syncLimit=2
autopurge.snapRetainCount=3
autopurge.purgeInterval=0maxClientCnxns=60
server.126=192.168.223.126:2887:3887
server.123=0.0.0.0:2888:3888
server.120=192.168.223.120:2889:3889
clientPort=2181dataDir=/data
dataLogDir=/data/log
tickTime=2000initLimit=5syncLimit=2
autopurge.snapRetainCount=3
aut**opurge.purgeInterval=0**
**maxClientCnxns=60**
**server.126=192.168.223.126:2887:3887**
**server.123=192.168.223.123:2888:3888**
**server.120=0.0.0.0:2888:3888**
然后在data目录下创建myid文件,并且将服务号设为值,比如server.126的myid为126
注:zoo.cfg文件下配置后面很容易带有空格,在保存之前一定要确定文件后面是否有空格。
4、创建容器
docker run --restart always -v /opt/local/zookeeper/data:/data -v /opt/local/zookeeper/conf/zoo.cfg:/conf/zoo.cfg\:rw --name zk-126 -e "TZ=Asia/Shanghai" -p 2181:2181 -p 2887:2888 -p 3887:3888 -d zookeeper:3.5.7
docker run --restart always -v /opt/local/zookeeper/data:/data -v /opt/local/zookeeper/conf/zoo.cfg:/conf/zoo.cfg\:rw --name zk-123 -e "TZ=Asia/Shanghai" -p 2182:2181 -p 2888:2888 -p 3888:3888 -d zookeeper:3.5.7
docker run --restart always -v /opt/local/zookeeper/data:/data -v /opt/local/zookeeper/conf/zoo.cfg:/conf/zoo.cfg\:rw --name zk-120 -e "TZ=Asia/Shanghai" -p 2183:2181 -p 2889:2888 -p 3889:3888 -d zookeeper:3.5.7
2.3 Zookeeper单节点安装
1、拉取镜像
docker pull zookeeper:3.5.7
2、创建映射文件
clientPort=2181dataDir=/data
dataLogDir=/log
tickTime=2000
3、创建容器
docker run --restart always -v /quse/zookeeper/data:/data -v /quse/zookeeper/conf/zoo.cfg:/conf/zoo.cfg:rw --name zk -e "TZ=Asia/Shanghai" -p 2181:2181 -d zookeeper:3.5.7
2.4 ZK的使用
1、zk的使用
- 连接客户端
# bin目录下
zkCli.sh
#访问其他节点的客户端
zkCli.sh -server 192.168.223.120:2183
- 查看当前ZK所包含内容
ls -s /
结果
[zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion =0
aclVersion =0
ephemeralOwner = 0x0
dataLength =0
numChildren =1
(1)czxid:创建节点的事务 zxid 每次修改 ZooKeeper 状态都会产生一个 ZooKeeper 事务 ID。事务 ID 是 ZooKeeper 中所 有修改总的次序。每次修改都有唯一的 zxid,如果 zxid1 小于 zxid2,那么 zxid1 在 zxid2 之 前发生。
(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 子节点数量
- 创建一个新的znode
create /zkPro myData
2、创建子节点
create /wqq/qml "zyq"
- 再次查看zk中所包含的内容
ls /
4、查看节点下状态信息,不查看数据
state /wqq
5、使用get查看新创建znode是否包含所创建字符串
get -s /zkPro
6、修改znode中关联字符串
set /zkPro myData 123
7、创建带序号字符串
create -s /wqq/qml/wsy "ne"
8、创建临时节点
create -e /wqq/qml/wsy "ne"
9、删除刚创建字符串
delete /zkPro
10、如果节点下有子节点则不能删除,需要用到指令
delete /wqq
11、查看当前EPOCH
cat currentEpoch
12、zk操作指令
#启动zk
zkServer.sh start
#关闭zk
zkServer.sh stop
2、zookeeper选举机制
2.1、 5台服务器第一次启动的选举机制
(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; LOOKING LOOKING 1 0 1 2 0 3
(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为 1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING; (5)服务器5启动,同4一样当小弟。
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 ) (EPOCH,ZXID,SID ) (EPOCH,ZXID,SID )
SID为1、2、4的机器投票情况: (1,8,1) (1,8,2) (1,7,4)
选举Leader规则: ①EPOCH大的直接胜出 ②EPOCH相同,事务id大的胜出 ③事务id相同,服务器id大的胜出
3、节点的类型
持久(Persistent):客户端和服务端断开连接后,创建的节点不删除
短暂(Ephemeral):客户端和服务端断开连接后创建的节点自己删除
- 持久化目录节点
客户端与Zookeeper断开连接后,该节点依旧存在
- 持久化顺序编号目录节点
客户端与Zookeeper断开连接后,改接地那依旧存在,只是zookeeper给该节点名称进行顺序编号
- 临时目录节点
客户端与Zookeeper断开连接后,该节点被删除
- 临时顺序编号目录节点
客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号。
说明:创建znode是设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
注意:在分布式系统中,顺序号可被用于为所有的时间进行全局排序,这样客户端可以通过顺序号推断时间的顺序。
4、监听器原理
;客户端注册监听它关心的目录接待,当目录接待发生变化(数据改变、节点删除、子目录接地那增加删除)时,ZooKeeper会通知客户端。监听机制保证ZooKeeper保存的任何的数据的任何改变都能快速的相应到监听该接地那的应用程序。
1、监听器原理
- 首先要有一个main()线程
- 在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listen)。
- 通过connect线程将注册的监听纱巾发送给Zookeeper
- 在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
- Zookeeper监听到有数据或者路径变化,就会将这个消息发送给listener线程
- listener线程内部调用了process()方法。
2、常用监听
- 监听节点数据的变化
get path[watch]
- 监听子节点增减的变化
ls path[watch]
3、监听器的使用
监听节点值的变化
1、监听某一个节点
get -w /wqq
2、修改监听的节点来进行验证
set /wqq "26"
注意:在对监听的节点进行多次修改的时候,将不会再收到监听。因为注册一次,只能监听一次。想再次监听,需要再次注册。
监听节点数的变化
1、监听某一个节点
ls -w /wqq
2、在监听节点下创建子节点
ls -w /wqq
注:节点路径的变化也是注册一次,生效一次。
5、客户端向服务端写数据流程
1、客户端向Leader节点发送写数据请求
2、客户端向Follower节点发送写数据请求
6、服务器动态上下线
1、首先创建服务器节点
create /servers "servers"
2、创建客户端
3、创建服务端
7、zookeeper分布式锁
什么叫分布式锁?
比如说“进程1”在使用该资源的时候,会先去获得锁,“进城1”获得锁以后对该资源保持独占。这样其他进程就无法访问该资源,“进程1”用完该资源以后就将锁四方掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证了分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫做分布式锁。
三、问题
1、启动所遇问题
- 有时启动集群的时候会出现有的服务器连接不了集群的情况,这个时候只要重启一下leader节点就好
版权归原作者 汀风 所有, 如有侵权,请联系我们删除。