温故知新-快速理解zookeeper功能&应用&选举机制

zooKeeper是一个经典的分布式数据一致性解决方案, 致力于为分布式应用提供一个高性能、 高可用, 且具有严格顺序访问控制能力的分布式协调存储服务。

  • 维护配置信息
  • 分布式锁服务
  • 集群管理
  • 生成分布式唯一ID

zookeeper特点

  • 高性能

zooKeeper将全量数据存储在内存中, 并直接服务于客户端的所有非事务请求, 尤其适用于以读为主的应用场景

  • 高可用

zooKeeper一般以集群的方式对外提供服务, 一般3 ~ 5台机器就可以组成一个可用的Zookeeper集群了, 每台机器都会在内存中维护当前的服务器状态, 并且每台机器之间都相 互保持着通信。 只要集群中超过一半的机器都能够正常工作, 那么整个集群就能够正常对外服务

  • 严格顺序访问

对于来自客户端的每个更新请求, ZooKeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序

zookeeper的数据模型

  • zookeeper的数据节点可以视为树状结构(或者目录) , 树中的各节点被称为znode(即zookeeper node) , 一个znode可以有多个子节点。 zookeeper节点在结构上表现为树状; 使用路径path来定位某个znode;
  • znode, 兼具文件和目录两种特点。 既像文件一样维护着数据、 元信息、 ACL(权限控制)、 时间戳等数据结构, 又像目录一样可以作为路径标识的一部分;

节点数据结构

  • 一个znode大体上分为3各部分:
    • 节点的数据: 即znode data(节点path, 节点data)的关系就像是java map中(key,value)的关系节点的子节点children
    • 节点的状态stat: 用来描述当前节点的创建、 修改记录, 包括cZxid、 ctime等
    • 节点状态stat的属性
[zk: localhost:2181(CONNECTED) 7] get /ns-1/tenant
cZxid = 0x6a0000000a
ctime = Wed Mar 27 09:56:44 CST 2019
mZxid = 0x6a0000000a
mtime = Wed Mar 27 09:56:44 CST 2019
pZxid = 0x6a0000000e
cversion = 2
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2
复制代码
  • 属性说明:

    cZxid: 数据节点创建时的事务 ID ctime: 数据节点创建时的时间 mZxid: 数据节点最后一次更新时的事务 ID mtime: 数据节点最后一次更新时的时间 pZxid: 数据节点的子节点最后一次被修改时的事务 ID cversion: 子节点的更改次数 dataVersion: 节点数据的更改次数 aclVersion: 节点的 ACL 的更改次数 ephemeralOwner: 如果节点是临时节点, 则表示创建该节点的会话的 SessionID; 如果节点是持久节点, 则该属性值为 0 dataLength: 数据内容的长度 numChildren: 数据节点当前的子节点个数

节点类型

zookeeper中的节点有两种, 分别为临时节点和永久节点。节点的类型在创建时即被确定, 并且不能改变。

  • 临时节点: 该节点的生命周期依赖于创建它们的会话。 一旦会话(Session)结束, 临时节点将被自动删除, 当然可以也可以手动删除。 虽然每个临时的Znode都会绑定到一个客户端会话, 但他们对所有的客户端还是可见的。 另外, ZooKeeper的临时节点不允许拥有子节点。
  • 持久化节点: 该节点的生命周期不依赖于会话, 并且只有在客户端显示执行删除操作的时候, 他们才能被删除;

zookeeper常用Shell命令

  • 新增节点

create [-s] [-e] path data #其中-s 为有序节点, -e 临时节点

  • 更新节点

更新节点的命令是 set , 可以直接进行修改eg:set /hadoop "345" 基于版本号进行更改时, 乐观锁机制, 当你传入的数据版本号(dataVersion) 和当前节点的数据版本号不符合时,zookeeper 会拒绝本次修改:eg: set /hadoop "3456" 1 version No is not valid : /hadoop

  • 删除节点

delete path [version] 和更新节点数据一样, 也可以传入版本号, 当你传入的数据版本号 (dataVersion)和当前节点的数据版本号不符合时,zookeeper 不会执行删除操作。 要想删除某个节点及其所有后代节点, 可以使用递归删除, 命令为 rmr path

  • 查看节点

get path

  • 查看节点状态

可以使用 stat 命令查看节点状态, 它的返回值和 get 命令类似, 但不会返回节点数据

  • 查看节点列表

查看节点列表有 ls path 和 ls2 path 两个命令, 后者是前者的增强, 不仅可以查看指定路径下的所有节点, 还可以查看当前节点的信息

  • 监听器 get path [watch]

使用 get path [watch] 注册的监听器能够在节点内容发生改变的时候, 向客户端发出通知。 需要注意的是 zookeeper 的触发器是一次性的 (One-time trigger), 即触发一次后就会立即失效。

  • 监听器stat path [watch]

使用 stat path [watch] 注册的监听器能够在节点状态发生改变的时候, 向客 户端发出通知

  • 监听器ls\ls2 path [watch]

使用 ls path [watch] 或 ls2 path [watch] 注册的监听器能够监听该节点下所有子节点的增加和删除操作

zookeeper的acl权限控制

