一、zookeeper介绍

1、简介

Zookeeper是雅虎公司基于chubby的思想,开发的一个分布式协调组件,后来捐献给Apache公司。它主要用来解决分布式数据一致性问题。分布式应用程序可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、配置管理、分布式锁和分布式队列等功能。
zookeeper官方文档:https://zookeeper.apache.org/doc/current/index.html

2、zookeeper工作原理

为了防止单点故障,在使用zookeeper时,一般使用集群。zookeeper集群的工作原理如下图所示:
在这里插入图片描述
在zookeeper集群中包含三个角色:
Leader: Leader 服务器是整个 zookeeper 集群的核心,主要的工作任务有两项。
1、写请求的唯一调度和处理者,保证集群写请求处理的顺序性。
2、集群内部各服务器的调度者。
Follower: Follower的职责是:
1、处理客户端读请求、转发写请求给 leader 服务器。
2、参与写请求 Proposal 的投票(需要半数以上服务器通过才能通知 leader commit 数据; Leader 发起的提案,要求 Follower 投票)。
3、参与 Leader 选举的投票
Observer: 与Follower一样,但是不参加任何形式的投票

3、zookeeper数据同步流程

zookeeper集群必然会涉及数据同步问题,需要保持各个节点的数据一致性。在zookeeper中,主要依赖 ZAB 协议来实现分布式数据一致性,而ZAB主要分为消息广播、崩溃恢复。
消息广播
zookeeper由Leader节点来接收和处理客户端所有事务请求(写请求),并采用 ZAB 协议的原子广播协议,将事务请求以 Proposal 提议广播到所有 Follower 节点,当集群中有过半的Follower 服务器进行正确的 ACK 反馈,那么Leader就会再次向所有的 Follower 服务器发送commit 消息,将此次提案进行提交。这个过程可以简称为 2pc 事务提交,整个流程可以参考下图,注意 Observer 节点只负责同步 Leader 数据,不参与 2PC 数据同步过程。
在这里插入图片描述
崩溃恢复
在正常情况消息广播情况下能运行良好,但是一旦 Leader 服务器出现崩溃,或者由于网络原理导致 Leader 服务器失去了与过半 Follower 的通信,那么就会进入崩溃恢复模式,需要选举出一个新的 Leader 服务器。新 leader 将事务日志中尚未提交的消息进行处理。

4、zookeeper的leader选举

zookeeper 的 leader 选举存在两个阶段,一个是服务器启动时 leader 选举,另一个是运行过程中 leader 服务器宕机,需要重新选举leader。
leader选举中的重要参数:
服务器 ID(myid):编号越大在选举算法中权重越大
事务 ID(zxid):值越大说明数据越新,权重越大
逻辑时钟(epoch-logicalclock):同一轮投票过程中的逻辑时钟值是相同的,每投完一次值会增加

zookeeper节点状态:
LOOKING: 竞选状态
FOLLOWING: 随从状态,同步 leader 状态,参与投票
OBSERVING: 观察状态,同步 leader 状态,不参与投票
LEADING: 领导者状态

leader选举
每个节点启动的时候都 LOOKING 观望状态,以三台机器组成的集群为例。第一台服务器 server1启动时,无法进行 leader 选举,当第二台服务器 server2 启动时,两台机器可以相互通信,进入 leader 选举过程:
1、每台 server 发出一个投票,由于是初始情况,server1 和 server2 都将自己作为 leader 服务器进行投票,每次投票包含所推举的服务器myid、zxid、epoch,使用(myid,zxid,epoch)表示,此时 server1 投票为(1,0),server2 投票为(2,0),然后将各自投票发送给集群中其他机器。
2、接收各个服务器的投票。集群中的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(epoch)、是否来自 LOOKING 状态的服务器。
3、分别处理投票。针对每一次投票,服务器都需要将其他服务器的投票和自己的投票进行对比,对比规则如下:
a. 优先比较 epoch
b. 检查 zxid,zxid 比较大的服务器优先作为 leader
c. 如果 zxid 相同,那么就比较 myid,myid 较大的服务器作为 leader 服务器
4、统计投票结果。每次投票后,服务器会统计投票结果,判断是否有过半机器选出了相同的leader。这里server1、server2 都统计出集群中有两台机器接受了(2,0)的投票信息,此时已经选出了 server2 为 leader 节点。
5、改变服务器状态。一旦确定了 Leader,每个服务器就会更新自己的状态,如果是 Follower,那么就变更为 FOLLOWING,如果是 Leader,就变更为 LEADING

