zookeeper概述(应用场景及基本概念)
ZooKeeper 是一个高性能的分布式数据一致性解决方案,它将那些复杂的,容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并提供一系列简单的接口给用户使用
基础概念
集群角色
- leader 是整个 zookeeper 集群的工作机制中的核心
- follower 是 Zookeeper 集群状态的跟随者
- observer 充当一个观察者的角色
会话
客户端与 zookeeper 服务器建立一个 tcp 长连接来维持一个 session 会话,客户端能够通过心跳检测与服务器保持有效的会话,也能向 zookeeper 服务器发送请求并获得响应。
数据节点
zookeeper 的数据模型是树形结构,树的节点称为 znode
, znode中可以保存信息。
两种类型
- 临时节点(ephemeral): 客户端和服务器断开连接后,创建的节点自动删除
- 持久节点(persistent): 客户端和服务器断开连接后,创建的节点不删除
四种形式(默认persistent)
- 持久化目录节点(persistent)
断开连接后,该节点依旧存在 - 持久化顺序编号目录节点(persistent_sequential)
断开连接后,该节点依旧存在,只是 zookeeper 给该节点名称进行顺序编号 - 临时目录节点(ephemeral)
断开连接后,该节点被删除 - 临时顺序编号目录节点(ephemeral_sequential)
断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
创建 znode 时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护。
在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序。
悲观锁和乐观锁
悲观锁是数据库中一种非常严格的锁策略,具有强烈的排他性,悲观锁认为事务访问相同数据的时候一定会出现相互干扰,所以简单粗暴的使用排他访问的方式。
乐观锁认为不同事务访问相同资源是很少出现相互干扰的情况,因此在事务处理期间不需要进行并发控制,只有真正出现不一致的情况,才会控制。
乐观锁,为了减少并发控制,对于数据库通常的做法是在每个表中增加一个 version 版本字段,事务修改数据之前先读出数据(包含版本号),然后把这个读取出来的版本号加入到更新语句的条件中,如果更新失败了,就说明这个数据从读取出到更新前,已经被修改过了,这时候可以交由客户端抛出异常,或者选择重新获取数据。
zookeeper 的版本
zookeeper 的版本号就是起到并发状态下数据的一致性作用,zookeeper 中的版本类型有:
- version: 当前数据节点数据内容的版本号
- cversion: 当前数据节点子节点的版本号
- aversion: 当前数据节点 ACL 变更版本号
watcher
zookeeper 允许用户在指定节点上注册一些 watcher,当数据节点发生变化的时候,zookeeper 服务器会把这个变化的通知发送给感兴趣的客户端。
ACL 权限控制
ACL 是 Access Control Lists 的简写,Zookeeper 采用 ACL 策略来进行权限控制,有以下权限:
- CREATE: 创建子节点的权限
- READ: 获取节点数据和子节点列表的权限
- WRITE: 更新及诶单数据的权限
- DELETE: 删除子节点的权限
- ADMIN: 设置节点 ACL 的权限
stat 节点状态
- czxid: 引起这个 znode 创建的 zxid,每次修改 zookeeper 状态都会收到一个 zxid 形式的时间戳,也就是 zookeeper 事务id。
- ctime: znode 被创建的毫秒数(从1970年开始)
- mzxid: znode 最后更新的 zxid
- mtime: znode最后修改的毫秒数(从1970年开始)
- pzxid: znode最后更新的子节点zxid
- cversion: znode子节点变化号,znode子节点修改次数
- dataversion - znode数据变化号
- aclVersion - znode访问控制列表的变化号
- ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id,如果不是临时节点则是0。
- dataLength- znode的数据长度
- numChildren - znode子节点数量
工作机制
选举机制
- 半数机制(Paxos 协议): 集群中半数以上机器存活时集群可用,所以zookeeper适合装在奇数台机器上。
- zookeeper 工作时,有一个节点为leader,其他为follower,leader是通过内部的选举机制临时产生的。
假设有 5 台服务器组成的 zookeeper 集群,它们的 id 为1-5,这些服务器依序启动:
服务器1
启动,此时它发出去的报没有任何响应,所以它的选举状态一直是 LOOKING 状态。服务器2
启动,与服务器1
进行通信,互相交换选举结果,由于两者都没有历史数据,所以 id 值较大的服务器2
胜出,但是没有达到半数以上的服务器都同意选举服务器2
,所以服务器1、2
还是继续保持 LOOKING 状态。服务器3
启动,根据 id 值选举,此时有三台服务器选举了服务器3
,它成为了这次选举的 leader。服务器4
启动,由于前面已经有半数以上的服务器选举了服务器3,所以它只能成为 follower。服务器5
启动,同第 4 步,成为 follower。
写数据流程
- 假设 client 向 zookeeper 集群的 server1 上发送一个写请求。
- 如果 server1 不是 leader,则会把接受到的请求转发给 leader,leader 会将写请求广播给各个server, 各个 server 写成功后会通知 leader。
- 当 leader 收到大多数 server 数据写成功的消息,就认为数据写成功了,之后 leader 会通知 server1 数据写成功了。
- server1 收到 leader 返回的成功消息后,会通知 client 数据写成功了,整个写操作成功。
应用场景
数据发布/订阅
发布者将数据发布到 zk 集群上,客户端订阅感兴趣节点,当服务器在这些节点的数据发生变化时,就通知客户端,客户端得到通知后就可以到服务器获取更新的信息。
统一配置管理
- 把配置文件的数据发布到 zk 集群的某个节点上
- 应用启动时主动到 zk 上获取配置信息,并注册 watcher 监听
- 当配置需要修改时,直接修改 zk 上存储的数据
- zk 推送变更给应用,触发 watcher 的回调函数
- 应用根据逻辑,主动获取新的配置信息
负载均衡
用 db 举例:
- DB 在启动的时候为自己在 zk 上注册一个临时节点,临时节点在服务器出现问题的时候会自动的从 zk 上删除, 这样 zk 上永远都是最新可用的节点列表。
- 客户端在需要读写 DB 的时候,先去 zookeeper 得到所有可用的 DB 的连接的列表。
- 客户端随机选择一个节点与之建立连接。
- 当客户端发现链接不可用的时候,再次从 zk 上获取可用的节点,也可以在刚刚获取的那个列表里移除掉不可以给的节点,再随机选择一个进行连接。
命名服务
以数据库表的 id 举例:
数据库的id可以是自增id 或 UUID, 自增id只能在单库单表中使用,UUID 可以在分布式中使用但字段没有规律,难于理解。可以借助 zk 生成一个可以在集群中使用的,顺序增长的,命名易于理解的 id。
分布式协调/通知
在分布式系统中,常常需要知道某个机器是否可用,传统的开发中,可以通过 ping 某个主机来实现,ping得通说明对方是可用的. zk 中让所有机器都注册一个临时节点,判断一个机器是否可用,只需要判断这个节点在 zk 中是否存在就可以了,不需要直接去连接需要检查的服务器,降低系统的复杂度。
文章标题:zookeeper概述(应用场景及基本概念)
文章字数:2.1k
本文作者:Waterandair
发布时间:2017-11-25, 09:23:42
最后更新:2019-12-28, 14:03:59
原始链接:https://waterandair.github.io/2017-11-25-zookeeper-intro.html版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。