ZooKeeper
是一个分布式开源的分布式应用协调服务。它公开了一组简单的原语,分布式应用程序可以在其基础上实现用于同步、配置维护以及分组和命名的更高级别服务。它的设计便于编程,并使用了一种熟悉的文件系统目录树结构样式的数据模型。它使用Java语言编写,并且有针对Java和C的客户端。
众所周知,协调服务很难做好。它们特别容易出现竞争条件和死锁等错误。ZooKeeper
背后的动机是为了减轻分布式应用从头开始实现协调服务的压力。
简单
ZooKeeper
允许分布式进程通过一个共享的分层命名空间来相互协调,这个命名空间的组织方式类似于一个标准的文件系统。命名空间由数据寄存器组成,在ZooKeeper
中称为znodes,它们类似于文件和目录。与为存储而设计的典型文件系统不同,ZooKeeper的数据保存在内存中,这意味着ZooKeeper
可以实现高吞吐量和低延迟数。
ZooKeeper
的实现重视高性能、高可用性、严格有序的访问。ZooKeeper
的性能意味着它可以用于大型分布式系统。可靠性方面使它不会成为单点故障。严格的排序意味着可以在客户机上实现复杂的同步。
可备份
就像它所协调的分布式进程一样,ZooKeeper
本身也被用于在一组称为集群的主机上进行复制
组成ZooKeeper服务的服务器必须相互了解。它们在内存中维护状态快照,并在持久存储中维护事务日志和快照。只要大多数服务器可用,ZooKeeper服务就可用。
客户端连接单个ZooKeeper服务器。客户机维护一个TCP连接,通过该连接发送请求、获取响应、获取监视事件和发送心跳。如果与服务器的TCP连接中断,客户端将连接到另一个服务器
有序
ZooKeeper用一个数字标记每个更新,这个数字反映了所有ZooKeeper事务的顺序。后续操作可以使用该顺序来实现更高级的抽象,比如同步原语
快速
它在“读为主”的工作负载中尤其快。ZooKeeper应用程序运行在数千台机器上,在读比写更常见的地方性能最好,其比率约为10:1
ZooKeeper
提供的命名空间很像标准的文件系统。名称是由斜杠(/)分隔的路径元素序列。ZooKeeper
命名空间中的每个节点都由路径标识
与标准文件系统不同,ZooKeeper
名称空间中的每个节点都可以有与其关联的数据以及子节点。这就像拥有一个文件系统,它允许一个文件同时也是一个目录。(ZooKeeper被设计用来存储协调数据:状态信息、配置、位置信息等,所以每个节点存储的数据通常很小,以字节到千字节为单位) 我们使用术语znode来表明我们谈论的ZooKeeper
数据节点
Znodes
维护一个统计结构,其中包括数据更改的版本号、ACL更改和时间戳,以允许缓存验证和协调更新。每次znode的数据发生变化,版本号就会增加。例如,每当客户机检索数据时,它也会接收数据的版本。
存储在名称空间中的每个znode
中的数据是原子地读取和写入的。读操作获取与znode
相关的所有数据字节,写操作替换所有数据。每个节点都有一个访问控制列表(Access Control List, ACL),用于限制谁可以做什么。
ZooKeeper
也有临时节点的概念。只要创建znode
的会话处于活动状态,这些临时节点就存在。当会话结束时,临时节点也被删除
ZooKeeper
支持监听器的概念,客户端可以在一个znode
节点上设置监听,监听器watcher
可以通过节点的变化来触发和删除。当一个watch
被触发时,客户端会收到一个通知znode
已经改变的数据包。当客户端与ZooKeeper
服务器之间的连接中断时,客户端会收到本地通知。
3.6.0 版本新特性:客户端还可以在一个znode上设置永久的递归监视,该监视在触发时不会删除,并递归地触发已注册的znode
以及任何子节点上的变化
ZooKeeper
非常快速和简单。但是,由于它的目标是成为更复杂的服务(如同步)构造的基础,因此它具有如下几个保证数据一致性的特性:
ZooKeeper
的设计目标之一就是提供一个非常简单的编程界面。因此,它只支持这些操作
下载地址:https://zookeeper.apache.org/
我下的是最新的稳定版本压缩包:apache-zookeeper-3.7.1-bin.tar.gz
tar zxvf apache-zookeeper-3.7.1-bin.tar.gz
执行重命名命令:mv apache-zookeeper-3.7.1-bin zookeeper-3.7.1
执行以下命令进入配置项目录: cd ./zookeeper-3.7.1/cfg
执行拷贝zoo_sample.cfg文件并重命名为zoo.cfg命令: cp zoo_sample.cfg zoo.cfg
执行编辑zoo.cfg
命令vim zoo.cfg
可以看到其中的配置项;
简化以下配置文件:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper-3.7.1/data
dataLogDir=/usr/local/zookeeper-3.7.1/logs
如何改cd到/usr/local/zookeeper-3.7.1
目录通过下面的命令创建data和logs目录
mkdir data logs
进入到/usr/local/zookeeper-3.7.1/bin
目录下
可通过下面的方式将zookeeper/bin
目录加入到环境变量
# 编辑环境变量
vim /etc/profile
# 在开发的文件中按住i键进入编辑状态后在CLASSPATH变量后面暴露zookeeper的环境变量
export ZOOKEEPER_HOME=/usr/local/zookeeper-3.7.1
PATH=$ZOOKEEPER_HOME/bin:$JAVA_HOME/bin:$PATH
# 然后按住esc键输入:wq后保存退出
# 输入如下的命令使配置的环境变量生效
source /etc/profile
这样就可以在任服务器的任意目录下运行zkServer.sh和zkCli.sh命令了,无需进入zookeeper的bin目录下执行
启动服务和建立客户端连接命令
打开命令行工具运行zkServer.sh start
命令,运行成功后控制太显示如下信息表示zookeeper服务启动成功
Starting zookeeper ... STARTED
ZooKeeper
启动成功后可通过下面的命令停止zookeeper
服务
zkServer.sh stop
关闭成功后会在命令控制台看到如下信息:
Stopping zookeeper ... STOPPED
在启动ZooKeeper
服务的前提下,打开一个新的客户端会话,在命令行中输入如下命令
zkCli.sh
运行成功后会看到客户端连接成功日志,最后可以在命令行中看到入戏控制台信息
[zk: localhost:2181(CONNECTED) 0]
关于API的使用下一篇文章我们再介绍
由于是在单机环境下模拟集群环境, 因而需要使用不同端口来模拟不同主机
cd /usr/local/zookeeper-3.7.1/cfg
cp zoo.cfg zoo1.cfg
cp zoo.cfg zoo2.cfg
cp zoo.cfg zoo3.cfg
# 切换到zookeeper主目录
cd ../
# 执行创建过个目录命令
mkdir data_1 data_2 data_3 logs_1 logs_2 logs_3
echo "1" > ./data_1/myid
echo "2" > ./data_2/myid
echo "3" > ./data_3/myid
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper-3.7.1/data_1
clientPort=2181
dataLogDir=/usr/local/zookeeper-3.7.1/logs_1
# server.x中的x和myid中的值保持一致,第一个端口用于Leader和Learner之间的同步通信,第二个端口用于选举过程中的投票通信
server.1=localhost:2887:3887
server.2=localhost:2888:3888
server.3=localhost:2889:3889
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper-3.7.1/data_2
clientPort=2182
dataLogDir=/usr/local/zookeeper-3.7.1/logs_2
# server.x中的x和myid中的值保持一致,第一个端口用于Leader和Learner之间的同步通信,第二个端口用于选举过程中的投票通信
server.1=localhost:2887:3887
server.2=localhost:2888:3888
server.3=localhost:2889:3889
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper-3.7.1/data_3
clientPort=2183
dataLogDir=/usr/local/zookeeper-3.7.1/logs_3
# server.x中的x和myid中的值保持一致,第一个端口用于Leader和Learner之间的同步通信,第二个端口用于选举过程中的投票通信
server.1=localhost:2887:3887
server.2=localhost:2888:3888
server.3=localhost:2889:3889
在zookeeper
主目录下的命令控制台中依次执行下面三条命令
zkServer.sh start ./conf/zoo1.cfg
zkServer.sh start ./conf/zoo2.cfg
zkServer.sh start ./conf/zoo3.cfg
以上每输入一条命令回车后控制台都会有表示ZK服务节点启动成功的信息
Starting zookeeper ... STARTED
在zookeeper
主目录下的命令控制台中依次执行如下命令
zkServer.sh status ./conf/zoo1.cfg
zkServer.sh status ./conf/zoo2.cfg
zkServer.sh status ./conf/zoo3.cfg
可以看到如下信息:
Server1: Mode: follower
Server2: Mode: leader
Server2: Mode: follower
打开三个客户端分别连上三个服务端
zkCli.sh -server localhost:2181
zkCli.sh -server localhost:2182
zkCli.sh -server localhost:2183
连上之后可以看到在三个客户端执行 ls /
命令 可以分别查到三个Server的当前目录结构都是一致的,都是[zookeeper]
在连接Server1的客户端命令控制台中输入创建节点命令
create /firstNode serverCreated
然后执行获取新创建节点数据命令:
get /firstNode
可以看到serverCreated
信息
在连接Server2
和Server3
的客户端命令控制台执行get /firstNode
命令也可以看到相同的信息
说明在集群模式下任意一个服务端节点创建了节点数据,都会同步到另外的ZK服务节点中去
zoo4.cfg节点配置中增加如下配置
# zoo4.cfg中单独添加
peerType=observer
#servers列表中增加(集群中的所有zoox.cfg都需要添加)
server.4=localhost:2890:3890
本文首发个人微信公众号【阿福谈Web编程】, 欢迎读者朋友们加个关注一起交流学习技术。