运行过程中的 leader选举
当集群中的 leader 服务器出现宕机或者不可用的情况时,那么整个集群将无法对外提供服务,而是进入新一轮的 Leader 选举,服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是一致的。选举过程:
1、变更状态。Leader 挂后,余下的非 Observer 服务器都会将自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。
2、每个 Server 会发出一个投票。在运行期间,每个服务器上的 ZXID 可能不同,此时假定 Server1 的 ZXID 为 123,Server3 的 ZXID 为 122;在第一轮投票中,Server1 和 Server3 都会投自己,产生投票(1, 123),(3, 122),然后各自将投票发送给集群中所有机器。接收来自各个服务器的投票。与启动时过程相同。
3、处理投票。与启动时过程相同,此时,Server1 将会成为 Leader。
4、统计投票。与启动时过程相同
5、改变服务器的状态。与启动时过程相同

二、Zookeeper 安装配置

1、linux环境下

下载地址:zookeeper 下载地址为: https://zookeeper.apache.org/releases.html。选择一个稳定版本下载。
在这里插入图片描述
官网说明了3.8.0是当前版本,3.7.0是最新的稳定版本,我们下载3.7.0就可以了。
将下载下来的tar包拷贝到linux服务器上。然后进入的tar包所在目录,打开终端。

$ tar -zxvf zookeeper-3.7.0.tar.gz
$ cd zookeeper-3.4.14
$ cd conf/
$ cp zoo_sample.cfg zoo.cfg
$ cd ..
$ cd bin/
$ sh zkServer.sh start  

到这里,Zookeeper就配置好启动了,如下所示:
在这里插入图片描述
查看服务状态(单机节点):
在这里插入图片描述
启动客户端:

$ sh zkCli.sh

客户端启动后就会进入客户端的操作界面
在这里插入图片描述
在客户端使用help命令,查看客户端的所有命令
在这里插入图片描述

启动完客户端,就可以对Zookeeper服务进行操作了。

2、windows环境下

下载同上。
下载后解压,将 conf 目录下的 zoo_sample.cfg 文件,复制一份,重命名为 zoo.cfg。然后在安装目录下面新建一个空的 data 文件夹和 log 文件夹。修改 zoo.cfg 配置文件,将 dataDir=/tmp/zookeeper 修改成 zookeeper 安装目录所在的 data 文件夹。注意目录不要使用反斜杠(3.7.0版本使用反斜杠会导致目录识别错误)。
在这里插入图片描述

运行zkServer.cmd启动Zookeeper服务
在这里插入图片描述
运行zkCli.cmd启动客户端
在这里插入图片描述

3、zookeeper集群搭建

这里搭建含3个节点的zookeeper集群
步骤:
1、准备好zookeeper安装包,分别复制并解压到三个集群环境里,在conf目录下复制zoo_sample.cfg并重命名为zoo.cfg。
2、配置zoo.cfg文件的dataDir,以及在三个zoo.cfg文件末尾加入server.id = ip:port:port

server.1=IP1:2888:3888 
server.2=IP2.2888:3888
server.3=IP3.2888:3888

ip使用实际ip。2888表示与集群中的节点通信端口,3888表示选举Leader的端口,如果是伪集群,因为ip一致,那么端口应该要不同。
zookeeper 的三个端口作用:
2181 : 对 client 端提供服务
2888 : 集群内机器通信使用
3888 : 选举 leader 使用
配置observer节点时:server.x=host:port1:port2:observer。还需要在zoo.cfg中加入:peerType=observer配置

3、在三个配置的dataDir目录下新建myid文件,每个文件的内容与zoo.cfg配置的id一致,比如server.1的myid 文件内容就是 1。【必须确保每个服务器的 myid 文件中的数字不同,并且和自己所在机器的 zoo.cfg 中 server.id的 id 值一致,id 的范围是 1~255】

