Zookeeper介绍

What is ZooKeeper?

ZooKeeper: A Distributed Coordination Service for Distributed Applications
ZooKeeper为分布式应用提供分布式协调服务,是Google的Chubby的开源实现。Zookeeper是一个高性能的分布式数据一致性解决方案,它并没直接采用Paxos算法,而是采用了一种被称ZAB(Zookeeper Atomic Broadcast)的一致性协议。

ZooKeeper功能点:

  • 统一的命名服务(Name Service)
  • 配置管理 (Maintaining Configuration)
  • 集群管理(Group membership)
  • 分布式锁(distributed synchronization)

ZooKeeper数据模型

ZooKeeper实现了一个类似于标准文件系统的数据结构,名称是由”/“分隔路径元素的序列。每一个节点在ZooKeeper的命名空间由路径唯一标识。如下图
ZK命名空间
每个Znode由3部分组成:

  1. stat: 此为状态信息,描述该znode的版本,权限等信息。
  2. data:与该znode关联的数据
  3. children:该znode下的子节点

znode状态Stat信息

1
2
3
4
5
6
7
8
9
10
**czxid**:znode创建时的zxid
**mzxid**:znode最后一次修改时的zxid
**ctime**:znode创建时的时间,单位毫秒
**mtime**:znode最后一次修改的时间,单位毫秒
**version**:znode修改的version(次数)
**cversion**:修改znode子节点的version(次数)
**aversion**:修改znode ACL的次数
**ephemeralOwner**:如果znode是临时节点该值是Owner的session id,如果znode不是临时节点,该值是0
**dataLength**:znode的数据字段的长度
**numChildren**:这个znode子节点数量

znode类型

  • EPHEMERAL:临时节点,生命周期依赖于client session,当session close/expire也会消失
  • EPHEMERAL_SEQUENTIAL : (SEQUENTIAL意为顺序的) 顺序的临时节点
  • PERSISTENT :持续的,不会随着session的close/expire而消失
  • PERSISTENT_SEQUENTIAL

典型的应用场景

1. 统一命名服务(Name Service)
分布式应用中,通常需要有一套完整的命名规则,既能够产生唯一的名称又便于人识别和记住,通常情况下用树形的名称结构是一个理想的选择,树形的名称结构是一个有层次的目录结构,既对人友好又不会重复。ZooKeeper的命名服务类似于JNDI,它们都是将有层次的目录结构关联到一定资源上,但是 Zookeeper 的 Name Service 更加是广泛意义上的关联,也许你并不需要将名称关联到特定资源上,你可能只需要一个不会重复名称,就像数据库中产生一个唯一的数字主键一样。

2. 数据发布与订阅(配置管理)
数据发布与订阅系统,即是配置中心。发布者(Publisher)把数据发送到Zookeeper的服务器上(单机或者ZK集群),订阅者(Subscriber)进行数据订阅,订阅者注册自己需要关注的节点,一旦该节点的数据发生变化,那么ZK服务器就会向该订阅者发送watch事件通知,订阅者需要主动去服务器端后去最新的数据。

3. 集群管理(Group Membership)
随着应用集群的扩大,我们需要知道集群中每台机器的存活状态(集群监控),Zookeeper可以很容易的实现集群管理的功能。
我们在Zookeeper服务器上创建一个znode节点/Servers,集群中每一个节点在在启动是去注册一个临时(EPHEMERAL)节点/Servers/hostname(可以使用ip),然后每个节点在父节点/Servers上调用 getChildren(String path, boolean watch) 方法并设置 watch 为 true,由于是 EPHEMERAL节点有个特性,就是节点和Zookeeper服务器断开连接或者Session过期,节点都会被删除。NodeChildrenChanged 事件会通知到所有watch的客户端。
集群管理

3. 分布式锁
完全分布式锁是全局同步的,在任何时间快照意味着没有两个client同时持有同一把锁。这种分布式锁可以使用ZooKeeeper来实现。
ZooKeeper并没有直接给用户提供分布式锁,需要我们借助其节点来实现分布式锁,ZooKeeper可以实现两种锁:共享锁和排它锁
关于分布式锁请参看另一篇博文!!

单机模式配置

单机模式安装和配置比较简单,下载压缩包zookeeper-3.3.6.tar.gz,然后解压到 /home/admin/zookeeper-3.3.6。配置文件在conf下面,需要重新命名zoo_sample.cfg 为 zoo.cfg,或者copy一份。

1
sudo cp zoo_sample.cfg zoo.cfg

配置如下:
1
2
3
tickTime=2000, tickTime是服务器之间或客户端与服务器之间心跳的时间间隔
dataDir=/home/admin/zookeeper-3.3.6/data,Zookeeper 保存数据的目录
clientPort=2181,Client连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求
启动Zookeeper命令(启动脚本在 bin 目录)
1
sudo sh zkServer.sh start

集群模式配置

Zookeeper 提供集群服务,下面介绍集群模式的安装和配置:

  • 配置hosts,首先修改/etc/hosts,为集群中所有机器配置一个hostName(主要为了方便配置Zookeeper)

    1
    2
    3
    192.168.0.100  zk-01
    192.168.0.101 zk-02
    192.168.0.102 zk-03
  • zoo.cfg 配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    tickTime=2000
    dataDir=/home/admin/zookeeper-3.3.6/data
    clientPort=2181

    initLimit=10 Zookeeper服务器集群中Leader最长能忍受Follower多少个心跳时间间隔数,10*2000ms=20s
    syncLimit=5 Leader与Follower之间发送消息,请求和应答时间间隔数,5*2000ms=10s
    server.1=zk-01:2888:3888
    server.2=zk-02:2888:3888
    server.3=zk-03:2888:3888

格式 server.X = A:B:C

X 和下面要介绍的myid保持一致,A是hostName或者ip,B表示的集群中 Leader 和Follower通信端口;C 表示集群中Leader 挂了,重新选举时使用端口C。

  • zoo.cfg配置的copy
    为保证集群中所有的机器都使用同一份配置,用scp复制到集群中的其他机器(scp基于ssh登录)

    1
    2
    scp -r zookeeper-3.3.6/ jiandong.zjd@zk-02:/home/admin/
    scp -r zookeeper-3.3.6/ jiandong.zjd@zk-03:/home/admin/
  • 配置myid
    在zookeeper配置的dataDir指定的目录下面,创建一个myid文件,里面内容为一个数字,用来标识当前主机,zoo.cfg文件中配置的server.X中X是什么数字,则myid文件中就输入这个数字。

    1
    2
    3
    zk-01: echo "1" > /home/admin/zookeeper-3.3.6/data/myid
    zk-01: echo "2" > /home/admin/zookeeper-3.3.6/data/myid
    zk-01: echo "3" > /home/admin/zookeeper-3.3.6/data/myid
  • 启动集群,在ZooKeeper集群的每个结点上,执行启动ZooKeeper服务的脚本

    1
    sh bin/zkServer.sh start
  • 集群安装验证

    1
    2
    3
    4
    5
    6
    sh bin/zkServer.sh status

    sh bin/zkServer.sh status
    JMX enabled by default
    Using config: /home/admin/zookeeper-3.3.6/bin/../conf/zoo.cfg
    Mode: follower