ZKEssentials读书笔记(二) - 18965050/ZookeeperEssentials GitHub Wiki

ZooKeeper架构

zk架构

ZK数据模型

ZK数据模型类似于Unix的文件系统(filesystem).每个节点在zk中被称为znode,里面可以存储数据 zk数据模型

  • znode中的数据以字节(byte)的方式存储,大小限制不能大于1M
  • 目前znode路径(path)只能以绝对路径方式表示, 不支持相对路径(chroot 这个特性在zk 3.2.0版本中新增了.这样, 不同的用户可以指定不同的根目录)
  • znode节点还包含版本号,创建,修改时间,访问控制列表(ACL)等信息. 当节点数据变更时,版本号会相应的增加

znode类型

znode有两种类型(每种类型又有有序,无序之分),在节点创建时指定

persistent znode

  • 持久化的znode创建之后,必须手动才能删除. 示例如下:
     create /hello world
     get /hello
    
  • 持久化znode一般用作数据存储,配置管理

ephemeral znode

  • 临时znode在会话结束,客户端或服务端崩溃的情况下会删除. 当然,也可以手动删除

  • 临时znode不能拥有子节点

     create -e /hello world
     
     create -e /hello/child aaa
     Ephemerals cannot have children: /hello/child
    
  • 临时znode的这种特性非常适合用作成员管理(member management)

sequential znode

  • zk对于有序节点会自动在节点名称后添加序号(十位数字,单向递增)

     create -s /hello world
     
     create -e -s /hello/world
    
  • 有序znode的这种特性适合用作分布式队列或锁的实现

Watch

  • zk client在对znode操作时可注册Watch.这样,当此znode发生变化(比如数据变化,节点子节点变化等)时,所有注册的Watch都会收到相应的事件,进行处理

  • Watch是一次性的. 当触发后需要继续监听相应的事件, 需要再次注册Watch

  • znode触发watch的事件包括:

    • 节点数据变化.通过getData操作注册. 触发操作为setData,事件为Watch.Event.EventType.NodeDataChanged
    • 子节点发生变化.通过getChildren操作注册. 触发操作为子节点的create,delete,事件为 Watch.Event.EventType.NodeChildrenChanged
    • 节点本身变化.通过exists操作注册. 触发操作为节点的create,delete事件为 Watch.Event.EventType.NodeCreatedWatch.Event.EventType.NodeDeleted
  • ZK以先进先出(FIFO)的方式严格保证注册Watch的触发顺序(比如两个Watch注册了某个事件, ZK保证Watch触发顺序为Watch注册顺序)

  • ZK保证事件在通知到client watch之前,此节点不会再有其他的变化(比如,zk保证节点不会发生变化,如果前一个数据变化事件还未通知到Watch)

  • ZK保证Watch事件的顺序(比如某个znode进行了数据修改和节点变化,zk保证此两个操作的事件顺序)

  • 由于watch是一次性触发的. 在重新复位监听的过程中可能会丢失节点变化事件. 这点在开发过程中需要注意

  • 如果client从server断开并重新连接, 不管连接到的是原先的server还是一个新的server, 注册过的watch都会被重新注册并触发(断开期间触发的事件将会被顺序的通知到Watch).但有一种情况除外, 就是client监听某个还未创建znode,在client断开期间, 此znode被创建并删除了, client重新连接后将不会收到任何事件

一个成员管理示例图见下: 用Watch进行成员管理

ZK操作

ZK操作

ZK访问控制列表(ACL)

ZK的ACL类似于Unix系统中的权限控制, 但其没有拥有者(ownership)的概念

内建的4中认证机制

  • World: 任何人都可以访问ZK服务
  • Auth: 用户认证
  • Digest:用户名/密码认证
  • IP Address:IP地址认证

ZK也支持插件形式的自定义认证机制

ZK ACL不具有传递性, 即不能传递给子节点

ZK中, 每个ACL有认证机制, 身份ID和对应的权限三部分组成.ZK中已定义了一些默认的ACL: 内建ACL

ZK状态(stat)结构

ZK znode状态结构可通过 statls2 命令查看.

  • cZxid: 节点创建时的事务ID
  • mZxid: 节点修改时的事务ID
  • pZxid: 节点子节点变化(增加, 删除)时的事务ID
  • ctime: 节点创建时的时间. 单位:毫秒
  • mtime: 节点修改时的时间. 单位:毫秒
  • dataVersion: 节点数据变化版本号
  • cversion: 节点子节点变化版本号
  • aclVersion: 节点ACL变化版本号
  • ephemeralOwner: 临时节点创建时的会话ID. 如果不是临时节点, 此值为0
  • dataLength: 节点数据长度
  • numChildren: 节点子节点数量

ZK内部工作原理

zk集群有个定额(quorum)的概念,数据存储或维持集群可用性必须要达到定额的数量. 定额数量由公式 total_num%2+1 j计算. 比如一个有5台机器组成的ZK集群,定额数量是3, 而由6台机器组成的ZK集群,定额数量是4. 这也是为什么ZK集群一般由奇数服务组成.

会话

  • zk client和server连接, 会生成一个会话. 会话id为64位的数字.
  • client连接server,可以设置会话超时时长(SESSION_TIMEOUT),单位毫秒.在会话超时时长内, client会向server发心跳检测, server会重置client的超时时长. 如果由于网络拥塞或断开等原因,导致会话超时,会话就会过期无效了(expired). 因此对于网络情况不太好的环境或大量机器组成的集群,建议SESSION_TIMEOUT设置长些
  • 会话状态流程图见下: 内建ACL

事务(更新请求才会有事务的概念)

  • ZK集群中的服务器分为领导者(leader)和追谁者(follower). 所有更改操作(修改数据, 增删节点等操作)都由leader发起,由followers进行投票决定.而所有读取请求(getData, exists等操作)均直接从follower获取, 以保证速度
  • ZK集群内部使用ZAB(ZooKeeper Atomic Broadcasting)协议进行消息的广播. ZAB协议是事务的, 确保要不一起成功, 或一起失败
  • ZK中的每个事务都需要经过两个流程: 选举领导者原子广播
    • 选举领导者: 每个参与选举的server 节点进入LOOKING状态, 如果已经选举出领导者,则对端节点会相互通知领导者是谁,并进入FOLLOWING状态.而领导者进入LEADING状态; 如果未选举出领导者,这通过选举协议进行领导者选举,直至某个服务节点胜出.选举协议消息包含服务器的id(sid)和最近的事务id(zxid),领导者由最大的zxid对应的sid担当, 其余变为follower
    • 原子广播: 更新事务请求会发往领导者, 领导者根据ZAB协议发送更新请求到每个follower. 只有达到定额数量追谁者同意此请求,事务才会被提交
  • ZK机器节点处理领导者和追随者之外, 还有一类节点:观察着.观察着和追谁者类似,除了没有投票选举的权利.追谁者是为了提升读请求(read request)而出现的
  • 事务提交后,会被追加(append)到事务日志. 在saving point点会异步产生快照. 事务日志存放目录由dataLogDir参数配置, 数据目录由dataDir配置
⚠️ **GitHub.com Fallback** ⚠️