【Apache ZooKeeper】官方文档

ZooKeeper是一个高性能的用于协调分布式应用程序的服务。它将公共服务,比如命名、配置管理、同步化和集群服务封装进一个简单的接口,可以直接用于实现共识(consensus)、集群管理、领导者选举和存在(presence )协议。可以在其上构建自己的分布式应用程序。

ZooKeeper使用一种类似文件系统目录树的数据模型,它可以运行于Java上并且具有JavaC的封装


ZooKeeper的设计目标

简单——ZooKeeper允许分布式进程之间通过一个共享的层级命名空间来相互协作,这个命名空间以类似于文件系统的方式组织起来。命名空间中的数据单元被称为znode,它相当于文件或者目录。与典型文件系统不同的是,文件系统用于持久化存储,而ZooKeeper的数据是保持在内存中的,这意味着ZooKeeper能达到很高的吞吐量和低延迟。

     ZooKeeper的实现十分注重高性能、高可用性,和严格的顺序访问。高性能使得ZooKeeper能用于大规模分布式系统,高可用性能避免单点故障,严格的顺序化意味着复杂的同步操作可以在客户端实现。

集群化——ZooKeeper本身也是有集群化的。如下图:




    客户端与单个服务端相连,它维持一个TCP连接,在其上发送请求,获得响应,获得监控事件和发送心跳检测。如果到服务端的TCP连接断了,客户端会连接另一个服务端。组成ZooKeeper服务的每个服务端都知道其它服务端的存在,它们维护一个服务端状态的内存镜像,连同事务日志和快照保存在持久化存储中,只要大部分服务端可用,ZooKeeper服务就可用。

顺序化——ZooKeeper为每个更新操作都标记一个号码以反映事务的顺序。后来的操作使用这个顺序来实现高度的抽象,比如同步原语。

快速——这个特性在以读操作为主的工作中尤为明显。ZooKeeper应用程序运行于数以千计的机器中,当读操作与写操作的比例为10:1时,ZooKeeper能获得最佳性能。


数据模型和层级命名空间

ZooKeeper提供的命名空间极像一个标准的文件系统,一个名字是一个以/分隔的路径元素的序列,ZooKeeper命名空间的每个节点通过路径来标识。



节点和临时节点

与标准文件系统不同,ZooKeeper命名空间中的所有节点都可以有数据和子节点,这就像文件系统中允许一个文件同时是一个目录。(ZooKeeper被设计用来存储管理服务的数据:状态信息、配置、位置信息等,所以每个节点存储的数据通常很小,几字节到几K字节不等。)我们使用znode这个术语来表示ZooKeeper的数据节点。

znode维持一个stat结构,它包含数据变化的版本号、ACL变化和时间戳,以允许cache校验和协调化的更新。每当znode的数据变化时,版本号将增加。一个客户端收到数据时,它也会收到数据的版本号。

保存在每个znode中的数据都是自动读写的。读操作获取znode的所有数据,写操作替换掉znode的所有数据。每个节点有一个访问控制表(ACL)来限制谁能做哪些操作。

ZooKeeper也有临时节点的概念,这些znode只存在于创建znode的会话中。当会话结束,这些节点也就被删除了。


条件化更新和监控

ZooKeeper支持监控的概念。客户端可以在zonode上设置一个观察员。这个观察员会在znode发生变化时触发和移除。当观察员被触发时,客户端会接收到一个说明znode发生变化的包。如果客户端和服务端的连接断了,客户端会收到一个本地的通知。这些可以用于[tbd]


保证

ZooKeeper非常快,也非常简单。因为它的目标是成为构建复杂服务的基础,所以它提供一系列保证:

  • 顺序一致性——来自客户端的更新操作将以它们发送的顺序来执行。
  • 原子性——更新操作只有成功和失败两种结果,没有局部化结果。
  • 单个系统镜像——不管客户端连接的服务器是哪个,所有客户端看到的服务都是一个样子。
  • 可靠性——一旦更新操作被执行,它将被持久化保存直到被下次更新所覆盖。
  • 及时性——客户端所看到的系统在一个时间范围内是最新的。


简单的API

ZooKeeper的一个设计目标是易于编程。所以,它只支持如下操作:

create

    在命名空间的某个位置创建一个节点

delete

    删除一个节点

exists

    测试某位置的节点是否存在

get data

    从一个节点读取数据

set data

    往一个节点写数据

get children

    获取一个节点的子节点列表

sync

等待数据被传播以同步数据


实现

下图从较高层次说明了ZooKeeper的构成。除了请求处理单元,组成ZooKeeper服务的每个服务端都会备份它的每个组件。


集群数据库是存在于内存中的数据库,保存命名空间的所有数据。更新操作会被记录到硬盘中以便恢复,写操作先被序列化到硬盘中,再应用到内存数据库中。

每个ZooKeeper服务端为一个或多个客户端服务。客户端连接一个服务端来提交请求。读操作请求由每个服务端数据库的本地副本提供服务。能够改变服务状态的请求、写操作请求,按协议处理。

