1、Zookeeper介绍
ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
2、Zookeeper工作原理
ZooKeeper工作原理是通过一个叫做ZAB(ZooKeeper Atomic Broadcast)的分布式一致性协议来实现的。ZAB协议主要由两个部分组成:写入集合和选举。
写入集合部分负责维护所有客户端的写请求,并将它们按照顺序排列。每个写请求都会被分配一个全局唯一的版本号,并在写入集合中按照版本号的顺序进行排序。
选举部分负责选出当前的领导者,并维护集群的状态。ZooKeeper集群中的每个节点都可以参与选举,并通过投票的方式产生新的领导者。新的领导者会接手处理所有客户端的写请求,并将它们写入到写入集合中。
客户端可以通过向ZooKeeper集群中的任意一个节点发送读请求来获取数据。节点会把读请求转发给当前的领导者,然后领导者会从写入集合中读取数据,并返回给客户端。
这样,ZooKeeper集群就可以保证数据的一致性,并为客户端提供可靠的分布式协调服务。
3、Zookeeper功能
3.1、命名服务
命名服务是分布式系统中比较常见的一类场景。命名服务是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等——这些我们都可以统称它们为名字(Name),其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供者的信息等。
3.2、Zookeeper数据模型
在 Zookeeper 中,节点分为两类
1、第一类是指构成Zookeeper集群的主机,称之为主机节点
2、第二类则是指内存中zookeeper数据模型中的数据单元,用来存储各种数据内容,称之为数据节点 ZNode。
Zookeeper内部维护了一个层次关系(树状结构)的数据模型,它的表现形式类似于Linux的文件系统,甚至操作的种类都一致。
Zookeeper数据模型中有自己的根目录(/),根目录下有多个子目录,每个子目录后面有若干个文件,由斜杠(/)进行分割的路径,就是一个ZNode,每个 ZNode上都会保存自己的数据内容和一系列属性信息。
Zookeeper模型特性
1、Znode兼具文件和目录两种特点:既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分,并可以具有子Znode。用户对Znode具有增、删、改、查等操作(权限允许的情况下)。
2、Znode具有原子性操作,读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。
3、Znode存储数据大小有限制。ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,常规使用中应该远小于此值。
4、Znode通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。字符串”/zookeeper”用以保存管理信息,比如关键配额信息。
3.3、状态同步
每个节点除了存储数据内容和 node 节点状态信息之外,还存储了已经注册的APP 的状态信息,当有些节点或APP 不可用,就将当前状态同步给其他服务。
3.4、配置中心
现在我们大多数应用都是采用的是分布式开发的应用,搭建到不同的服务器上,我们的配置文件,同一个应用程序的配置文件一样,还有就是多个程序存在相同的配置,当我们配置文件中有个配置属性需要改变,我们需要改变每个程序的配置属性,这样会很麻烦的去修改配置,那么可用使用ZooKeeper 来实现配置中心,ZooKeeper 采用的是推拉相结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据。
Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,此应用比较流行
3.5、集群管理
集群管理,包括集群监控与集群控制两大块,前者侧重对集群运行时状态的收集,后者则是对集群进行操作与控制,在日常开发和运维过程中,我们经常会有类似于如下的需求:
1、希望知道当前集群中究竟有多少机器在工作。
2、对集群中每台机器的运行时状态进行数据收集。对集群中机器进行上下线操作。
ZooKeeper 具有以下两大特性:
1、客户端如果对ZooKeeper的一个数据节点注册Watcher监听,那么当该数据节点的内容或是其子节点列表发生变更时,ZooKeeper服务器就会向已注册订阅的客户端发送变更通知。
2、对在ZooKeeper上创建的临时节点,一旦客户端与服务器之间的会话失效,那么该临时节点也就被自动清除。
Watcher(事件监听器)是 Zookeeper 中的一个很重要的特性。Zookeeper 允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 Zookeeper 实现分布式协调服务的重要特性。
3.6、Zookeeper服务流程
1、生产者启动
2、生产者注册至zookeeper
3、消费者启动并订阅频道
4、zookeeper 通知消费者事件
5、消费者调用生产者
6、监控中心负责统计和监控服务状态
4、Zookeeper单机部署
4.1、配置java环境
1、可联网
Ubuntu操作系统
# yum -y install openjdk-8-jdk
# java -version 正常输出版本信息即可
Centos系列操作系统
# apt -y install openjdk-8-jdk
# java -version 正常输出版本信息即可
2、不可联网
2.1 提前登录oracle官网,下载好jdk软件包,使用工具将包传至需要部署的目录即可,示例为下载了jdk-8u191-linux-x64.tar.gz版本的jdk包,部署在了/app目录下
# cd /app && tar -zxvf jdk-8u191-linux-x64.tar.gz
# ls /app
-rw-r--r-- 1 hrfax hrfax 183M 7月 5 15:10 jdk-8u191-linux-x64.tar.gz
drwxr-xr-x 7 hrfax hrfax 4.0K 10月 6 2018 jdk1.8.0_191
2.2 配置环境变量
echo 'export JAVA_HOME=/app/jdk1.8.0_191
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin' >> /etc/profile
# source /etc/profile
# java -version #有如下内容输出,则java环境变量配置完成
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
4.2、部署Zookeeper
zookeeper官网:https://zookeeper.apache.org/
官网各版本下载地址:https://archive.apache.org/dist/zookeeper/
官网文档:https://zookeeper.apache.org/doc/
部署示例:
# 官网下载
wget -P /usr/local/src https://archive.apache.org/dist/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz
# 国内镜像下载
wget -P /usr/local/src https://mirrors.aliyun.com/apache/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz
# 解压
cd /usr/local/src && tar -zxvf apache-zookeeper-3.8.0-bin.tar.gz -C /usr/local
# 建立软连接,为后续版本做兼容,升级版本仅更新软连接即可
ln -s /usr/local/apache-zookeeper-3.8.0-bin /usr/local/zookeeper
# 配置环境变量
echo 'PATH=/usr/local/zookeeper/bin:$PATH' > /etc/profile.d/zookeeper.sh
source /etc/profile.d/zookeeper.sh
# 配置替换,官网提供了一个示例配置,可以直接copy成zoo.cfg即可
cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
默认配置及含义如下:
grep -v "#" /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000 #"滴答时间",用于配置Zookeeper中最小的时间单元长度,单位毫秒,是其它时间配置的基础
initLimit=10 #初始化时间,包含启动和数据同步,其值是tickTime的倍数
syncLimit=5 #正常工作,心跳监测的时间间隔,其值是tickTime的倍数
dataDir=/tmp/zookeeper #配置Zookeeper服务存储数据的目录,基于安全,可以修改为
dataDir=/usr/local/zookeeper/data #dataLogdir=/usr/local/zookeeper/logs #可以指定日志路径
clientPort=2181 #配置当前Zookeeper服务对外暴露的端口,用户客户端和服务端建立连接会话
autopurge.snapRetainCount=3 #3.4.0中的新增功能:启用后,ZooKeeper 自动清除功能,会将只保留此最新3个快照和相应的事务日志,并分别保留在dataDir 和dataLogDir中,删除其余部分,默认值为3,最小值为3
autopurge.purgeInterval=24 #3.4.0及之后版本,ZK提供了自动清理日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是 0,表示不开启自动清理功能
4.3、启动、验证Zookeeper
# 查看选项
zkServer.sh --help
# 前台启动观察启动过程
zkServer.sh start-foreground
# 后台启动
zkServer.sh start
#注意:如果配置service,zkServer.sh和systemctl不要混用,否则无法启动
# 查看Zookeeper状态
zkServer.sh status
# 查看端口是否启动
netstat -tnlp|grep 2181
5、Zookeeper集群介绍及部署
5.1、Zookeeper集群介绍
ZooKeeper集群用于解决单点和单机性能及数据高可用等问题。
5.2、集群模型
zookeeper集群基于Master/Slave的模型,处于主要地位(处理写操作)的主机称为Master(Leader)节点,处于次要地位(处理读操作)的主机称为 slave(Follower)节点,生产中读取的方式一般是以异步复制方式来实现的。
对于n台server,每个server都知道彼此的存在。只要有>n/2台server节点可用,整个zookeeper系统保持可用。因此zookeeper集群通常由奇数台Server节点组成
当进行写操作时,由leader完成,并且同步到其它follower节点,当在保证写操作在所有节点的总数过半后,才会认为写操作成功,n必须为基数个,防止资源浪费及脑裂现象发生
5.3、集群角色
序号 | 角色 | 描述 |
---|---|---|
1 | 领导者 (Leader) | 负责处理写入请求的,事务请求的唯一调度和处理者,负责进行投票发起和决议,更新系统状态 |
2 | 跟随者(Follower) | 接收客户请求并向客户端返回结果,在选Leader过程中参与投票 |
3 | 观察者(Observer) | 转交客户端写请求给leader节点,和同步leader状态和Follower唯一区别就是不参与Leader投票,也不参与写操作的”过半写成功”策略 |
4 | 学习者(Learner) | 和leader进行状态同步的节点统称Learner,包括:Follower和Observer |
5 | 客户端(client) | 请求发起方 |
5.4、选举过程
节点角色状态:
- LOOKING:寻找 Leader 状态,处于该状态需要进入选举流程
- LEADING:领导者状态,处于该状态的节点说明是角色已经是Leader
- FOLLOWING:跟随者状态,表示 Leader已经选举出来,当前节点角色是follower
- FOLLOWING:跟随者状态,表示 Leader已经选举出来,当前节点角色是follower
选举ID:
- ZXID(zookeeper transaction id):每个改变 Zookeeper状态的操作都会形成一个对应的zxid。ZXID最大的节点优先选为Leader
- myid:服务器的唯一标识(SID),通过配置 myid 文件指定,集群中唯一,当ZXID一样时,myid大的节点优先选为Leader
具体过程:
当集群中的 zookeeper 节点启动以后,会根据配置文件中指定的 zookeeper节点地址进行leader 选择操作,过程如下:
- 每个zookeeper 都会发出投票,由于是第一次选举leader,因此每个节点都会把自己当做leader角色进行选举,每个zookeeper 的投票中都会包含自己的myid和zxid,此时zookeeper 1 的投票为myid 为 1,初始zxid有一个初始值0x0,后期会随着数据更新而自动变化,zookeeper2 的投票为myid 为2,初始zxid 为初始生成的值。
- 每个节点接受并检查对方的投票信息,比如投票时间、是否状态为LOOKING状态的投票。
- 对比投票,优先检查zxid,如果zxid 不一样则 zxid 大的为leader,如果zxid相同则继续对比myid,myid 大的一方为 leader
- 成为 Leader 的必要条件: Leader 要具有最高的zxid;当集群的规模是 n 时,集群中大多数的机器(至少n/2+1)得到响应并follower 选出的 Leader。
心跳机制:Leader 与 Follower 利用 PING 来感知对方的是否存活,当 Leader无法响应PING 时,将重新发起 Leader 选举。
ZAB协议:
ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB(Zookeeper Atomic Broadcast) 协议就会进入恢复模式并选举产生新的Leader服务器。过程如下:
- Leader Election(选举阶段):节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。
- Discovery(发现阶段):在这个阶段,followers 跟准 leader 进行通信,同步 followers 最近接收的事务提议。
- Synchronization(同步阶段):同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。同步完成之后 准 leader 才会成为真正的 leader。
- Broadcast(广播阶段) :到了这个阶段,Zookeeper 集群才能正式对外提供事务服务,并且leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步
5.5、Zookeeper集群部署
5.5.1、环境准备
#三台CentOS或者Ubuntu服务器
zookeeper-node1.haoge.org 192.168.0.101
zookeeper-node2.haoge.org 192.168.0.102
zookeeper-node3.haoge.org 192.168.0.103
#在三个节点都安装JDK,CentOS使用如下命令:
yum -y install openjdk-8-jdk
#在三个节点都安装JDK,Ubuntu使用如下命令:
apt update
apt -y install openjdk-8-jdk
5.5.2、所有节点下载并解压Zookeeper包文件
# 下载包
wget -P /usr/local/src https://downloads.apache.org/zookeeper/stable/apache-zookeeper-3.6.3-bin.tar.gz
# 解压包
tar xf /usr/local/src/apache-zookeeper-3.6.3-bin.tar.gz -C /usr/local/
# 创建软连接
ln -s /usr/local/apache-zookeeper-3.6.3-bin /usr/local/zookeeper
# 配置环境变量
echo 'PATH=/usr/local/zookeeper/bin:$PATH' > /etc/profile.d/zookeeper.sh
# 加载环境变量
. /etc/profile.d/zookeeper.sh
5.5.3、准备配置文件
# 三个节点都要创建数据目录
mkdir /usr/local/zookeeper/data
#基于模板配置文件生成配置文件
cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
#修改配置文件
vim /usr/local/zookeeper/conf/zoo.cfg
#配置文件内容如下
tickTime=2000 #服务器与服务器之间的单次心跳检测时间间隔,单位为毫秒
initLimit=10 #集群中leader 服务器与follower服务器初始连接心跳次数,即多少个 2000 毫秒
syncLimit=5 #leader 与follower之间连接完成之后,后期检测发送和应答的心跳次数,如果该follower在设置的时间内(5*2000)不能与 leader 进行通信,那么此 follower将被视为不可用。
dataDir=/usr/local/zookeeper/data #自定义的zookeeper保存数据的目录
clientPort=2181 #客户端连接 Zookeeper 服务器的端口,Zookeeper会监听这个端口,接受客户端的
访问请求
maxClientCnxns=128 #单个客户端IP 可以和zookeeper保持的连接数
autopurge.snapRetainCount=3 #3.4.0中的新增功能:启用后,ZooKeeper 自动清除功能,会将只保留此最新3个快照和相应的事务日志,并分别保留在dataDir 和dataLogDir中,删除其余部分,默认值为3,最小值为3
autopurge.purgeInterval=24 #3.4.0及之后版本,ZK提供了自动清理日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是 0,表示不开启自动清理功能
#格式: server.服务器唯一编号=服务器IP:Leader和Follower的数据同步端口(只有leader才会打开):Leader和Follower选举端口(L和F都有)
server.1=192.168.0.101:2888:3888
server.2=192.168.0.102:2888:3888
server.3=192.168.0.103:2888:3888
#如果添加节点,只需要在所有节点上添加新节点的上面形式的配置行,在新节点创建myid文件,并重启所有节点服务即可
# 将配置同步到其他两个节点
scp /usr/local/zookeeper/conf/zoo.cfg 192.168.0.102:/usr/local/zookeeper/conf/
scp /usr/local/zookeeper/conf/zoo.cfg 192.168.0.103:/usr/local/zookeeper/conf/
5.5.4、各节点生成ID文件
注意: 各个myid文件的内容要和zoo.cfg文件相匹配
# 第一个节点:
echo 1 > /usr/local/zookeeper/data/myid
# 第二个节点:
echo 2 > /usr/local/zookeeper/data/myid
# 第三个节点:
echo 3 > /usr/local/zookeeper/data/myid
5.5.5、各服务器启动Zookeeper
# 分别登录三台机器,启动zk服务
zkServer.sh start
# 如启动失败,可进入目录查看具体日志报错信息
cd /usr/local/zookeeper/logs/
5.5.5.6、查看集群状态
# 分别查看状态,可看到有一个leader,两个follower 角色
zkServer.sh status
# 只有leader节点能看到2888端口
ss -tnl|grep 888
6、客户端访问
6.1、命令行客户端访问Zookeeper
# 连接当前机器zk
zkCli.sh -server localhost:2181
# 进入到zk命令行
[zk: localhost:2181(CONNECTED) 0] ls
[zk: localhost:2181(CONNECTED) 0] # TAB命令可以列出所有支持命令
addWatch addauth close config connect
create delete deleteall delquota get
getAcl getAllChildrenNumber getEphemerals history listquota
ls printwatches quit reconfig redo
removewatches set setAcl setquota stat
sync version whoami
#默认创建持久节点,即退出不丢失,create -e 可以创建临时节点(退出就丢失)
#持久节点才支持创建子节点,临时节点不支持,如: create /app1/subapp1 "subnode"
[zk: localhost:2181(CONNECTED) 0] create /app1 "hello,zookeeper"
[zk: localhost:2181(CONNECTED) 0] get /app1
hello,zookeeper
#修改已有节点的值
[zk: localhost:2181(CONNECTED) 0] set /app1 "hello,world"
[zk: localhost:2181(CONNECTED) 0] get /app1 "hello,world"
hello,world
#删除不包含子节点的节点(相当于rmdir),如果想删除所有节点内的数据,使用deleteall /path(相当于rm -rf)
[zk: localhost:2181(CONNECTED) 0] delete /app1
#查看已知节点
[zk: localhost:2181(CONNECTED) 0] stat /zookeeper
xid = Ox0 #节点创建时的zxid
ctime = Thu Jan 01 08:00:00 CST 1970 #节点创建时间
mzxid = Ox0 #节点最近一次更新时的zxid
mtime = Thu Jan 01 08:00:00 cST 1970 #节点最近一次更新的时间
pzxid = Ox0 #父节点创建时的zxid
cversion = -1 #子节点数据更新次数
dataversion = 0 #本节点数据更新次数
aclversion = o #节点ACL(授权信息)的更新次数
ephemera10wner = Ox0 #持久节点值为0,临时节点值为sessionid
dataLength = 0 #节点数据长度
numchi1dren = 1 #子节点个数
# 退出zk客户端
[zk: localhost:2181(CONNECTED) 0] quit
6.2 、nc访问Zookeeper
ZooKeeper支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper服务的当前状态及相关信息。用户在客户端可以通过 netcat 或telnet向zookeeper发送下面命令
常见命令列表
conf #输出相关服务配置的详细信息
cons #列出所有连接到服务器的客户端的完全的连接/会话的详细信息
envi #输出关于服务环境的详细信息
dump #列出未经处理的会话和临时节点
stat #查看哪个节点被选择作为Follower或者Leader
ruok #测试是否启动了该Server,若回复imok表示已经启动
mntr #输出一些运行时信息
reqs #列出未经处理的请求
wchs #列出服务器watch的简要信息
wchc #通过session列出服务器watch的详细信息
wchp #通过路径列出服务器watch的详细信息
srvr #输出服务的所有信息
srst #重置服务器统计信息
kill #关掉Server
isro #查看该服务的节点权限信息
命令安全限制
#默认情况下,这些4字命令有可能会被拒绝,发送如下报错
xxx is not executed because it is not in the whitelist.
#解决办法:在 zoo.cfg文件中添加如下配置,如果是集群需要在所有节点上添加下面配置
# vim conf/zoo.cfg
4lw.commands.whitelist=*
#在服务状态查看命令中有很多存在隐患的命令,所以为了避免生产中因为这些命令的安全隐患,所以我们要对
这些命令进行一些安全限制,只需要编辑服务的zoo.cfg文件即可
# vim conf/zoo.cfg
4lw.commands.whitelist=stat,ruok,conf,isro
使用示例
ubuntu系统需要安装netcat
#apt -y install netcat-traditional
#查看节点服务状态
echo stat | nc 127.0.0.1 2181
#查看节点服务配置
echo conf | nc 127.0.0.1 2181
#查看节点服务环境
echo envi | nc 127.0.0.1 2181
#查看节点服务会话
echo cons | nc 127.0.0.1 2181
echo dump | nc 127.0.0.1 2181
最后编辑:于浩 更新时间:2024-02-06 11:18