ZooKeeper 基础与安装
基础知识
开发框架
-
ORM - 一台主机承载所有的业务应用
-
MVC - 多台主机分别承载业务应用的不同功能,通过简单的网络通信实现业务的正常访问
-
RPC - 应用业务拆分、多应用共用功能、核心业务功能 独立部署,基于远程过程调用技术(RPC)的分布式服
-
务框架 提高业务功能复用及项目的整合
-
SOA - 粗放型的RPC分布式实现了大量的资源浪费,提高机器利用率的 资源调度和治理中心(SOA) ,基于
现有资源的高效利用,进一步提高服务的能力
-
微服务 - 随着互联网的发展、各种技术的平台工具出现、编程语言的升级、开发规范的标准化等因素,中小
型企业也有了相应的能力来发展更轻量级的SOA模式。
在微服务架构的场景中,有一个组件服务Service Registry,它是整个"微服务架构"中的核心,主要提供了 四个功能:服务注册和服务发现、下线处理、健康检测等。
服务注册:当服务启动后,将当前服务的相关配置信息都注册到一个公共的组件 -- Service Registry中。 服务发现:当客户端调用操作某些已注册服务 或者 服务的新增或删除等,通过从Service Registry中读取这些 服务配置的过程。
目前,Service Registry的最佳解决方案就是Zookeeper。这就是我们要学习Zookeeper的目的之一。
分布式特性
目前来说,随着互联网的发展,各种软件技术,尤其是设备计算能力的提升,所以很多企业在项目的开启就应 用了 分布式架构。在分布式系统中各个节点之间的协作是通过高效网络进行消息数据传递,实现业务内部多 个服务的通信和协调,基于服务本地设备的性能实现资源的高效利用。
分布式系统的设计目标通常包括几个方面:
- 可用性:可用性是分布式系统的核心需求,衡量了一个分布式系统持续对外提供服务的能力。
- 可扩展性:增加及其后不会改变或者极少改变系统行为,并且获得相似的线性的性能提升
- 容错性:系统发生错误时,具有对错误进行规避以及从错误中恢复的能力
- 性能:对外服务的响应延时和吞吐率要满足用户的需求
一致性协议
我们为了满足分布式的各种场景需求,先后提出了 ACID、CAP、BASE等理论 ,其目的就是 在项目架构正常的运行过程中,即时出现各种问题,也能够保证业务保持基本可用的目标。
那么,我们在 项目架构在运行过程中 为了保证 业务保持基本可用 过程中定制的各种规约或者通信格 式,都可以将其称为 一致性协议。 一般情况下,我们会基于 集群的方式实现分布式的 可用性、可扩展性、容错性等的目标,那么我们如 何保证集群中的数据的一致性呢?
一般情况下,我们会基于 集群的方式实现分布式的 可用性、可扩展性、容错性等的目标,这个时候, 集群中各个主机之间的通信信息是否一致的就非常重要了。所谓的一致性是集群内部各个主机系统对外呈现的状态是否一致,即时业务出现问题的时候,这是所有的节点也要达成一个错误的共识。如果各个主机之间通信的数据不一致,就会导致各种分布式的场景问题。
在一个集群系统中,为了保证所有的主机系统能够处于一种相对的平衡状态,我们一般会基于传递数据本 身和主机角色的方式来实现,所以我们可以从两个方面来进行分析: 数据本身:将所有的更新数据,同步到整个集群系统,保证数据的最终一致性。 主机角色:client向多个server主机系统发起访问(包括并行访问)请求时,如何获取相同的更新后数据。
分类 | 解析 |
---|---|
状态复制机 (StateMachineReplication) | 一个服务端集群,有多个server主机组成,每个server主机的更新都在本地实现。每个服务端都有一个一致性模块来接收客户端请求,没接收一次用户请求,一致性模块的状态就发生改变,通过 状态机系统 对所有的一致性模块的状态进行管控,只要所有的模块状态是一样的,那么server主机本地执行后的最终数据值就是一样的,从 而实现服务的容错效果。GFS、HDFS、Chubby、ZooKeeper和etcd等分布式系统都是基于复制状态机模型实现的。 |
拜占庭将军问题 (Byzantine Failures) | 一个服务端集群,有多个server主机组成,每个server主机接收到client请求后,根据自己本身的特性进行分析并给出执行的策略,多个server主机通过专用的通讯方式来进行协商,并达成最终的共识结果(少数服从多数),然后按照最终的结果进行操作执行,从而实现服务的容错效果。 |
FLP定理 (Fischer,Lynch ,Patterson) | 三位科学家在1985年发表的分布式理论,最小化异步网络通信场景下,因为消息通信是延迟的,所以可能会出现 只有一个节点故障(没被其他节点发现)时,其他节点不能达成一致。这证明了在异步场景中永远无法避免的一种现象。比如:三台主机ABC异步方式通信,在正常协商之间,因为C主机突然网络故障,导致无法实现剩余两台的少数服从多数,从而导致业务终止执行。 |
ZooKeeper 简介
Zookeeper,英文字面意思就是"动物管理员",因为动物园里面的所有动物的特殊性,需要管理员必须具备 观察动物状态和管理动物行为等方面的协调的能力,为动物们建立友好生存的生活环境。Zookeeper就是纷乱 的软件服务世界中的一名管理者,为繁杂的软件服务环境提供统一的协调管理服务。
可以想象为 Pig hive hadoop HAMA 等框架的logo都是动物的象形,zookeeper 相当于铲屎官,帮他们解决大小便
Zookeeper是Yahoo基于 Google的 Chubby 论文实现的一款解决分布式数据一致性问题的开源实现,它 是使用Java语言开发的,目前是Hadoop项目中的一个子项目。它在Hadoop、HBase、Kafka、Dubbo等技 术中充当了非常重要的核心组件角色。
官方网站:https://zookeeper.apache.org/ 最新版本:3.7.0
环境安装
搭建java环境
zookeeper 是依赖于java环境的,所以我们需要提前定制java环境
创建目录
mkdir /data/{softs,server} -p
cd /data/softs
下载java或者上传java
ls /data/softs
安装java
tar xf jdk-8u121-linux-x64.tar.gz -C /data/server
cd /data/server/
ln -s jdk1.8.0_121 java
配置java环境变量
echo 'export JAVA_HOME=/data/server/java' >> /etc/profile
echo 'export JRE_HOME=$JAVA_HOME/jre' >> /etc/profile
echo 'export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar' >>
/etc/profile
echo 'export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH' >> /etc/profile
source /etc/profile
检查效果
java -version
检查java目录效果
tree -L 1 /data/server/java/
安装软件
软件准备
cd /data/softs
wget http://archive.apache.org/dist/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
wget http://archive.apache.org/dist/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz.asc
校验软件
gpg --verify apache-zookeeper-3.7.0-bin.tar.gz.asc
对比 MD5 码一致后进行解压安装
tar zxvf apache-zookeeper-3.7.0-bin.tar.gz -C /data/server
cd /data/server
ln -s apache-zookeeper-3.7.0-bin zookeeper
echo 'export PATH=/data/server/zookeeper/bin:$PATH' > /etc/profile.d/zk.sh
source /etc/profile.d/zk.sh
修改配置文件
查看配置模板文件
cat zookeeper/conf/zoo_sample.cfg
grep -ni '^[a-Z]' zookeeper/conf/zoo_sample.cfg
设置配置文件
cp conf/zoo_sample.cfg conf/zoo.cfg
默认读取配置文件名 zoo.cfg
配置文件常用参数
- tickTime :"滴答时间",用于配置 Zookeeper中最小的时间单元长度,单位毫秒,是其他时间配置的基础
- initLimit:初始化时间,包含启动和数据同步,其值是tickTime的倍数
- syncLimit :正常工作,心跳监测的时间间隔,其值是tickTime的倍数
- dataDir :配置Zookeeper服务存储数据的目录
- clientPort:配置当前Zookeeper服务对外暴露的端口,用户客户端和服务端建立连接会话
启动服务
在Zookeeper的bin目录下有很多执行文件,其中zkServer.sh是启动服务的脚本文件
ls bin/
查看帮助信息
bin/zkServer.sh
命令参数功能详解
start:用于后台启动Zookeeper服务器
start-foreground:用于前台启动Zookeeper服务器,常用来排查失败原因
stop:用于关闭Zookeeper服务器
restart:用于重启Zookeeper服务器
status:用于查看Zookeeper服务器状态
upgrade:用于升级Zookeeper服务器
print-cmd:用于打印Zookeeper程序命令行及其相关启动参数
启动服务
bin/zkServer.sh start
检查服务状态
Zookeeper的检查有很多种方式,主要有以下四种:端口、服务、进程、连接
端口检查
netstat -tnulp | grep 2181
服务检查
bin/zkServer.sh status
进程检查
ps aux | grep zoo
连接检查
bin/zkCli.sh
进阶实践
在生产中,我们一般会讲Zookeeper的数据目录和日志目录都放在一个专用的路径下,而我们刚才实践 的效果是数据目录在临时文件夹/tmp下,而且没有设置日志文件配置信息,那么接下来我们就按照生产环境的 部署方法先来做一个单机版的Zookeeper环境。
关闭刚才的服务
bin/zkServer.sh stop
创建专用的数据和日志目录
cd /data/server/zookeeper
mkdir {data,logs}
在默认的配置文件中,没有日志的配置项,日志的配置项是dataLogDir
# vim conf/zoo.cfg
# grep -ni '^[a-Z]' conf/zoo.cfg
2:tickTime=2000
5:initLimit=10
8:syncLimit=5
12:dataDir=/data/server/zookeeper/data
13:dataLogDir=/data/server/zookeeper/logs
15:clientPort=2181
启动之前注意权限
ll
chown 1000.1000 -R /data/server/zookeeper*
启动当前Zookeeper的服务
bin/zkServer.sh start
三种方式查看不同的关注点
bin/zkServer.sh status
ps aux | grep zoo
bin/zkCli.sh
查看产生的数据
ls /data/server/zookeeper/data/
ls /data/server/zookeeper/logs/
本地连接服务
当Zookeeper服务器正常启动后,我们就可以使用Zookeeper自带的zkCli.sh脚本,以命令行的方式 连接到Zookeeper。使用方法非常简单:
bin/zkCli.sh
如果出现下面信息,就表示命令行客户端已经成功连入到Zookeeper
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]
远程连接服务
zkCli.sh 脚本还提供了远程连接非本地的Zookeeper服务器的参数 -server,使用这个参数就可以连接 到远程的Zookeeper服务主机
zkCli.sh 脚本还提供了远程连接非本地的Zookeeper服务器的参数 -server,使用这个参数就可以连接
到远程的Zookeeper服务主机
命令格式:
bin/zkCli.sh -server <zk_ip>:<zk_port>
远程连接
bin/zkCli.sh -server 192.168.8.14:2181
命令帮助
当客户端成功的连接到Zookeeper服务后,我们可以输入任意非法的命令都可以获取Zookeeper客户端 相关的命令使用方法。
连接到Zookeeper服务后,输入help查看相关命令
ZooKeeper -server host:port cmd args 宿主机命令行执行Zookeeper客户端命令
stat path [watch] 查看节点状态或者判断结点是否存在
set path data [version] 设置节点数据
ls path [watch] 列出 节点信息
delquota [-n|-b] path 删除节点个数(-n)或数据长度(-b)配额
ls2 path [watch] ls命令的加强版,列出更多信息
setAcl path acl 设置节点的权限信息
setquota -n|-b val path 设置节点个数(-n)或数据长度(-b)的配额
history 列出最近的命令历史,可以和redo配合使用
redo cmdid 再次执行某个命令,结合history使用
printwatches on|off 设置和显示监视状态
delete path [version] 删除节点,不可删除有子节点的节点
sync path 强制数据同步
listquota path 显示节点资源配额信息
rmr path 强制删除节点
get path [watch] 获取节点数据
create [-s] [-e] path data acl 创建顺序(-s)或临时(-e)结点
addauth scheme auth 配置节点认证信息
quit 退出连接
getAcl path 获取节点的权限信息
close 断开当前Zookeeper连接
connect host:port 连接Zookeeper服务端
使用close命令可以关闭当前的连接
使用quit命令可以退出Zookeeper服务
使用connect host:port命令可以重新连接Zookeeper服务 connect 192.168.8.14:2181
这些命令主要分为五大类:基本信息查看、节点基本操作、资源配额、权限设置、其他操作等
信息查看
节点列表
关于节点列表主要有两种命令ls和ls2,他们的意思都是"获取路径下的节点信息" 命令格式:
ls path 显示当前的节点列表
注意:
此path路径为绝对路径
显示普通效果
[zk: 127.0.0.1:2181(CONNECTED) 4] ls /
[zookeeper]
注意:
该结果表示Zookeeper服务端的根目录下有一个Zookeeper的子节点,
它是Zookeeper的保留节点,一般不用。
节点状态
stat命令作用:判断节点是否存在,节点不存在则报错,否则显示节点的状态信息,
命令格式:
stat [ -w ] path
注意:
注意事项同ls
查看未知节点
[zk: 127.0.0.1:2181(CONNECTED) 7] stat /nihao
Node does not exist: /nihao
查看已知节点
[zk: 127.0.0.1:2181(CONNECTED) 8] stat /zookeeper
cZxid = 0x0 节点创建时的zxid
ctime = Thu Jan 01 08:00:00 CST 1970 节点创建时间
mZxid = 0x0 节点最近一次更新时的zxid
mtime = Thu Jan 01 08:00:00 CST 1970 节点最近一次更新的时间
pZxid = 0x0 父节点创建时的zxid
cversion = -1 子节点数据更新次数
dataVersion = 0 本节点数据更新次数
aclVersion = 0 节点ACL(授权信息)的更新次数
ephemeralOwner = 0x0 持久节点值为0,临时节点值为sessionid
dataLength = 0 节点数据长度
numChildren = 1 子节点个数
Zookeeper 工作机制
Zookeeper 从设计模式的角度理解:是一个基于观察者模式设计的分布式服务管理框架(监工),它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的哪些观察 者做出相应的反应。
Zookeeper作为一个典型的分布式数据一致性解决方案,依赖Zookeeper的分布式应用程序,可以基于Zookeeper实现数据发布/订阅、负载均衡、命名服务、服务注册与发现、分布式协调/事件通知、集群管理、Leader 选举、 分布式锁和队列 等功能。
特点
- Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
- 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所 以Zookeeper适合安装奇数台服务器。
- 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
- 更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行。
- 数据更新原子性,一次数据更新要么成功,要么失败。
- 实时性,在一定时间范围内,Client能读到最新数据。
角色
基本上所有的集群模式中的主机都有自己的角色,最为典型的集群模式就是 M/S 主备模式。在这种模式下, 我们把处于主要地位(处理写操作)的主机称为 Master 节点,处于次要地位(处理读操作)的主机称为 Slave 节点,生产中读取的方式一般是以异步复制方式来实现的。
Zookeeper集群就是这种M/S的模型,集群通常由2n+1台Server节点组成,每个Server都知道彼此的存 在。对于2n+1台server,只要有>=(n+1)台server节点可用,整个Zookeeper系统保持可用。
角色 | 描述 |
---|---|
领导者 (Leader) | 领导者不接受client读请求,负责进行投票发起和决议,更新系统状态 |
跟随者 (Follower) | 接收客户请求并向客户端返回结果,在选Leader过程中参与投票 |
观察者 (Observer) | 转交客户端写请求给leader节点,和同步leader状态,不参与选主投票 |
学习者(Learner) | 和leader进行状态同步的节点统称Learner,Follower和Observer 都是 |
客户端(client) | 请求发起方 |
Zookeeper集群系统启动时,集群中的主机会选举出一台主机为Leader,其它的就作为Learner(包括 Follower和Observer)。接着由follower来服务client的请求,对于不改变系统一致性状态的读操作, 由follower的本地内存数据库直接给client返回结果;对于会改变Zookeeper系统状态的更新操作,则交 由Leader进行提议投票,超过半数通过后返回将结果给client。
ZAB协议
(Zookeeper Atomic Broadcast,Zookeeper原子广播协议)来保证主从节点数据一致性的,ZAB协议支持「崩溃恢复和消息广播」两种模式,很好解决了这两个问题:
-
崩溃恢复:
Leader挂了,进入该模式,选一个新的leader出来,接着,新的Leader服务器与集群中Follower服务进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式。
-
消息广播:
把更新的数据,从Leader同步到所有Follower Leader 服务器开始接收客户端的事务请求生成事务Proposal进行事务请求处理。
事务id
所谓的事务id -- zxid。ZooKeeper的在选举时通过比较各结点的zxid和机器ID选出新的主结点的。 zxid由Leader节点生成,有新写入事件时,Leader生成新zxid并随提案一起广播,每个结点本地都保存了 当前最近一次事务的zxid,zxid是递增的,所以谁的zxid越大,就表示谁的数据是最新的。
ZXID有两部分组成: 任期:完成本次选举后,直到下次选举前,由同一Leader负责协调写入; 事务计数器:单调递增,每生效一次写入,计数器加一。 --同一任期内,ZXID是连续的,每个结点又都保存着自身最新生效的ZXID,通过对比新提案的ZXID与 自身最新ZXID是否相差“1”,来保证事务严格按照顺序生效的。
数据结构
ZooKeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看作是一棵树,每个 节点称做一个 ZNode。每一个 ZNode 默认能够存储 1MB 的数据,每个 ZNode 都可以通过 其路径唯一标识。
Zookeeper使用这个基于内 存的树状模型来存储分布式数据,正因为所有数据都存放在内存中,所以 才能实现高性能的目的,提高数据的吞吐率。特别是在集群主机节点间的数据同步。
Znode包含了 存储数据(data)、访问权限(acl)、子节点引用(child)、节点状态(stat)信息等信息
注意: 为了保证高吞吐和低延迟,以及数据的一致性,znode只适合存储非常小的数据,不能超过1M,最好都 小于1K
节点类型解析
虽然ZNode的样式跟Linux文件系统类似,根据节点的生命周期,在Zookeeper中的ZNode有四种独有的特 性,有时候页称为四种类型:
基本节点: Persistent(持久节点):会话断开后,除非主动进行移除操作,否则该节点一直存在 Ephemeral(临时节点):会话断开后,该节点被删除
序列节点: Persistent Sequential:按顺序编号的持久节点该节点被创建的时候,Zookeeper 会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀。
Ephemeral Sequential:按顺序编号的临时节点该节点被创建的时候,Zookeeper 会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀
注意: 只有持久性节点(持久节点和顺序持久节点)才有资格创建子节点
自增后缀格式: 10位10进制数的序号
有序和无序区别: 多个客户端同时创建同一无序ZNode节点时,只有一个可创建成功,其它匀失败。并且创建出的节点名称 与创建时指定的节点名完全一样。
多个客户端同时创建同一有序ZNode节点时,都能创建成功,只是序号不同。
Stat 数据结构
Zookeeper 的 ZNode 上都会存储数据,对应于每个 ZNode,Zookeeper 都会为其维护一个叫做 Stat 的数据结构。
Stat 中记录了这个 ZNode 的三个数据版本:
- dataversion 当前 ZNode 数据内容的版本
- cversion 当前 ZNode 子节点的版本
- aversion 当前 ZNode 的 ACL 变更版本。
这里的版本起到了控制 Zookeeper 操作原子性的作用,基于这些功能,才能更好实现了分布式锁的功能。
节点实践
节点创建
使用create命令可以来创建一个节点,命令格式如下:
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
注意:
-s 表示创建的节点是顺序节点。
-e 表示创建的节点是临时节点,这个是create的默认参数。
acl 用于权限控制,Zookeeper的权限控制很强大,默认不使用。
分别创建2个普通节点(永久节点 + 不带序号)
[zk: localhost:2181(CONNECTED) 3] create /sanguo "diaochan"
Created /sanguo
[zk: localhost:2181(CONNECTED) 4] create /sanguo/shuguo
"liubei"
Created /sanguo/shuguo
注意:创建节点时,要赋值
获得节点的值
[zk: localhost:2181(CONNECTED) 5] get -s /sanguo
diaochan
cZxid = 0x100000003
ctime = Wed Aug 29 00:03:23 CST 2018
mZxid = 0x100000003
mtime = Wed Aug 29 00:03:23 CST 2018
pZxid = 0x100000004
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 1
[zk: localhost:2181(CONNECTED) 6] get -s /sanguo/shuguo
liubei
cZxid = 0x100000004
ctime = Wed Aug 29 00:04:35 CST 2018
mZxid = 0x100000004
mtime = Wed Aug 29 00:04:35 CST 2018
pZxid = 0x100000004
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0