zookeeper的介绍和部署
ZooKeeper是Hadoop的正式子项目,是Google的Chubby一个开源的实现。它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。在一个分布式的环境中,我们需要一个Master实例或存储一些配置信息,确保文件写入的一致性等。
1、znode
在Zookeeper中,实现了一个层次名字空间(hierarchal name space)的数据模型,它特别象一个文件系统,每个文件被称为znode,可以往这个节点存储或获取数据。zookeeper一个znode除了自己包含一些数据外,还能拥有孩子节点。存在下述的3种类型znode:
Persistent Nodes:永久有效地节点,除非client显式的删除,否则一直存在
Ephemeral Nodes:临时节点,仅在创建该节点client保持连接期间有效,一旦连接丢失,zookeeper会自动删除该节点
Sequence Nodes:顺序节点,client申请创建该节点时,zk会自动在节点路径末尾添加递增序号,这种类型是实现分布式锁,分布式queue等特殊功能的关键
2、条件更新和watches
Zookeeper支持Watches,客户端在一个znode上设置watch,当客户端接收到节点改变的包时,watch将被触发,通知客户端此节点发生改变,然后调用相应的行为来处理数据。如果客户端与zookeeper服务器的连接出现故障,客户端也会收到一个本地的通知。
3、设计目标
3.1复制的
如图,像zookeeper协调的分布式程序一样,它本身就是被复制在一群主机上。服务器组成的zookeeper服务都必须了解其他服务器。他们保持一个内存映像的状态,以及永久存储一个事务日志和快照。只要大多数服务器可用,zookeeper服务将是可用的。
客户端连接到单个ZooKeeper server。 客户端维护一个TCP连接,通过此连接发送请求,得到响应,得到观察事件,并发送心跳。如果TCP连接到服务器发生故障,客户端将连接到其他的服务器。
3.2简单高效:
Zookeeper的实现重视高性能、高可用性、严格有序的访问。Zookeeper数据都在内存中,能达到高吞吐量,低延迟。它在读操作占主导的负载中速度尤其快。Zookeeper应用运行在上千个机器上时,在读写比例10比1的时候,性能最好。
3.3顺序的
zookeeper用一个反映zookeeper事物顺序的号来表示每个更新。后面的操作可以用此顺序来实现更高级别的抽象,如同步原语。
4、简单的 API
设计目标之一是提供简单的编程接口。因此,它只提供以下这些操作。
create
creates a node at a location in the tree
delete
deletes a node
exists
tests if a node exists at a location
get data
reads the data from a node
set data
writes data to a node
get children
retrieves a list of children of a node
sync
waits for data to be propagated
5、实现
Zookeeper组件展示了zookeeper服务的高层次的组件。除了request processor,每个服务器都拷贝一份每个组件。
ZooKeeper 组件图
replicated database是一个包含全部数据的在内存中的数据库。写操作都先写进磁盘,然后写进这个内存中的数据库。
每一个ZooKeeper服务器为客户提供服务。客户端连接到一个服务器提交请求。读请求由每个服务器数据库的本地副本提供服务。更改服务状态的请求及写请求,通过一项agreement协议来处理。
作为agreement协议的一部分,所有客户机的写入请求被转发到一台服务器上,即leader。剩余的ZooKeeper服务器被称为followers,从leader接收消息,并同意消息传递。通讯层负责在leader故障时更换leader和同步leader的followers。
ZooKeeper使用一个自定义的原子的消息传递协议。由于消息传递层是原子的。ZooKeeper可以保证本地副本从来没有分歧。leader接收到一个写请求时,它计算当写操作要执行的时候系统将转成的状态,并将其转换到一个捕捉此新状态的事务中。
6、zookeeper应用——分布式锁
拥有了zookeeper如此强大的分布式协作系统后,我们可以很容易的实现大量的分布式应用,包括了分布式锁,分布式队列,分布式Barrier,双阶段提交等等. 这些应用可以帮我们改进很多复杂系统的协作方式,将这些系统的实现变得更加优雅而高效。这里仅介绍分布式锁的实现。
利用了前文提到的sequence nodes可以非常容易的实现分布式锁. 实现分布式锁的基本步骤如下(这些步骤需要在所有需要锁的客户端执行):
1、client调用create()创建名为”_locknode_/lock-”的节点,注意需要设置sequence和ephemeral属性
2、client调用getChildren(“_locknode_”),注意不能设置watch,这样才能避免羊群效应
3、步骤1中创建的节点序号最低,则该client获得锁,开始执行其它程序
4、client对lock-xxx中序号仅次于自己创建节点的那个节点调用exists(),并设置watch
5、如果exist()返回false(节点不存在)则回到步骤2,否则等待步骤4中的watch被触发并返回步骤2
分布式锁在zookeeper的源代码中已经有实现,可以参考org.apache.zookeeper.recipes.lock下面是一个使用分布式锁的样例,这段程序摘自一个hadoop reduce的configure函数, 使用分布式锁的目的是确保一台机器上的所有reduce进程中,只有一个reduce进程会执行某些初始化代码. 同时其它reduce在总和初始化完成之前不会继续执行.
多个reduce分别获取锁后,加锁节点的子节点信息如下所示
1
2
ls /full-dump-gcih/xxxxx.cm2
这些节点全部是Sequence+Ephemeral属性的节点, 其中
1
2
x-84692699318388014-000000000
name-zk_session_id-sequence_number
这个节点名称是org.apache.zookeeper.recipes.lock中使用的名称,可以根据需要自己重新实现相关代码,进而设计一个专用的锁.
7、ZooKeeper部署
此部分主要讲一个单一的ZooKeeper服务器的简单的安装说明,通过它是一些命令来验证zookeeper的运行,以及简单的编程示例。此外还有更复杂的安装,例如运行集群模式的部署。
1)下载:
从apache下载镜像中下载一个稳定版本(目前3.4.5是最稳定的版本)。
2)创建配置文件
下载之后解压缩,cd根目录。然后创建一个配置文件conf/zoo.cfg:
tickTime=2000
dataDir=/zookeeper/data
clientPort=2181
设置dataDir为一个已存在的空的目录。其中三个参数的意义如下:
tickTime
服务器与客户端间交互的基本时间单元(以毫秒为单位)
dataDir
保存zookeeper数据、日志的路径
clientPort
客户端与zookeeper相互交互的端口号,默认情况下设置为2181
3)启动zookeeper
创建配置文件之后,就可以启动zookeeper了(权限不够时,用chmod775 zkServer.sh):
bin/zkServer.sh start
查看状态: bin/zkServer.sh status
JMX enabled by default
Using config: /home/liufen/zookeeper-3.4.4/bin/../conf/zoo.cfg
Mode: standalone
4)连接到 ZooKeeper
一旦ZooKeeper在运行, 可以有几种方式连接它:
[*]Java: Use
bin/zkCli.sh -server localhost:2181
[*]C: compile cli_mt (multi-threaded) or cli_st (single-threaded) by running make cli_mt or make cli_st in thesrc/c subdirectory in the ZooKeeper sources. See the README contained withinsrc/cfor full details.
You can run the program from src/c using:
LD_LIBRARY_PATH=. cli_mt 127.0.0.1:2181
or
LD_LIBRARY_PATH=. cli_st 127.0.0.1:2181
This will give you a simple shell to execute file system like operations on ZooKeeper.
当你连接后,会出现下列信息:
Connecting to localhost:2181
log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
Welcome to ZooKeeper!
JLine support is enabled
从shell中,键入help获得可以从客户端执行的命令,如下:
help
ZooKeeper host:port cmd args
get path
ls path
set path data
delquota [-n|-b] path
quit
printwatches on|off
createpath data acl
stat path
listquota path
history
setAcl path acl
getAcl path
sync path
redo cmdno
addauth scheme auth
delete path
deleteall path
setquota -n|-b val path
5)简单的命令
从这里,你可以尝试一些简单的命令来感受一下这个简单的命令行接口。首先,发出list命令,如ls:
ls /
然后创建一个新节点,命令是 create /zk_test my_data.
create /zk_test my_data
Created /zk_test
然后操作ls / ,结果如下:
ls /
接下来,确认这个数据是与znode相关的,通过get命令:
get /zk_test
my_data
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 5
mtime = Fri Jun 05 13:57:06 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0
dataLength = 7
numChildren = 0
我们可以修改与zk_test相关联的数据通过set命令。:
set /zk_test junk
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 6
mtime = Fri Jun 05 14:01:52 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0
dataLength = 4
numChildren = 0
get /zk_test
junk
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 6
mtime = Fri Jun 05 14:01:52 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0
dataLength = 4
numChildren = 0
最后我们删除节点zk_test:
delete /zk_test
ls /
6)运行集群模式的 ZooKeeper
在独立模式下运行的ZooKeeper对进行评估,一些开发和测试提供了方便。但在生产中,应该运行集群模式的ZooKeeper。在同一应用程序的服务器组被称为quorum,并且在集群模式中,所有服务器有相同的配置文件的副本。该文件和在独立模式下使用的文件是类似的,但有一些差异。下面是一个例子:
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
initLimit是zookeeper所能接受的客户端数量
syncLimit服务器和客户端间请求和应答间的时间间隔(是ticktime的倍数)
server.X 是组成 ZooKeeper服务的服务器. X表示第几个服务器,其后的表示服务器的IP地址。最后注意服务器名字后面的两个端口号: " 2888" 和"3888"。第一个端口用来服务器之间的通信,而且还用来连接followers到leader. 第二个端口用来选举leader。
页:
[1]