分布式应用协同服务:ZooKeeper

jopen 10年前

ZooKeeper是Apache Hadoop的一个子项目,其实现的功能与Google的Chubby基本一致,主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

数据模型:</span>
zookeeper维护一个层次关系的数据结构,其非常类似于一个标准的文件系统,如下:

分布式应用协同服务:ZooKeeper

和文件不一样的是,/app1(文件系统中的目录)这样的节点也可以关联数据。我们把zookepper的节点成为znode。
znode具有如下特点:
1. ZooKeeper有临时节点的概念。临时节点在创建它的会话活动期间存在。会话终止的时候,临时节点被删除,所以临时节点不能有子节点。
2. Znode可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端。
3. Znode可以保留数据,但是,其不是设计用来作为通用数据库或者大型对象存储的,而是用来存储协调数据的。协调数据的形式可能是配置、状态信息、聚合等 等。各种形式的协调数据的一个共同特点是:它们通常比较小,以千字节来衡量。ZooKeeper客户端和服务器实现会进行检查,以保证znode数据小于 1MB
4.Znode中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据就需要带上版本。

ZooKeeper中的时间:
zxid : 每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid。
版本号 : 对节点的每次修改将使得节点的版本号增加一。版本号有三种:version(znode数据修改的次数)、cversion(znode子节点修改的次数),以及aversion(znode的ACL修改次数)。
tick : 多服务器ZooKeeper中,服务器使用tick来定义状态上传、会话超时、节点间连接超时等事件的时序。tick仅被最小会话超时(2倍的tick时间)间接使用:如果客户端要求小于最小会话超时的时间,服务器将告知客户端,实际使用的是最小会话超时。

znode会维护一个包含数据修改和ACL修改版本号的 Stat结构体 , 这个结构体还包含时间戳字段。版本号和时间戳让ZooKeeper可以校验缓存,协调更新。每次修改znode数据的时候,版本号会增加。客户端获取数据 的同时,也会取得数据的版本号。执行更新或者删除操作时,客户端必须提供版本号。如果提供的版本号与数据的实际版本不匹配,则更新操作失败。stat结构 体内容:
czxid : The zxid of the change that caused this znode to be created.
mzxid : The zxid of the change that last modified this znode.
ctime : The time in milliseconds from epoch when this znode was created.
mtime : The time in milliseconds from epoch when this znode was last modified.
version : The number of changes to the data of this znode.
cversion : The number of changes to the children of this znode.
aversion : The number of changes to the ACL of this znode
ephemeralOwner : The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.
dataLength : The length of the data field of this znode.
numChildren : The number of children of this znode.

安装使用
下载解压:</span>
$ wget http://mirror.bit.edu.cn/apache//zookeeper/zookeeper-3.4.3/zookeeper-3.4.3.tar.gz .
$ tar -zxvf zookeeper-3.4.3.tar.gz

修改配置:
$ cp zookeeper-3.4.3/conf/zoo_sample.cfg zookeeper-3.4.3/conf/zoo.cfg
$ cat  zookeeper-3.4.3/conf/zoo.cfg

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1


启动zookeeper:
ZooKeeper 要求 JAVA 的环境才能运行,并且需要 JAVA6 以上的版本
ubuntu下安装jdk:
$sudo apt-get install  openjdk-7-jre-headless
启动zookeeper:
$ sudo sh zookeeper-3.4.3/bin/zkServer.sh start
JMX enabled by default
Using config: /home/zxm/zookeeper-3.4.3/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
查看相应端口:
$ netstat -na | grep 2181
tcp6       0      0 :::2181                 :::*                    LISTEN

客户端连接测试:
$ sh zookeeper-3.4.3/bin/zkCli.sh -server 127.0.0.1:2181
.......
输入help
[zk: 127.0.0.1:2181(CONNECTED) 0] help
ZooKeeper -server host:port cmd args
    connect host:port
    get path [watch]
    ls path [watch]
    set path data [version]
    rmr path
    delquota [-n|-b] path
    quit
    printwatches on|off
    create [-s] [-e] path data acl
    stat path [watch]
    close
    ls2 path [watch]
    history
    listquota path
    setAcl path acl
    getAcl path
    sync path
    redo cmdno
    addauth scheme auth
    delete path [version]
    setquota -n|-b val path

我们可以尝试做一些操作:
[zk: 127.0.0.1:2181(CONNECTED) 4] ls /
[zookeeper]
[zk: 127.0.0.1:2181(CONNECTED) 5] create /test1 99
Created /test1
[zk: 127.0.0.1:2181(CONNECTED) 6] get /test1
99
cZxid = 0xa
ctime = Thu Apr 19 02:08:37 PDT 2012
mZxid = 0xa
mtime = Thu Apr 19 02:08:37 PDT 2012
pZxid = 0xa
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0
[zk: 127.0.0.1:2181(CONNECTED) 7] create /test1/mytest 1000
Created /test1/mytest
[zk: 127.0.0.1:2181(CONNECTED) 8] get /test1/mytest
1000
cZxid = 0xb
ctime = Thu Apr 19 02:08:54 PDT 2012
mZxid = 0xb
mtime = Thu Apr 19 02:08:54 PDT 2012
pZxid = 0xb
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0

编译使用C客户端:
$ cd zookeeper-3.4.3/src/c
$ mkdir prefix
$ ./configure --prefix=/home/zxm/zookeeper-3.4.3/src/c/prefix
$ make
$ ./cli_mt 127.0.0.1:2181
Watcher -1 state = CONNECTED_STATE
Got a new session id: 0x136c9d62bdc0004
ls /
time = 4 msec
/: rc = 0
    test1
    zookeeper
time = 7 msec
get /test1
time = 2438 msec
/test1: rc = 0
 value_len = 2
99
Stat:
    ctime = Thu Apr 19 02:08:37 2012
    czxid=a
    mtime=Thu Apr 19 02:08:37 2012
    mzxid=a
    version=0    aversion=0
    ephemeralOwner = 0