4、启动集群。linux下要关闭防火墙,如果是生产环境,则需要打开对应的端口。

三、Zookeeper数据模型znode

1、znode结构和属性

在Zookeeper中,提供了znode的数据模型来实现功能。可以说 zookeeper 中的所有存储的数据是由 znode 组成的,并以 key/value 形式存储数据。整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 / 开头,zookeeper 名称空间中的每个节点都是由一个路径标识。结构如下所示。
在这里插入图片描述
每个节点都有自己的属性,使用get -s 节点全路径或者stat 节点全路径命令可以得到节点的信息。第一行是这个节点的value。
在这里插入图片描述

属性名称属性含义
cZxid该节点被创建时的事务ID
ctime该节点被创建时的时间
mZxid该节点最后一次被更新时的事务ID
mtime该节点最后一次被更新时的时间
pZxid该节点的子节点列表最后一次更新时的事务ID,注意只有子节点列表变更了才会变更pzxid,子节点内容变更不会影响pzxid
cversion该节点的子节点版本号,子节点每次更新版本号加1(和pZxid一样,子节点内容不影响)
dataversion该节点的数据(value)版本号,数据每次修改该版本号加1
aclversion该节点的权限版本号,权限每次修改该版本号加1
ephemeralOwner创建该临时节点的会话的sessionID。(如果该节点是持久节点,那么这个属性值为0)
dataLength该节点的数据长度
numChildren该节点拥有子节点的数量(只统计直接子节点的数量)

2、znode类型

持久节点(Persistent Nodes)
创建后会一直存在 zookeeper 服务器上,直到主动删除的节点。

create 节点路径 value值

临时节点(Ephemeral Nodes)
临时节点的生命周期和客户端的会话(session)绑定在一起,当客户端会话失效该节点自动清除。临时节点不允许有子节点。使用getEphemerals 节点路径命令可以获得指定路径下的临时节点列表,不加路径则会列出所有临时节点。

//创建临时节点
create -e 节点路径 value值

有序节点(Sequence Nodes)
每个节点都会为它的一级子节点维护一个计数器。这个计数器对于父 znode 是唯一的,计数器的格式为 %010d - 即 10 位数字和 0(零)填充。示例:

//创建的就是node_1下的子节点,节点名称形式:0000000001,值是value
create -s /node/node_1/ value
//创建的就是node下的子节点,节点名称形式就是node_10000000001,值是value
create -s /node/node_1 value

