介绍

Zookeeper是分布式应用协调框架,用于解决一些数据管理问题,如配置管理,集群管理,状态同步管理等。可理解为是一种基于内存的数据库,采用文件系统(树形)数据结构以及事件监听机制。
zk数据结构

节点(znode)

znode对应的就是文件系统数据结构中的一个"目录"。
znode的四种类型:

  1. 持久节点
    [zk: localhost:2181(CONNECTED) 0] create /heoller
    Created /heoller
    [zk: localhost:2181(CONNECTED) 1] get -s /heoller
    null # 数据
    cZxid = 0x4 # 创建时的事务id
    ctime = Sun Nov 22 16:40:54 CST 2020 # 创建时间
    mZxid = 0x4 # 修改的事务id
    mtime = Sun Nov 22 16:40:54 CST 2020 # 修改时间
    pZxid = 0x4 # 子节点新增或删除时的事务id
    cversion = 0 # 创建时的版本
    dataVersion = 0 # 数据版本
    aclVersion = 0 # acl的版本
    ephemeralOwner = 0x0 # 临时节点的owner,0表示持久节点,非0表示当前客户端连接的sessionId
    dataLength = 0 # 数据长度
    numChildren = 0 # 子节点数
  2. 持久+序列化节点
    [zk: localhost:2181(CONNECTED) 2] create -s /heoller/aaa-
    Created /heoller/aaa-0000000000
    [zk: localhost:2181(CONNECTED) 3] create -s /heoller/aaa-
    Created /heoller/aaa-0000000001
  3. 临时节点
    [zk: localhost:2181(CONNECTED) 4] create -e /temp
    Created /temp
    [zk: localhost:2181(CONNECTED) 5] get -s /temp
    null
    cZxid = 0x7
    ctime = Sun Nov 22 16:46:55 CST 2020
    mZxid = 0x7
    mtime = Sun Nov 22 16:46:55 CST 2020
    pZxid = 0x7
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x1000448f3c20001
    dataLength = 0
    numChildren = 0
  4. 临时+序列化节点
    [zk: localhost:2181(CONNECTED) 1] create /temp-seq
    Created /temp-seq
    [zk: localhost:2181(CONNECTED) 2] create -e -s /temp-seq/seq-
    Created /temp-seq/seq-0000000000
    [zk: localhost:2181(CONNECTED) 3] create -e -s /temp-seq/seq-
    Created /temp-seq/seq-0000000001
    [zk: localhost:2181(CONNECTED) 4] ls -R /temp-seq
    /temp-seq
    /temp-seq/seq-0000000000
    /temp-seq/seq-0000000001

事件监听机制

  1. 监听节点数据
    节点被删除或者内容发生变化,对应客户端会被通知。
    [zk: localhost:2181(CONNECTED) 0] create /test
    Created /test
    [zk: localhost:2181(CONNECTED) 1] get -w /test
    null
    [zk: localhost:2181(CONNECTED) 2] set /test heoller
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/test
  2. 监听"目录"
    "目录"下的子节点发生新增或删除时,对应客户端会被通知。
    [zk: localhost:2181(CONNECTED) 3] ls -w /test
    []
    [zk: localhost:2181(CONNECTED) 4] create /test/aaa
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/test
    Created /test/aaa
    [zk: localhost:2181(CONNECTED) 5] ls -w /test
    [aaa]
    [zk: localhost:2181(CONNECTED) 6] delete /test/aaa
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/test
  3. 监听递归子节点
    1和2的结合。
    [zk: localhost:2181(CONNECTED) 18] ls -R -w /test
    /test
    /test/sub0
    /test/sub1
    /test/sub2
    /test/sub0/sub0
    [zk: localhost:2181(CONNECTED) 19] set /test aaa
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/test
    [zk: localhost:2181(CONNECTED) 29] ls -R -w /test
    /test
    /test/sub0
    [zk: localhost:2181(CONNECTED) 30] create /test/sub1
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/test
    Created /test/sub1
    [zk: localhost:2181(CONNECTED) 31] create /test/sub0/sub0
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/test/sub0
    Created /test/sub0/sub0

所有监听都是一次性的,触发之后,监听就会被移除

ACL权限控制

ACL说明