概述

  • zookeeper 类似文件系统, client 可以创建节点、 更新节点、 删除节点,可以通过acl控制节点的权限的控制;
  • 使用scheme: id: permission 来标识, 主要涵盖 3 个方面:

    权限模式(scheme) : 授权的策略 授权对象(id) : 授权的对象 权限(permission) : 授予的权限

  • 其特性如下
  • zooKeeper的权限控制是基于每个znode节点的, 需要对每个节点设置权限
  • 每个znode支持设置多种权限控制方案和多个权限
  • 子节点不会继承父节点的权限, 客户端无权访问某节点, 但可能可以访问它的子节点

权限模式

  • world 只有一个用户: anyone, 代表登录zokeeper所有人(默认)
  • ip 对客户端使用IP地址认证
  • auth 使用已添加认证的用户认证
  • digest 使用“用户名:密码”方式认证

授权的对象

  • 给谁授予权限 ​- 授权对象ID是指, 权限赋予的实体, 例如: IP 地址或用户。

授予的权限

  • create、delete、read、writer、 admin,即 增、 删、 改、 查、 管理权限,这5种权限简写为cdrwa; 注意:这5种权限中, delete是指对子节点的删除权限, 其它4种权限指对自身节点的操作权限
  • 授权的相关命令
    • getAcl getAcl 读取ACL权限
    • setAcl setAcl 设置ACL权限
    • addauth addauth 添加认证用户

zookeeper事件监听机制

watcher概念

  • zookeeper提供了数据的发布/订阅功能,多个订阅者可同时监听某一特定主题对 象,当该主题对象的自身状态发生变化时(例如节点内容改变、节点下的子节点列表改变等),会实时、主动通知所有订阅者 ​- zookeeper采用了Watcher机制实现数据的发布/订阅功能。该机制在被订阅对 象发生变化时会异步通知客户端,因此客户端不必在Watcher注册后轮询阻塞,从而减轻了客户端压力。 ​- watcher机制实际上与观察者模式类似,也可看作是一种观察者模式在分布式场 景下的实现方式。

watcher架构

Watcher实现由三个部分组成:

  • Zookeeper服务端
  • Zookeeper客户端
  • 客户端的ZKWatchManager对象

客户端首先将Watcher注册到服务端,同时将Watcher对象保存到客户端的Watch管 理器中。当ZooKeeper服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的Watch管理器会触发相关Watcher来回调相应处理逻辑,从而完成整体的数据发布/订阅流程

watcher特性

watcher接口设计

Watcher是一个接口,任何实现了Watcher接口的类就是一个新的Watcher。Watcher内部包含了两个枚举类:KeeperState、EventType

  • Watcher通知状态(KeeperState) KeeperState是客户端与服务端连接状态发生变化时对应的通知类型。路径为 org.apache.zookeeper.Watcher.Event.KeeperState,是一个枚举类,其枚举属性 如下:
  • Watcher事件类型(EventType) EventType是数据节点(znode)发生变化时对应的通知类型。EventType变化时 KeeperState永远处于SyncConnected通知状态下;当KeeperState发生变化时, EventType永远为None。其路径为org.apache.zookeeper.Watcher.Event.EventType, 是一个枚举类,枚举属性如下:
    注:客户端接收到的相关事件通知中只包含状态及类型等信息,不包括节点变化前后的具体内容,变化前的数据需业务自身存储,变化后的数据需调用get等方法重新获取;

应用

了解完zk的基本特性,据此分析一下具体的使用场景案例

配置中心

eg: 数据库用户名和密码信息放在一个配置文件中,应用读取该配置文件,配置文件信息放入缓存。若数据库的用户名和密码改变时候,还需要重新加载缓存,比较麻烦,通过ZooKeeper可以轻松完成,当数据库发生变化时自动完成缓存同步。 设计思路:

  1. 连接zookeeper服务器
  2. 读取zookeeper中的配置信息,注册watcher监听器,存入本地变量
  3. 当zookeeper中的配置信息发生变化时,通过watcher的回调方法捕获数据变化事件
  4. 重新获取配置信息

生成分布式唯一ID

在单库单表型系统中,通常可以使用数据库字段自带的auto_increment属性来自动为每条记录生成一个唯一的ID。但是分库分表后,就无法在依靠数据库的auto_increment属性来唯一标识一条记录了。可以用zookeeper在分布式环境下生成全局唯一ID。 设计思路:

  1. 连接zookeeper服务器
  2. 指定路径生成临时有序节点
  3. 取序列号及为分布式环境下的唯一ID

注:生产环境,一般采用别的方式:例如雪花算法等

分布式锁

分布式锁有多种实现方式,比如通过数据库、redis都可实现。作为分布式协同 工具ZooKeeper,当然也有着标准的实现方式。下面介绍在zookeeper中如何实现排他锁。 设计思路:

  1. 每个客户端往/Locks下创建临时有序节点/Locks/Lock 000000001
  2. 客户端取得/Locks下子节点,并进行排序,判断排在最前面的是否为自己,如果自己的锁节点在第一位,代表获取锁成功
  3. 如果自己的锁节点不在第一位,则监听自己前一位的锁节点。例如,自己锁节点 Lock 000000001
  4. 当前一位锁节点(Lock 000000002)的逻辑
  5. 监听客户端重新执行第2步逻辑,判断自己是否获得了锁
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章