计数器由有符号整数(4 字节)存储,所以超过 2147483647 时,计数器将溢出(导致”-2147483648"出现)。

容器节点(Container Nodes)
当子节点都被删除后,容器节点也随即删除

create -c 节点路径 value值

TTL 节点
可以给持久节点或者持久有序节点设置一个 TTL(以毫秒为单位)。如果节点在 TTL 内没有被修改并且没有子节点,则会被删除。此功能默认是关闭的,需要在配置文件中设置extendedTypesEnabled=true,开启。如果没开启就设置TTL,则Zookeeper服务器将抛出 KeeperException.UnimplementedException。

create -t 1000 节点路径 value值

3、znode特性

1、同一级节点 key 名称是唯一的。
2、创建节点时,必须要带上全路径
3、session 关闭,临时节点清除
4、watch 机制,监听节点变化
5、delete 命令只能一层一层删除,可以使用deleteall 命令递归删除

四、Zookeeper权限控制ACL

Zookeeper使用ACL来控制对znode的访问。ACL实现与UNIX文件访问权限非常相似:它使用权限位来允许/禁止针对节点的各种操作以及这些位适用的范围。与标准 UNIX 权限不同,ZooKeeper 节点不受用户(文件所有者)、组和world(其他)三个标准范围的限制。ZooKeeper 没有 znode 所有者的概念。相反,ACL 指定一组 id 和与这些 id 关联的权限。

ACL命令
getAcl 命令:获取某个节点的 acl 权限信息。
setAcl 命令:设置某个节点的 acl 权限信息。
addauth 命令:输入认证授权信息,注册时输入明文密码,加密形式保存。

Zookeeper 的ACL通过 [scheme🆔permissions] 来构成权限列表。
permissions:权限类型
CREATE:您可以创建一个子节点
READ:您可以从节点获取数据并列出其子节点。
WRITE:您可以为节点设置数据
DELETE:您可以删除一个子节点
ADMIN:您可以设置权限

scheme:权限模式
world:默认权限,只有一个id为“anyone”。

$ create /aclnodes
$ getAcl /aclnodes
//设置world方案,id为anyone,权限为cdrwa
$ setAcl /aclnodes world:anyone:cdrwa
$ getAcl /aclnodes

auth :身份验证模式。需要先通过addauth添加一个验证口令。形式为:user:pwd

//auth:user:pwd:cdrwa
//需要使用addauth先创建用户和密码
$ addauth digest user1:123456
//auth方案,id为user1:123456,权限为cdrwa
$ setAcl /aclnodes auth:user1:123456:cdrwa
$ getAcl /aclnodes

digest:和auth差不多,区别是pwd需要使用加密后的密文,加密方式是BASE64(SHA1(PWD))。形式是digest:user:BASE64(SHA1(PWD)):cdrwa

//digest:user:BASE64(SHA1(PWD)):cdrwa
//HYGa7IZRm2PUBFiFFu8xY2pPP/s=是‘user1:123456’加密后的字符串。可以使用getAcl查看加密后的字符串
$ getAcl /aclnodes
$ setAcl /aclnodes  digest:user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s=:cdrwa
$ getAcl /aclnodes
//其他客户端需要先添加验证口令,才能操作加了此验证口令的节点
$ addauth digest user1:123456
$ getAcl /aclnodes

ip:
使用客户端主机 IP 作为 ACL ID 身份

$ create /ipnode
$ getAcl /ipnode
$ setAcl /ipnode ip:127.0.0.1:cdrwa
$ getAcl /ipnode

还可以直接在创建节点时加上acl

$ create /aclnode1 world:anyone:cdrwa

五、Zookeeper watcher事件

Watcher 监听机制是 Zookeeper 中非常重要的特性。我们基于 zookeeper 上创建的节点,可以对这些节点绑定监听事件,比如可以监听节点数据变更、节点删除、子节点状态变更等
事件,通过这个事件机制,可以基于 zookeeper 实现分布式锁、集群管理等功能。

在客户端命令行中,我们可以使用带有-w参数的命令,设置一个watch监听。
stat path -w :监听节点属性变化
ls path -w:监听子节点列表的变化
get path -w:监听节点的数据变化
示例:

$ create /watchnode
$ get /watchnode -w

当值变化后,就会触发监听:
在这里插入图片描述
watch监听只会触发一次,如果要实现永久监听,可以通过循环注册来实现。

六、客户端命令

在客户端输入help命令可以查看所有命令。
在这里插入图片描述
常用命令:

命令作用
ls [-s] [-w] [-R] path查看节点下的子节点列表 。-s展示属性信息,-w加上监听,-R展示此节点及所有子节点的路径信息
get [-s] [-w] path用于获取节点数据和状态信息,-s 展示属性信息,-w 加上监听
stat [-w] path查看节点属性信息。-w加上监听
create [-s] [-e] [-c] [-t ttl] path [data] [acl]创建节点。-s 有序节点,-e 临时节点, -c 容器节点, -t ttl TTl节点,ttl表示超时时间(ms),acl ACL权限,data 节点数据
set [-s] [-v version] path data设置节点的值。-s 设置完显示属性信息,-v version 版本号,只有version=当前版本号,才能设置成功。
delete [-v version] path删除节点,没有子节点时才能删除 -v version 版本号,

七、注意事项

zookeeper3.5版本以后,新增了一个AdminServer功能,这是一个jetty的嵌入式服务器,默认开启,端口就是8080。这会与tomcat冲突。解决方案如下:
1、换端口。在zoo.cfg里新增如下配置。port是不冲突的端口

admin.serverPort=port

2、停用这个服务
在zkServer.cmd/zkServer.sh中加入"-Dzookeeper.admin.enableServer=false"

zkServer.cmd:
在这里插入图片描述
zkServer.sh:
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