Zookeeper原理与优化

本文转自 http://yuzhouwan.com/posts/31915/

Zookeeper是什么

ZooKeeper 是一个基于 Google Chubby论文实现的一款解决分布式数据一致性问题的开源实现,方便了依赖 Zookeeper的应用实现数据发布/订阅负载均衡服务注册与发现分布式协调事件通知集群管理Leader选举分布式锁和队列等功能

基本概念

集群角色

 一般的,在分布式系统中,构成集群的每一台机器都有自己的角色,最为典型的集群模式就是 Master/Slave主备模式。在该模式中,我们把能够处理所有写操作的机器称为 Master节点,并把所有通过异步复制方式获取最新数据、提供读服务的机器称为 Slave节点:
Uploading file...

 而 Zookeeper中,则是引入了 领导者(Leader)、跟随者(Follower)、观察者(observer) 三种角色 和 跟随(Following)、寻找(Looking)、观察(Observing)、领导(Leading) 等相应的状态。在 Zookeeper集群中的通过一种Leader选举的过程,来选定某个节点作为 Leader节点,该节点为客户端提供读和写服务。而Follower和 Observer节点,则都能提供读服务,唯一的区别在于,Observer机器不参与Leader选举过程 和 写操作的"过半写成功"策略,Observer只会被告知已经 commit的 proposal。因此 Observer可以在不影响写性能的情况下提升集群的读性能(详见 “性能优化 - 优化策略 - Observer模式”)

Uploading file...

会话

 Session指客户端会话。在 Zookeeper中,一个客户端会话是指 客户端和服务器之间的一个TCP长连接。客户端启动的时候,会与服务端建立一个TCP连接,客户端会话的生命周期,则是从第一次连接建立开始算起。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,并向 Zookeeper服务器发送请求并接收响应,以及接收来自服务端的 Watch事件通知

 Session的 sessionTimeout参数,用来控制一个客户端会话的超时时间。当服务器压力太大 或者是网络故障等各种原因导致客户端连接断开时,Client会自动从 Zookeeper地址列表中逐一尝试重连 (重试策略可使用 Curator来实现)。只要在 sessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。如果,在 sessionTimeout时间外重连了,就会因为 session已经被清除了,而被告知 SESSION_EXPIRED,此时需要程序去恢复临时数据;还有一种 Session重建后的在新节点上的数据,被之前节点上因网络延迟晚来的写请求所覆盖的情况,在 ZOOKEEPER-417中被提出,并在该 JIRA中新加入的 SessionMovedException,使得 用同一个sessionld/sessionPasswd 重建 Session的客户端能感知到,但是这个问题到 ZOOKEEPER-2219仍然没有得到很好的解决 Uploading file...

