一、Zookeeper简介
Zookeeper 是一个开源的分布式协调服务, Apache Hadoop的一个子项目,采用JAVA语言开发。Zookeeper 可以用于实现分布式系统中常见的发布/订阅、负载均衡、服务发现、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
Zookeeper是一种高性能、可扩展的分布式协调服务。Zookeeper将数据存储在内存中,具有高吞吐量和低延迟特性,特别是在多读少写的时候,性能更好。但是zookeeper节点存储的数据大小有限制(官网推荐不超过1M)
Zookeeper具有如下特性:
- 顺序一致性:从一个客户端发起的事务请求,最终都会严格按照其发起顺序被应用到 Zookeeper 中;
- 原子性:所有事务请求的处理结果在整个集群中所有机器上都是一致的;不存在部分机器应用了该事务,而另一部分没有应用的情况;
- 最终一致性(单一视图):所有客户端看到的服务端数据模型都是一致的,即无论客户端连接哪台服务器,看到的视图是一样的;
- 可靠性:一旦服务端成功应用了一个事务,则其引起的改变会一直保留,直到被另外一个事务所更改;
- 实时性:一旦一个事务被成功应用后,Zookeeper 可以保证客户端立即可以读取到这个事务变更后的最新状态的数据。
二、安装使用
1. 安装部署
下载安装3.8.3,官网地址:https://zookeeper.apache.org/releases.html
- 解压安装
tar -zxvf apache-zookeeper-3.8.3-bin.tar.gz
- 配置修改
cd apache-zookeeper-3.8.3-bin
cp apache-zookeeper-3.8.3-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.3-bin/conf/zoo.cfg
vim apache-zookeeper-3.8.3-bin/conf/zoo.cfg
修改配置文件如下:
# Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,单位毫秒
tickTime=2000
initLimit=10
syncLimit=5
#数据目录
dataDir=/tmp/zookeeper
#客户端要连接的端口,即Server 监听的端口号
clientPort=2181
#8080端口防止被tomcat占用,修改端口
admin.serverPort=8888
集群启动需要配置参数(3台服务器) ,机器分别为192.168.1.100,192.168.1.101,192.168.1.102
server.1=192.168.1.100:2888:3888
server.2=192.168.1.101:2888:3888
server.3=192.168.1.102:2888:3888
- 启动
bin/zkServer.sh start
#查看状态
bin/zkServer.sh status
- 停止
bin/zkServer.sh stop
配置信息详解
- tickTime:通信心跳数,Zookeeper服务器与客户端心跳时间,单位毫秒
- initLimit:集群中的 Follower 与 Leader 之间初始连接时能容忍的最多心跳数(initLimit * tickTime为时间)
- syncLimit:Leader和Follower之间同步通信的超时时间,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。
- dataDir:数据文件目录路径
- clientPort :监听客户端连接的端口
- dataLogDir : 事物日志目录,默认跟数据文件目录一致
- server.A=B:C:D : 集群信息配置
A 是一个数字,表示这个是第几个服务器
集群模式下配置一个myid文件,这个文件在 dataDir 目录下,这个文件里面有一个数据就是 A 的值,Zookeeper 启动时读取此文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个server
B 是这个服务器的IP地址
C 是这个服务器的集群中的 Leader 服务器交换信息的端口
D 是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来选举时服务器互相通信的端口
2. 客户端命令
- 启动客户端
bin/zkCli.sh
#查看命令帮助
help
- ls [-w] path 使用 ls 命令来查看当前 znode 中所包含的内容
- create 普通创建节点 -s 含有序列 -e 临时(重启或超时时消失)
- get [-w] path 获得节点的数据值
- set 设置节点的值
- stat path 查看节点详细信息
- delete 删除节点
- deleteall 递归删除节点
- sync 同步节点
- quit 退出
三、工作原理
Zookeeper = 文件系统 + 通知机制
从设计模式的角度来理解:Zookeeper是一个基于观察者模式的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接收观察者的注册,一旦这些数据的状态发生变化,就会通知已注册的观察者。
1.文件系统
主要用于管理(存储\读取)用户程序提交的数据
1) 数据节点
Zookeeper 数据模型是由一系列基本数据单元 Znode(数据节点) 组成的节点树,其中根节点为/
。每个节点上都会保存自己的数据和节点信息。节点可以分为两大类:
持久节点:节点一旦创建,除非被主动删除,否则一直存在;
临时节点 :一旦创建该节点的客户端会话失效,则所有该客户端创建的临时节点都会被删除。
临时节点和持久节点都可以添加一个特殊的属性:SEQUENTIAL,代表该节点是否具有递增属性。如果指定该属性,那么在这个节点创建时,Zookeeper 会自动在其节点名称后面追加一个由父节点维护的递增数字。
create /book -s #创建有序的节点
create /tmp -e #创建临时节点(会话有效)
2) 节点信息
每个 ZNode 节点在存储数据的同时,都会维护一个叫做 Stat 的数据结构,里面存储了关于该节点的全部状态信息。如下:
stat /test #查看节点信息
- cZxid - 创建节点的事务 zxid
- cTime - znode 被创建的毫秒数(从1970 年开始)
- mZxid - 最后更新的事务 zxid
- mTime - 最后修改的毫秒数(从1970 年开始)
- pZixd - 最后更新的子节点 zxid
- cVersion - znode 子节点变化号,znode 子节点修改次数
- dataVersion - znode 数据变化号
- aclVersion - znode 访问控制列表的变化号
- ephemeralOwner - 如果是临时节点,这个是 znode 拥有者的 session id。如果不是临时节点,则是 0
- dataLength - znode 的数据长度
- numChildren - znode 子节点的数量
2.通知机制
为用户程序提供数据节点监听服务
Zookeeper监视点(watchpoint)是一种在Zookeeper中设置的机制,用于监视和观察Znode的变化情况。在Zookeeper中,每个Znode都可以设置一个监视点,当Znode发生变化时,Zookeeper会通知设置了监视点的客户端。为了设置监视点,客户端需要向Zookeeper发送一个watch请求,指定要监视的Znode路径。当Znode发生变化时,Zookeeper会给客户端发送一个通知,客户端可以在收到通知后做出相应的处理.
建立 Zookeeper 连接时传入的 watcher;
通过 getData、exists、getChildren; 来设置watcher,而它们又各有同步和异步两种形式。Zookeeper 的所有读操作都可以设置 watch 监视点: getData, getChildren, exists. 写操作则是不能设置监视点的。
- 监视有两种类型:数据监视点和子节点监视点。创建、删除或者设置znode都会触发这些监视点。exists,getData 可以设置数据监视点。getChildren 可以设置子节点变化。而可能监测的事件类型有: None、NodeCreated、NodeDataChanged、NodeDeleted、NodeChildrenChanged。
3.选举机制
集群角色
Zookeeper 集群中的机器分为以下三种角色:
- Leader(领导者) :为客户端提供读写服务,并维护集群状态,它是由集群选举所产生的;
- Follower(跟随着) :为客户端提供读写服务,并定期向 Leader 汇报自己的节点状态。同时也参与写操作“过半写成功”的策略和 Leader 的选举;
- Observer(观察者) :为客户端提供读写服务,并定期向 Leader 汇报自己的节点状态,但不参与写操作“过半写成功”的策略和 Leader 的选举,因此 Observer 可以在不影响写性能的情况下提升集群的读性能。
Observer与Follower唯一的区别是:Observer 不参与leader选举的投票
zookeeper 的 leader 选举存在两个阶段,一个是服务器启动时 leader 选举,另一个是运行过程中 leader 服务器宕机。在分析选举原理前,先介绍几个重要的参数。
服务器 ID(myid):编号越大在选举算法中权重越大
事务 ID(zxid):值越大说明数据越新,权重越大
逻辑时钟(epoch-logicalclock):同一轮投票过程中的逻辑时钟值是相同的,每投完一次值会增加(Zxid的高32位)
选举状态
LOOKING: 竞选状态
FOLLOWING: 随从状态,同步 leader 状态,参与投票
OBSERVING: 观察状态,同步 leader 状态,不参与投票
LEADING: 领导者状态
1) 启动选举机制
假设5个节点(Server1,Server2,Server3, Server4, Server5)
- 节点启动时: 加载本地快照文件及事务日志,恢复内存数据,所有节点都会进入 LOOKING 状态。
- 发送选举消息:每个节点会向其他节点发送选举消息,它们会将自己的信息包括自己的 myid(唯一标识)和 ZXID(事务 ID)发送给其他节点。
- 接收选举消息:节点会接收其他节点发送的选举消息,并比较其中的信息。
- 选举算法执行:节点会根据选举算法来决定谁将成为领导者。通常情况下,节点会选择具有最大 ZXID 值的节点作为领导者。如果多个节点的 ZXID 值相同,则选择 myid 值更大的节点作为领导者。
- 收到选举结果:一旦一个节点收到过半节点的选票(反馈),它会成为领导者,其他节点则成为追随者。
- 同步数据:新选举出的Leader会以自己数据为基准,结合各个Follower的本地提交数据,确定给具体Follower回滚哪些数据和同步哪些数据
整个选举流程是自动进行的,ZooKeeper 内部实现了选举算法和消息交换机制。一旦选举完成,领导者节点将负责处理客户端请求,并保持与其他节点的心跳连接以维持集群的正常运行。
2) 非第一次启动选举机制(恢复模式)
当Leader 宕机以后,Follower节点都会变成LOOKING节点, 会触发选举机制, ZXID值大的胜出,ZXID值相同,myid值大的胜出.
ACL
Zookeeper 采用 ACL(Access Control Lists) 策略来进行权限控制,类似于 UNIX 文件系统的权限控制。它定义了如下五种权限(简写cdrwa
):
- CREATE:允许创建子节点;
- READ:允许从节点获取数据并列出其子节点;
- WRITE:允许为节点设置数据;
- DELETE:允许删除子节点;
- ADMIN:允许为节点设置权限。
Zookeeper的权限控制是基于znode节点的,需要对每个节点设置权限
五种权限认证模式:
- world 权限模式: 默认模式每个客户端都设置一样cdrwa 权限
#创建默认/test节点, 未设置权限默认是world模式
create /test hello
#获取/test节点的ACL
getAcl /test
- auth 权限模式:
#设置auth之前,先添加账号:密码,比如test:test@2024
addauth digest test:test@2024
#设置/test节点设置test账号cdrwa权限, 只有登录test 账号的客户端才能cdrwa 节点/test
setAcl /test auth:test:cdrwa
#客户端登录test账号
addauth digest test:test@2024
- digest 权限模式:
digest授权模式基于账号密码的授权模式,与Auth模式类似,只是他设置权限之前不需要使用
addauth digest username:password进行权限用户添加。直接使用命令 setAcl path digest:username:password:acl 进行授权就行。只是这里的密码要使用加密后的密码,不能使用明文密码
#计算密文
echo -n test:test@2024 | openssl dgst -binary -sha1 | openssl base64
##得到OiTewOYRV8qivsx7WoXjiR0+6VI=
setAcl /test digest:test:OiTewOYRV8qivsx7WoXjiR0+6VI=:cdrwa
- ip权限模式:
#只能127.0.0.1 客户端cdrwa 节点/test
setAcl /test ip:127.0.0.1:cdrwa
- 管理员模式:
需要重启zk,在 zkEnv.sh 添加如下行
export SERVER_JVMFLAGS="-Dzookeeper.DigestAuthenticationProvider.superDigest=admin:YyNjoNUGKrgkriwbwIhqA7oK/jo= $SERVER_JVMFLAGS"
#计算密文
echo -n admin:test@2024 | openssl dgst -binary -sha1 | openssl base64
- 同时设置多个权限模式(
逗号分隔
)
setAcl /test ip:127.0.0.1:cdrwa,auth:test:cdrwa,world:anyone:cdrwa,digest:test:OiTewOYRV8qivsx7WoXjiR0+6VI=:cdrwa
写数据流程
- 1.当事务请求发送到Follower服务器节点,请求会先转发给Leader节点;
- 2.Leader节点把写请求转化成一个事务Proposal(提议),并把这个 Proposal 分发给集群中的所有 Follower 节点;
- 3.如果过半的Follower节点同意(返回ACK),Leader 就会再次向所有的Follower 节点发送 Commit 消息,要求各个 Follower 节点对前面的一个 Proposal 进行提交;
- 4.把最后的结果同步给Observer节点;
- 5、把写数据的最终结果返回给客户端;
读数据流程
由于数据一致性,所有每个节点的数据是一样,随便访问哪个节点(不管是Leader还是Follow)读取数据都行,也就是说,任务节点都可以去处理读请求, 无须转发, 提高负载能力.
4. ZAB 协议
Zab协议是为分布式协调服务Zookeeper专门设计的一种 支持崩溃恢复 的 原子广播协议 ,是Zookeeper保证数据一致性的核心算法。它借鉴了Paxos算法,但又不是完完全全的按照Paxos算法去实现的,解决了一些Paxos算法的问题.Zab协议有两种模式:1.恢复模式(选主)和2.广播模式(同步)
Paxos算法
paxos算法是分布式中保证一致性的一种算法,引入了半数原则,它可以保证在节点失效、网络分区、网络延迟等情况下各个节点状态的一致性;有三个版本:Basic Paxos , Multi Paxos和 Fast Paxos(ZAB协议就基于Fast Paxos的)
四、Springboot集成
curator 是针对zookeeper 的客户端程序
五、使用场景
1.配置管理
数据的发布/订阅系统,通常也用作配置中心。将数据发布到ZooKeeper节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。
2.命名服务
在分布式系统中,通常需要一个全局唯一的名字,如生成全局唯一的订单号等,Zookeeper 可以通过顺序节点的特性来生成全局唯一 ID,从而可以对分布式系统提供命名服务。
3.Master选举
分布式系统一个重要的模式就是主从模式 (Master/Salves),Zookeeper 可以用于该模式下的 Matser 选举。可以让所有服务节点去竞争性地创建同一个 ZNode,由于 Zookeeper 不能有路径相同的 ZNode,必然只有一个服务节点能够创建成功,这样该服务节点就可以成为 Master 节点。
4. 分布式锁
可以通过 Zookeeper 的临时节点和 Watcher 机制来实现分布式锁,这里以排它锁为例进行说明:
分布式系统的所有服务节点可以竞争性地去创建同一个临时 ZNode,由于 Zookeeper 不能有路径相同的 ZNode,必然只有一个服务节点能够创建成功,此时可以认为该节点获得了锁。其他没有获得锁的服务节点通过在该 ZNode 上注册监听,从而当锁释放时再去竞争获得锁。锁的释放情况有以下两种:
当正常执行完业务逻辑后,客户端主动将临时 ZNode 删除,此时锁被释放;
当获得锁的客户端发生宕机时,临时 ZNode 会被自动删除,此时认为锁已经释放。
当锁被释放后,其他服务节点则再次去竞争性地进行创建,但每次都只有一个服务节点能够获取到锁,这就是排他锁。
5.集群管理
Zookeeper 还能解决大多数分布式系统中的问题:
如可以通过创建临时节点来建立心跳检测机制。如果分布式系统的某个服务节点宕机了,则其持有的会话会超时,此时该临时节点会被删除,相应的监听事件就会被触发。
ls
分布式系统的每个服务节点还可以将自己的节点状态写入临时节点,从而完成状态报告或节点工作进度汇报。
通过数据的订阅和发布功能,Zookeeper 还能对分布式系统进行模块的解耦和任务的调度。
通过监听机制,还能对分布式系统的服务节点进行动态上下线,从而实现服务的动态扩容。