由权限模式+授权对象+权限信息组成。可以通过系统参数zookeeper.skipACL控制是否跳过权限检测,默认为不跳过。
zkS

  1. 权限模式(Scheme)
    即权限验证方式,支持范围模式,口令模式(用户名密码)以及Super权限模式。
    • 范围模式(IP模式)
      可以对指定ip或ip段的客户端赋予权限。
    • 口令模式(Digest模式)
      服务端通过账密验证客户端权限。
    • Super权限模式
      具有该权限的客户端有操作数据节点的任意权限
  2. 授权对象(ID)
    对于范围模式,授权对象是IP或IP段;对于Digest/Super模式,授权对象是具体用户;对于World模式,授权对象是所有用户。
    生成授权ID方法:
    • 代码方式
        DigestAuthenticationProvider.generateDigest("user:password");
    • shell方式
        echo ‐n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
  3. 权限信息(Permission)
    指具体的操作权限。
    • c 创建,可以在授权节点下创建子节点。
    • w 更新(写)
    • r 读取
    • d 删除,可以删除授权节点下的子节点。
    • a 管理者(admin)

ACL示例

  1. 密文方式

    ➜  ~ echo -n heoller:123456 | openssl dgst -binary -sha1 | openssl base64
    tcQjGGQnqBWfeXxNnaIrU4A7pTw=
    [zk: localhost:2181(CONNECTED) 1] create /nodeWithACL aclnode digest:heoller:tcQjGGQnqBWfeXxNnaIrU4A7pTw=:rw
    # 此时只有heoller用户才有权限访问了
    [zk: localhost:2181(CONNECTED) 2] get /nodeWithACL
    org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /nodeWithACL
    # 需要添加授权信息才有权限
    [zk: localhost:2181(CONNECTED) 3] addauth digest heoller:123456
    [zk: localhost:2181(CONNECTED) 14] get /nodeWithACL
    aclnode
  2. 明文方式

    # 先登录,再使用auth授权
    [zk: localhost:2181(CONNECTED) 0] addauth digest iholen:111111
    [zk: localhost:2181(CONNECTED) 1] create /nodeDigest mingwen auth:iholen:111111:rw
    Created /nodeDigest
    [zk: localhost:2181(CONNECTED) 1] get /nodeDigest
    org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /nodeDigest
    [zk: localhost:2181(CONNECTED) 2] addauth digest iholen:111111
    [zk: localhost:2181(CONNECTED) 3] get /nodeDigest
    mingwen
  3. IP模式

    create /ipnode ipnode ip:192.168.1.161:rw
    setAcl /ipnode ip:192.168.1.161:rw,ip:192.168.1.162:rw
  4. Super模式
    zkSuper

-Dzookeeper.DigestAuthenticationProvider.superDigest=super:admin:x1nq8J5GOJVPY6zgzhtTtA9izLc=

事务日志

客户端每次事务操作,服务端都会将这些操作记录在事务日志中,事务日志默认存放在dataDir中,可通过设置dataLogDir设置存储路径。zk在存储事务日志时会频繁的进行磁盘IO,为了提升效率,zk创建事务日志文件时就进行了文件空间的预分配,预分配的空间大小可以通过zookeeper.preAllocSize参数设置。
zk提供了查看事务日志的工具,org.apache.zookeeper.server.LogFormatter

➜  ~ cd /Users/henry/zookeeper/lib
➜  lib> java -classpath .:slf4j-api-1.7.25.jar:zookeeper-3.6.1.jar:zookeeper-jute-3.6.1.jar org.apache.zookeeper.server.LogFormatter /Users/henry/zookeeper/data/version-2/log.1
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
ZooKeeper Transactional Log File with dbid 0 txnlog format version 2
20-11-28 上午12时03分31秒 session 0x10004e9a70f0000 cxid 0x0 zxid 0x1 createSession 30000
 2,1371985504

20-11-28 上午12时03分45秒 session 0x10004e9a70f0000 cxid 0x2 zxid 0x2 closeSession v{}
 2,1371985504

20-11-28 上午12时03分49秒 session 0x10004e9a70f0001 cxid 0x0 zxid 0x3 createSession 30000
 2,1371985504

20-11-28 上午12时03分55秒 session 0x10004e9a70f0001 cxid 0x1 zxid 0x4 create '/node1,#6e6f646531,v{s{31,s{'world,'anyone}}},F,1
 2,7175659339

20-11-28 上午12时03分57秒 session 0x10004e9a70f0001 cxid 0x2 zxid 0x5 closeSession v{}
 2,7175659339

EOF reached after 5 txns.

数据快照

用于记录服务器某一时刻的全量数据,可通过snapCount设置每多少次事务操作生成一次快照.

java -classpath .:slf4j-api-1.7.25.jar:zookeeper-3.6.1.jar:zookeeper-jute-3.6.1.jar org.apache.zookeeper.server.SnapshotFormatter /Users/henry/zookeeper/data/version-2/snapshot.0

事务日志和数据快照为什么都要有?

快照用于快速恢复数据,反应了当时数据的状态,事务日志是全面的日志,在恢复数据时,可以先恢复快照数据,然后再通过事务日志进行增量恢复。