数据模型

 在 Zookeeper中,节点分为两类,第一类是指 构成集群的机器,称之为机器节点;第二类则是指 数据模型中的数据单元,称之为数据节点 ZNode。Zookeeper将所有数据存储在内存中,数据模型的结构类似于树 (ZNode Tree),由斜杠(/)进行分割的路径,就是一个ZNode,例如/foo/path1。每个 ZNode上都会保存自己的数据内容 和 一系列属性信息

 ZNode可以分为持久节点(PERSISTENT)和临时节点(EPHEMERAL)两类。所谓持久节点是指一旦这个 ZNode被创建了,除非主动进行移除操作,否则这个节点将一直保存在 Zookeeper上。而临时节点的生命周期,是与客户端会话绑定的,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。在 HBase中,集群则是通过 /hbase/rs/* 和 /hbasae/master两个临时节点,来监控 RS进程的加入和宕机 和 HMaster进程的 Active状态

 另外,Zookeeper还有一种 顺序节点(SEQUENTIAL)。该节点被创建的时候,Zookeeper会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀 (上限: Integer.MAX_VALUE)。该节点的特性,还可以应用到 持久/临时节点 上,组合成 持久顺序节点 (PERSISTENT_SEQUENTIAL) 和 临时顺序节点 ( EPHEMERAL_SEQUENTIAL)

版本

 Zookeeper的每个 ZNode上都会存储数据,对应于每个 ZNode,Zookeeper都会为其维护一个叫做 Stat的数据结构,Stat中记录了这个 ZNode的三个数据版本,分别是 version(当前 ZNode数据内容的版本),cversion(当前 ZNode子节点的版本)和 aversion (当前 ZNode的 ACL变更版本)。这里的版本起到了控制 Zookeeper操作原子性的作用 (详见 “源码分析 - 落脚点 - Zookeeper乐观锁”)

Watcher

 Watcher(事件监听器)是 Zookeeper提供的一种 发布/订阅的机制。Zookeeper允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,Zookeeper服务端会将事件通知给订阅的客户端。该机制是 Zookeeper实现分布式协调的重要特性

ACL

 类似于 Unix文件系统,Zookeeper采用 ACL(Access Control Lists)策略来进行权限控制 (使用方式,详见 “常用命令 - 执行脚本 - zkCli - 节点操作”部分)

Command Comment CREATE (c) 创建子节点的权限 READ (r) 获取节点数据和子节点列表的权限 WRITE (w) 更新节点数据的权限 DELETE (d) 删除当前节点的权限 ADMIN (a) 管理权限,可以设置当前节点的permission Scheme ID Comment world anyone Zookeeper中对所有人有权限的结点就是属于 world:anyone auth 不需要id 通过 authentication的 user都有权限 (Zookeeper支持通过 kerberos来进行 authencation,也支持 username/password形式的 authentication) digest username:BASE64 (SHA1(password)) 需要先通过 username:password形式的 authentication ip id为客户机的IP地址(或者 IP地址段) ip:192.168.1.0/14,表示匹配前 14个bit的 IP段 super 对应的 id拥有超级权限 (CRWDA)

环境搭建

单机版

  • 安装

    $ cd ~/install/
    $ wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
    $ wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz.md5
    # 校验 MD5
    $ head -n 1 zookeeper-3.4.10.tar.gz.md5
    e4cf1b1593ca870bf1c7a75188f09678  zookeeper-3.4.10.tar.gz
    $ md5sum zookeeper-3.4.10.tar.gz
    e4cf1b1593ca870bf1c7a75188f09678 *zookeeper-3.4.10.tar.gz
    # 对比 MD5码一致后进行解压安装
    $ tar zxvf zookeeper-3.4.10.tar.gz -C ~/software/
    $ cd ~/software
    $ ln -s zookeeper-3.4.10 zookeeper
    
  • 配置

    $ cd zookeeper
    $ mkdir tmp
    $ cp conf/zoo_sample.cfg conf/zoo.cfg
    $ mkdir -p /home/zookeeper/data/zookeeper
    $ mkdir -p /home/zookeeper/logs/zookeeper
    # 配置详见 "常用配置"部分
    $ vim conf/zoo.cfg
    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/home/zookeeper/data/zookeeper
    dataLogDir=/home/zookeeper/logs/zookeeper
    clientPort=2181
    
  • 启动

    $ bin/zkServer.sh start
    $ bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /home/zookeeper/software/zookeeper/bin/../conf/zoo.cfg
    Mode: standalone
    $ bin/zkCli.sh
    
  • 分布式

    # 配置详见 "常用配置"部分
    $ vim conf/zoo.cfg
    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/home/zookeeper/data/zookeeper
    dataLogDir=/home/zookeeper/logs/zookeeper
    clientPort=2181
    server.1=yuzhouwan01:2281:2282
    server.2=yuzhouwan02:2281:2282
    server.3=yuzhouwan03:2281:2282
    # 在各个节点的 dataDir下创建 myid文件,并对应 zoo.cfg中配置的 id
    [zookeeper@yuzhouwan01 ~] echo "1" > /home/zookeeper/data/zookeeper/myid
    [zookeeper@yuzhouwan02 ~] echo "2" > /home/zookeeper/data/zookeeper/myid
    [zookeeper@yuzhouwan03 ~] echo "3" > /home/zookeeper/data/zookeeper/myid
    

本文转自 http://yuzhouwan.com/posts/31915/