本文是对Zookeeper组件基础知识的一个学习总结,包含如下章节内容:
- Zookeeper是什么
- Zk文件系统
- Zk的观察机制
- Zk的设计思路
- 安装和运行
- 命令行程序
一、Zookeeper是什么
ZooKeeper(下面简称Zk)是一个开源的分布式协调服务组件,它为分布式应用提供了高效且可靠的分布式协调服务,提供了诸如统一命名空间服务,配置服务和分布式锁等分布式基础服务。
Zk是一个独立的组件,不依赖其它服务。它本身就是一个分布式应用。作为分布式应用,分为Server(服务器) 和 Client(客户端) 两部分。作为Zk的使用者,可以使用Zk组件提供的客户端(命令行程序)或自己利用Zk提供的api编写客户端程序来访问Zk服务器。
hadoop生态圈中很多分布式组件都使用Zk来作为分布式协调服务,如hdfs HA(High Availability), yarn HA, hbase,kafka等,从这角度看,hbase等就是Zk服务的客户端。当然,也可以使用Zk提供的服务来开发自己的分布式应用程序。
二、Zk文件系统
Zk服务的核心是一个精简的文件系统,类似linux文件系统的树形层次结构,与文件系统节点分目录和文件不同,Zk文件系统中的节点统一称为znode。如下图所示:
Zk文件系统的信息会保存在内存中(以加快读取的速度),同时会进行持久化。
(一)znode的概念
znode通过路径被引用,类似linux文件系统的路径。根节点用/表示,其余节点从/开始加上各层节点的名称,如/zoo/duck。但是与文件系统路径不同,znode没有相对路径的概念,每个节点都以绝对路径标识。
znode既可以作为保存数据的容器(如同文件),也可以作为保存其它znode的容器(如目录)。znode除了可以保存数据外(保存的数据不能太大,一个znode存储的数据被限制在1M以内),znode本身就是一个数据结构,其中的信息称为元数据(如创建时间、子节点信息、版本信息、ACL信息等)。
(二)znode的操作
znode支持如下9种基本操作:
- create:创建znode
- delete:删除znode
- exists:测试一个znode是否存在并且查询它的元数据
- getChildren:获取一个znode的子节点列表
- setACL:设置znode的ACL
- getACL:获取znode的ACL
- setData:设置znode所保存的数据
- getData:获取znode所保存的数据
- sync:将客户端的znode视图与zk服务器同步
(三)znode的类型
znode可分为短暂的(或叫临时的)和持久的。所谓短暂znode,是指创建该节点的客户端会话结束后,该节点会被自动删除。而持久znode的生存期与创建它的客户端会话无关,如果要删除,需要显示的执行命令删除。注意,短暂znode不可以有子节点。
顺序znode:指znode的名称中包含顺序号。当我们创建一个顺序znode时,框架会自动在指定的名称之后附加一个单调递增的计数器值(由父节点维护),并且保证这个计数器值是唯一的。注意,顺序znode可以是持久的,或短暂的。
(四)znode的版本信息
znode有版本信息,对于每个znode来说,均存在三个版本号:
-
dataVersion
数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据),初始值为0。 -
cversion
子节点的版本号。当znode的子节点有变化时,cversion 的值就会增加1,初始值为0。 -
aclVersion
ACL的版本号。
下面以dataVersion (数据版本号)为例来说明Zk中版本号的作用。每一个znode都有一个数据版本号,它随着每次数据变化而自增。ZooKeeper提供的一些API例如setData和delete根据版本号有条件地执行。多个客户端对同一个znode进行操作时,版本号的使用就会显得尤为重要。例如,假设客户端C1对znode /config写入一些配置信息,如果另一个客户端C2同时更新了这个znode,此时C1的版本号已经过期,C1调用setData一定不会成功。这正是版本机制有效避免了数据更新时出现的先后顺序问题。在这个例子中,C1在写入数据时使用的版本号无法匹配,使得操作失败。因此使用版本号可用来阻止并行操作的不一致性。
(五)znode的ACL列表
每个znode都有一个ACL(权限控制列表),用于决定哪个客户端可以对它执行何种操作,也就是说一种权限控制的方式。 znode的ACL列表可以在创建时指定,也可以后续重新设置。如果不加设置,默认所有客户端可以对znode进行任何操作。关于ACL的更详细信息本文不再介绍。
三、Zk的观察机制
当znode的发生变化时,Zk提供一种观察(watch)机制可以让希望获取这个变化信息的客户端得到通知。当一个客户端对一个节点设置了观察,如果该节点发生变化(如被删除、设置数据、添加/删除子节点等),Zk框架会通知设置了观察的客户端。
注意,节点上设置了观察,当节点发生变化后,只会通知一次。如果想再次获取通知,需要重新设置。
四、Zk的设计思路
在集群环境下,Zk通过复制来实现高可用性,只要集群环境下的超过一半机器处于可用状态,它就能提供服务。比如一个集群有5个节点,任意2台机器出现问题,但因为还有3台机器可用,3台超过1半,所以服务可以继续保证。如果集群是6台节点,也最多只能有2台机器出问题,因为如果有3台机器有问题,则可用的没超过一半,服务也不可用。因此,对于Zk的集群,其节点的数量通常配置为奇数个。
集群中的节点分为两种类型:领导者(leader)和跟随着(flower)。 集群中的机器通过一个选择过程来选出领导者,其它的机器就作为跟随者。如果领导者出现故障,其它机器就会选出一个新的领导者。随后,如果之前的领导者恢复,则会成为一个跟随者。
Zk客户端可以连接到任意一台Zk服务器,但是所有的写请求都会被转发给领导者,再由领导者将更新广播给跟随者,当半数以上的跟随者已经将修改持久化之后,领导者才会提交这个更新,然后客户端才会收到一个更新成功的响应。
下面示意图可以简单说明上面描述的内容:
(摘自hadoop权威指南一书)
五、安装和运行
Zk既可以运行在windows系统下,也可以运行在liunux系统下。它有两种不同的运行模式。一种是独立模式,即只有一个Zk服务器,这种模式只适合开发测试环境,不能保证高可用性和可恢复性。另一种是复制模式,运行在集群环境下,至少需要三台机器(启动3个Zk服务)。在本文中,我们使用独立模式来学习Zk的基本概念和操作。
1、下载Zookeeper,本文下载的版本是zookeeper-3.4.10.tar.gz。
将该压缩文件解压到某个目录下。
2、修改conf 下的zoo.cfg文件(如果没有就新建),增加如下的配置信息,最少的配置信息如下(假设我们采用独立模式运行Zk服务器,即只在一台机器上启动单个Zk服务),其它配置信息采用默认值。
tickTime=2000
dataDir= 本地某目录
clientPort=2181
tikeTime是超时时间设置(单位是毫秒);dataDir用于设置一个本地目录,保存Zk文件系统的持久化信息。clientPort是设置Zk服务器的端口号。
3、启动Zk服务器
启动服务器的程序位于Zk安装目录下的bin目录下,windows下的可执行程序为zkServer.cmd,linux下的可执行程序是zkServer.sh。
说明:可以将bin目录加到PATH环境变量下,这样可以在任意在目录下运行服务器程序。
六、命令行程序
Zk提供了一个命令行程序,可以连接到Zk服务器,执行对znode的各种操作。该命令行程序在Zk安装目录的bin目录下,windows下的程序名叫zkCli.cmd,linux下的程序名叫zkCli.sh。
如果是连接到本机的服务器,在控制台中运行上面客户端程序即可。
如果是连接到其它机器的服务器,则加上服务器ip地址和端口即可。如:zkCli.cmd/zkCli.sh -server IP地址:2181
如果一切正常,则就可以执行命令了。下面展示一些常见的命令:
1、ls命令
语法: ls 节点路径
含义:列出指定节点下的所有子节点名称
举例:
[zk: localhost:2181(CONNECTED) 0] ls /
[cluster, brokers, zookeeper, admin, zoo]
[zk: localhost:2181(CONNECTED) 1] ls /zoo
[dd]
2、ls2命令
语法: ls2 节点路径
含义:列出指定节点下的所有子节点名称 ,以及当前节点的元数据信息,如time、version等信息
举例:
[zk: localhost:2181(CONNECTED) 2] ls2 /zoo
[dd]
cZxid = 0xf1
ctime = Mon Dec 03 17:17:41 CST 2018
mZxid = 0x126
mtime = Tue Dec 04 20:03:09 CST 2018
pZxid = 0x106
cversion = 3
dataVersion = 11
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 1
3、create命令
语法: create [-s] [-e] path data acl
含义:创建znode节点,其中参数path是节点的路径,data是节点存储的字符串数据,-s选项表示是创建短暂的节点,-e选项表示是创建顺序节点。
举例:
[zk: localhost:2181(CONNECTED) 8] create /zoo/newnode ""
Created /zoo/newnode
[zk: localhost:2181(CONNECTED) 9] create -e /zoo/tmpnode "hello"
Created /zoo/tmpnode
[zk: localhost:2181(CONNECTED) 10] create -s /zoo/mynode "data"
Created /zoo/mynode0000000006
[zk: localhost:2181(CONNECTED) 11] ls /zoo
[dd, tmpnode, mynode0000000006, newnode]
4、delete命令
语法:delete path [version]
含义:删除指定的节点,path为待删除节点路径。version是节点版本号,如果指定,则version值必须与待删除节点的数据版本号一致,否则无法删除。如果不指定version参数,则删除时不管版本号。如果节点下有子节点,则无法删除。
举例:
[zk: localhost:2181(CONNECTED) 17] delete /zoo/newnode 2
version No is not valid : /zoo/newnode
[zk: localhost:2181(CONNECTED) 18] delete /zoo/newnode
[zk: localhost:2181(CONNECTED) 19] ls /zoo/newnode
Node does not exist: /zoo/newnode
5、set命令
语法:set path data [version]
含义:设置znode存储的数据。path为znode路径。data为要设置的字符串内容。version是节点版本号,如果指定,则version值必须与待设置节点的数据版本号一致,否则无法设置。如果不指定version参数,则设置时不管版本号。
举例:
[zk: localhost:2181(CONNECTED) 28] set /zoo gooddata
cZxid = 0xf1
ctime = Mon Dec 03 17:17:41 CST 2018
.............
6、get命令
语法:get path [watch]
含义:获取znode存储的数据及元数据信息。如果加上watch标记,则表示该客户端对该znode进行观察。当其它客户端(或本客户端)对该znode进行变更后,该客户端会收到通知。
举例:
[zk: localhost:2181(CONNECTED) 30] get /zoo watch
gooddata
cZxid = 0xf1
ctime = Mon Dec 03 17:17:41 CST 2018
mZxid = 0x148
mtime = Thu Dec 06 10:29:37 CST 2018
pZxid = 0x145
cversion = 11
dataVersion = 14
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 3
上面例子中的get命令加上了可选项watch标记。这时如果我们打开另外一个命令行客户端,并对/zoo节点进行设置存储数据操作。会发现当前客户端会收到消息,如下面内容:
[zk: localhost:2181(CONNECTED) 30] get /zoo watch
gooddata
cZxid = 0xf1
ctime = Mon Dec 03 17:17:41 CST 2018
mZxid = 0x148
mtime = Thu Dec 06 10:29:37 CST 2018
pZxid = 0x145
cversion = 11
dataVersion = 14
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 3
[zk: localhost:2181(CONNECTED) 31]
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/zoo
如果我们在另外一个客户端对/zoo节点进行设置存储数据操作后,再次执行set操作,会发现上面客户端不会再收到消息。这正如前面介绍,设置观察后,收到一次消息后观察不再有效,要想再次接受消息,必须重新设置。
上面介绍了zk命令行客户端的一些常见命令,还有其它一些命令(可以输入help查看所有支持的命令),这里不再一一介绍。在实际应用中,我们更多往往通过zk提供的编程API(如java api)来编写zk客户端程序,这个在后面的文章中介绍。
网友评论