作为协议的一部分,来自客户端的所有写操作请求会导向一个服务端,叫做leader。其他服务端叫做follower。所有followerleader接收消息建议并且对消息转发达成一致。由消息传送层来处理失败时替换leader,同步followerleader的工作。

ZooKeeper使用自定义的原子性消息协议。由于消息传送层是原子性的,ZooKeeper能够保证本地副本不产生分歧。当leader收到一个写请求,它会计算出当写操作完成后系统将会是什么状态,接着将之转变为一个事务。

使用ZooKeeper管理分布式应用程序


单机模式

以单机模式安装一个ZooKeeper服务端是很简单的。这个服务端包含在一个JAR文件中,所以安装工作包括创建一个配置。一旦你已经下载了ZooKeeper的稳定版本,解压到根目录。启动ZooKeeper需要一个配置文件,例如,创建一个配置文件conf/zoo.cfg:

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181

配置文件可以叫做任何名字。dataDir需要指向一个已存在的目录。以下是每个域的解释:

tickTime

    ZooKeeper使用的基本时间单位(毫秒)。它用于心跳检测,最小的会话超时时间是tickTime的两倍。

dataDir

    存放内存数据库快照的位置。除非另外指定,更新操作的事务日志也存在于这个数据库中。

clientPort

    监听客户端连接的端口。

现在,你可以启动ZooKeeper了:

bin/zkServer.sh start

ZooKeeper的日志消息使用log4j。你可以在终端(默认)或日志文件中查看日志信息,取决于log4j的配置。

以上步骤可将ZooKeeper运行于单机模式,没有备份,所以如果ZooKeeper处理失败,服务就会停止。


连接到ZooKeeper

当ZooKeeper运行起来,可以有多种方式连接到它:

Java:使用

bin/zkCli.sh -server 127.0.0.1:2181
在ZooKeeper源码的src/c目录下执行make cli_mt或者make cli_st来编译clt_mt(多线程)和cli_st(单线程)。

    你可以使用:

LD_LIBRARY_PATH=. cli_mt 127.0.0.1:2181
    或者:

LD_LIBRARY_PATH=. cli_st 127.0.0.1:2181
    从src/c运行程序。这将给你一个简单的shell,在ZooKeeper上执行类似文件系统的操作。

当连接上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
[zkshell: 0]
        

在这个shell中输入help,列出客户端可以使用的命令:

[zkshell: 0] help
ZooKeeper host:port cmd args
        get path [watch]
        ls path [watch]
        set path data [version]
        delquota [-n|-b] path
        quit
        printwatches on|off
        createpath data acl
        stat path [watch]
        listquota path
        history
        setAcl path acl
        getAcl path
        sync path
        redo cmdno
        addauth scheme auth
        delete path [version]
        deleteall path
        setquota -n|-b val path

例如执行ls命令:

[zkshell: 8] ls /
[zookeeper]
        
接着,创建一个新的znode。
[zkshell: 9] create /zk_test my_data
Created /zk_test
      

这将会创建一个新的znode,字符串"my_data"作为这个节点的关联数据。

再次执行ls命令,可以看到,zk_test目录已经创建:

[zkshell: 11] ls /
[zookeeper, zk_test]
    

接着,用get命令来获取znode的数据:

[zkshell: 12] 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
        

可以用set命令来设置zk_test节点的数据:

[zkshell: 14] 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
[zkshell: 15] 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
      

最后,删除节点:

[zkshell: 16] delete /zk_test
[zkshell: 17] ls /
[zookeeper]
[zkshell: 18]


ZooKeeper编程

ZooKeeper有Java封装和C封装,它们在功能上是一样的。C封装有两种情况:单线程和多线程,这两种情况只是在消息循环处理中有区别。


集群模式

在一个相同应用程序下的服务端集群叫做一个quorum,在集群模式下,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是quorum中的ZooKeeper服务端连接leader的超时时间。syncLimit是一个服务端失去leader身份的过期时间。它们的单位都是tickTime,即上面的initLimit设置的是10s。

server.X列出了组成ZooKeeper服务的服务端,当服务端启动时,它会在数据目录中查找文件myid以确定它是哪个服务端,这个文件包含着服务端的编号,已ASCII码形式。

最后,注意每个服务端名字后面的端口号:" 2888"和"3888"。服务端之间的连接使用前一个端口,通过它实现服务端间的交流,比如在更新操作的顺序上达成一致。特别地,一个服务端使用这个端口来连接到leader。当产生了新leader时,follower使用这个端口打开一个TCP连接到leader。因为默认的leader选举使用的也是TCP,所以我们现在需要另一个端口用于leader选举,这就是第二个端口的用途。

注意:如果你想在一台机器上测试多个服务端,指定服务端名为localhost,每个server.X端口号都要不一样,如2888:3888, 2889:3889, 2890:3890。dataDir和clientPort也要不一样,所以需要多个配置文件。


其他优化

还有一些其他的配置参数,能极大地提高性能:

为了降低更新操作的延迟,指定专用的事务日志目录是很重要的。默认情况下,事务日志被放在与数据快照和myid文件相同的目录下。dataLogDir参数用来指定事务日志的目录。


更多 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值