Znode

结构:

  • path:唯一路径
  • childNode:子节点
  • stat:状态属性
  • type:节点类型

节点类型:

类型 描述
PERSISTENT 持久节点(默认节点)
PERSISTENT_SEQUENTIAL 持久序号节点
EPHEMERAL 临时节点(不可再拥有子节点)
EPHEMERAL_SEQUENTIAL 临时序号节点(不可再拥有子节点)

不过看了源码后发现不止这些.

ZK集群

集群角色:

  • leader : 主节点,写节点.选举产生
  • follower : 从节点,读节点.
  • observer : 读节点,没有投票权,用于缓解集群的读压力,但同时又不增加选举的复杂度(像不像外包?)

集群选举:

  • 触发条件 :

    • 服务节点初始化启动
    • 半数以上节点无法和leader建立连接
  • 投票规则 : 第一轮投票全部投给自己 第二轮投票给myid比自己大的相邻节点

  • 选举完成条件 : 当某节点得票超过半数,则其当选leader,选举结束

Watcher 事件监听器

  • ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性

崩溃恢复

  • 当leader出现异常或者网络异常,导致过半的节点无法与leader取得联系,那么集群会进入崩溃恢复阶段,重新选举出新的leader
  • 选出新leader后,新leader要完成整个集群的同步工作,也就是保证过半的节点能够和leader保持数据状态一致

消息广播

  • 当集群数据同步完成后,才进入消息广播阶段,才能对外开放服务

zk写数据过程

  • 用户找到其中一个follower/observer,它会将写请求转发给leader
  • leader会为这个请求生成一个全局唯一的zxid(事务编号),然后向全体follower发起投票来决定接不接受这个写请求
  • 如果follower收到的写请求的zxid大于本地记录的最大zxid,那么就会向leader回复一个ack
  • 如果同意过半,那么leader会向全体follower发起无条件写请求,follower执行之后会更新本地记录中的zxid
  • 考虑一种情况,如果leader向follower发送一个请求A,但是它丢失了,之后leader又发送了一个请求B,此时follower的ack实际是回复请求A的,但leader可能会误会成同意执行请求A.为了解决这种问题,zk的做法是为每个follower维护一个滑动窗口,全为唯一的zxid作为窗口编号,只接收按序到达的ack.

分布式锁

  • 首先肯定是如何获取锁,因为创建节点的唯一性,我们可以让多个客户端同时创建一个临时节点,创建成功的就说明获取到了锁 。然后没有获取到锁的客户端也像上面选主的非主节点创建一个 watcher 进行节点状态的监听,如果这个互斥锁被释放了(可能获取锁的客户端宕机了,或者那个客户端主动释放了锁)可以调用回调函数重新获得锁。
  • zk 中不需要向 redis 那样考虑锁得不到释放的问题了,因为当客户端挂了,节点也挂了,锁也释放了