一、简介
ZooKeeper 是一个开源的分布式协调服务,由雅虎创建并贡献给 Apache 软件基金会,现已成为 Apache 顶级项目之一。ZooKeeper 主要用于解决分布式应用中常见的数据管理、状态同步、集群协调等问题,为大型分布式系统提供高效且可靠的协同机制。
Zookeeper 是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。
二、特点和功能
ZooKeeper 的主要特点和功能简介:
- 数据模型与一致性保证: ZooKeeper 提供一个类似于文件系统的树形数据结构(命名空间),节点称为"ZNode",每个 ZNode 可以存储少量的数据(通常几 KB 到几十 KB)。ZooKeeper 保证在分布式环境中对 ZNode 的读写操作具有强一致性,即更新成功后所有后续的读请求都能看到最新的值,遵循 CP(Consistency, Partition-tolerance)原则。
- 分布式协调服务 : ZooKeeper 提供多种原语(Primitive)来实现分布式协作,如:
- 分布式锁:通过临时节点和节点监听机制实现互斥锁、读写锁等。
- 领导者选举:多个节点竞争成为集群的领导者,其他节点作为追随者。例如,在分布式系统中选择一个主节点进行任务分配或数据处理。
- 配置管理与服务发现:存储、分发和动态更新集群的配置信息,或者作为服务注册中心,使得客户端能够发现并连接到可用的服务实例。
- 组成员管理:跟踪集群中节点的加入、离开情况,支持心跳检测和会话管理。
- 原子性与有序性: ZooKeeper 提供原子性的读写操作,保证更新要么全部完成,要么不发生。此外,客户端观察到的操作顺序与全局一致,即所有客户端看到的操作序列是完全相同的。
- Watches 机制: ZooKeeper 支持客户端对 ZNode 的数据变化或子节点列表变化设置监视器(Watch)。当监控的事件发生时,ZooKeeper 会向客户端发送通知。Watches 是一次性的触发器,即触发后需要重新设置。这种机制使得分布式系统中的节点能够实时感知到状态变化,实现高效的事件驱动编程。
- 高可用性与容错性: ZooKeeper 集群通常由奇数个节点构成,采用 ZAB(ZooKeeper Atomic Broadcast)协议保证在部分节点故障的情况下仍能正常服务。ZAB 协议确保了数据的一致性和系统的恢复能力,即使在 Leader节点失败时也能快速选举出新的 Leader,并使集群恢复到一致状态。
三、Zookeeper数据结构
- ZooKeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看作是一棵树,每个节点称做一个 ZNode。
- 每一个 ZNode 默认能够存储 1MB 的数据,每个 ZNode 都可以通过其路径唯一标识。
ZooKeeper 的数据结构是一种层次化的命名空间,类似于传统的文件系统,但具有特定的特性和用途。以下是 ZooKeeper 数据结构的主要特点和组成部分:
命名空间(Namespace)
- 路径表示 :ZooKeeper 中的每个数据节点(ZNode)通过路径进行唯一标识,路径由一系列由斜杠(/)分隔的路径元素组成。例如,
/app/config/server1
表示一个名为server1
的 ZNode,位于/app/config
这个父节点下。 - 层级结构:如同文件系统的目录树,ZooKeeper 的命名空间支持无限层级的嵌套。这种结构使得数据可以根据逻辑关系组织成层次分明的树状结构。
ZNode(数据节点)
- 数据存储:每个 ZNode 存储一个小型的、字节形式的数据块。虽然实际限制可能随版本和配置有所不同,通常建议每个 ZNode 存储的数据不超过 1 MiB,以保持系统高效运行。ZNode 存储的数据可以是配置信息、状态标志、临时状态等。
- 元数据 :除了用户数据外,每个 ZNode 还包含一些元数据,如:
- 版本号(version):每次对 ZNode 的数据或元数据进行修改时,版本号都会递增,用于实现乐观锁控制。
- 时间戳(ctime, mtime):分别记录节点创建时间和最近一次修改时间。
- ACL(Access Control List):定义了哪些用户或角色对 ZNode 具有何种访问权限。
- 临时节点标记:ZNode 可以是持久的(persistent)或临时的(ephemeral)。临时节点在创建它的会话结束时会被自动删除,常用于表示会话相关状态。
节点类型
在 ZooKeeper 中,主要存在以下四种类型的 ZNode(数据节点):
-
持久节点(Persistent Node):
- 标识:无特殊标记
- 特征:一旦创建,除非被客户端明确地删除,否则会一直存在于 ZooKeeper 集群中。即使创建该节点的客户端会话结束,持久节点也不会被自动删除。
- 用途:用于存储需要长期保留且不受客户端会话生命周期影响的数据,如系统配置、静态资源映射、固定角色分配等。
-
临时节点(Ephemeral Node):
- 标识 :
ephemeral
- 特征:与创建它的客户端会话绑定。当客户端会话结束(如客户端主动关闭连接、网络中断或会话超时)时,临时节点会被自动删除。临时节点不能拥有子节点。
- 用途:表示与客户端会话相关的瞬时状态,如客户端在线状态、临时资源分配、会话关联的锁等。临时节点的生命周期与客户端会话一致,有助于实现会话失效时资源的自动清理。
- 标识 :
-
顺序节点(Sequential Node):
- 标识 :
sequential
- 特征:在创建节点时,ZooKeeper 会在节点名称后面自动追加一个递增的数字后缀,确保节点名称在整个集群中是唯一的。顺序节点可以是持久节点(Persistent Sequential Node)或临时节点(Ephemeral Sequential Node)。
- 用途:用于生成全局唯一的序列号,适用于分布式环境中需要唯一标识的任务、消息、租约等场景。顺序节点还可以用于实现基于节点创建顺序的公平锁、队列等数据结构。
- 标识 :
-
带过期时间的节点(TTL-based Node):
- 标识 :
PERSISTENT_SEQUENTIAL_WITH_TTL
或类似的表述,具体取决于 ZooKeeper 版本和 API 实现。 - 特征:除了具备持久节点或临时节点的基本属性外,这类节点还设置了过期时间(Time-to-Live, TTL)。在指定的时间间隔过后,如果节点未被显式更新或删除,ZooKeeper 会自动删除该节点。
- 用途:用于存储具有有效期的临时或持久数据,如定时清理的临时资源、定时任务的注册信息、具有生存周期的会话关联状态等。过期时间机制可以减轻系统中需要定期清理过期数据的负担。
- 标识 :
这四种类型的 ZNode 结合使用,可以满足分布式系统中多样化的数据管理需求,如状态存储、资源分配、协调控制、定时清理等。根据实际应用场景选择合适的节点类型,有助于优化系统设计和提升协调效率。请注意,不同 ZooKeeper 版本或实现可能对节点类型的支持有所差异,具体功能应参考所使用的 ZooKeeper 文档或 API 参考。
四、Watch(监视器)
ZooKeeper 提供了一种强大的事件监听机制------Watch(监视器),允许客户端订阅特定节点的变化事件。当订阅的事件发生时,ZooKeeper 服务端会向相应的客户端发送通知。Watch 事件监听是 ZooKeeper 实现分布式协调、状态同步等核心功能的关键手段之一。
类型与触发条件
ZooKeeper 支持两种类型的 Watch 事件:
-
数据变更 Watch(Data Watches) :
当客户端对某个 ZNode 设置数据变更 Watch 后,如果该 ZNode 的数据内容发生任何更改(包括创建、更新、删除),ZooKeeper 会向客户端发送一个通知。注意,数据变更 Watch 是一次性触发器,即触发后需要客户端重新设置才能继续监听后续变化。
-
子节点列表变更 Watch(Child Watches) :
如果客户端对某个 ZNode 设置子节点列表变更 Watch,当该 ZNode 的子节点集发生变化(新增、删除子节点)时,ZooKeeper 会发送通知。同样,子节点列表变更 Watch 也是一次性触发器。
设置 Watch
客户端可以通过以下方式设置 Watch:
-
使用 ZooKeeper API :
在使用 ZooKeeper 客户端库(如 Java 的
org.apache.zookeeper.ZooKeeper
类)编写程序时,可以在相应方法中指定是否设置 Watch。例如,getData()
方法可以设置数据变更 Watch,getChildren()
方法可以设置子节点列表变更 Watch。 -
使用 ZooKeeper 命令行工具 :
在 ZooKeeper 命令行客户端(如
zkCli.sh
)中,通过在命令中添加watch
参数来设置 Watch。例如,get path watch
会在获取数据的同时设置数据变更 Watch,ls path watch
会在列出子节点的同时设置子节点列表变更 Watch。
事件通知与处理
当触发 Watch 的事件发生时,ZooKeeper 服务端会通过客户端与服务端之间已建立的连接,向客户端发送一个 Watch 事件通知。通知包含以下信息:
-
事件类型 :
指明触发的具体事件类型,如
NodeDataChanged
(数据变更)、NodeDeleted
(节点删除)、NodeChildrenChanged
(子节点列表变更)等。 -
节点路径 :
发生事件的 ZNode 的完整路径。
-
状态码 :
通常表示事件通知的成功与否,以及可能的错误代码。
客户端在接收到 Watch 事件通知后,通常会调用预定义的回调函数(使用 ZooKeeper API 时)或在命令行中显示通知(使用命令行工具时),以便应用程序及时响应事件并采取相应的行动。
注意事项
-
一次性触发 :
Watch 是一次性触发器,这意味着一旦触发事件并发送通知后,该 Watch 就会自动移除。若想继续监听同一事件,客户端需在接收到通知后重新设置 Watch。
-
异步通知 :
Watch 事件通知是异步发送的,不保证立即送达。客户端在设置 Watch 后,不应假设事件会立即触发或通知会立即到达。
-
客户端会话状态 :
如果客户端会话由于网络问题、超时等原因中断,所有与该会话关联的 Watch 将被移除,客户端需要在重新建立会话后重新设置 Watch。
-
性能考虑 :
大规模集群中大量使用 Watch 可能会影响 ZooKeeper 服务端的性能。在设计系统时应合理规划 Watch 的使用,避免过度依赖或滥用。
应用场景
Watch 事件监听广泛应用于分布式系统中的各种场景,如:
-
配置变更通知 :
当存储在 ZooKeeper 中的配置数据发生变化时,客户端可以立即得到通知并应用新的配置。
-
服务发现 :
客户端监听服务注册节点的子节点列表变化,实时掌握服务实例的上线、下线情况。
-
分布式锁与同步 :
客户端通过监听锁节点的状态变化来实现锁的获取与释放,或者通过监听同步点的变化实现分布式流程的协调。
-
集群管理与监控 :
监控集群中节点的状态变化,及时发现异常并作出响应。
总之,ZooKeeper 的 Watch 事件监听机制为分布式系统提供了实时、灵活的事件驱动能力,极大地简化了状态同步、协调控制等复杂问题的实现,是 ZooKeeper 作为分布式协调服务的核心特性之一。
五、客户端常用命令
ZooKeeper 客户端提供了丰富的命令来与 ZooKeeper 集群进行交互,以下是一些常用的客户端命令及其用途:
连接与会话管理
-
连接服务器:
bash./zkCli.sh [-server host:port] [options]
-server host:port
:指定要连接的 ZooKeeper 服务器地址和端口。如果省略,可能会使用默认配置或尝试连接本地服务器。options
:可选参数,如设置超时时间(-timeout
)、启用只读模式(-readonly
)等。
-
列出当前连接的服务器信息:
bashstat
-
退出客户端:
bashquit
节点操作
-
查看节点信息:
bashls [-s] [-w] [-R] path
ls
:列出指定路径下的子节点。-s
:显示节点的统计信息(大小、子节点数量等)。-w
:显示节点的 watches信息。-R
:递归列出所有子节点及其子节点。
-
创建节点:
bashcreate [-s] [-e] [-c] [-t ttl] path data [acl]
create
:创建一个节点。-s
或-sequential
:创建顺序节点,自动在节点名后添加递增的序列号。-e
或-ephemeral
:创建临时节点,与客户端会话关联,会话结束时节点自动删除。-c
或-container
(可能需要特定版本或插件支持):创建容器节点,用于批量管理子节点。-t ttl
:(可能需要特定版本或插件支持)设置节点的过期时间(TTL)。path
:节点路径。data
:节点存储的数据(字符串形式)。acl
:可选的访问控制列表(ACL),如world:anyone:cdrwa
。
-
读取节点数据:
bashget path [watch]
get
:获取节点的当前数据。watch
:可选参数,设置数据观察者(watcher),当节点数据发生变化时,客户端收到通知。
-
更新节点数据:
bashset path data [version]
set
:更新节点数据。path
:节点路径。data
:新的节点数据(字符串形式)。version
:可选参数,指定节点版本号,用于乐观锁控制。
-
删除节点:
bashdelete path [version]
delete
:删除指定节点。path
:节点路径。version
:可选参数,指定节点版本号,用于乐观锁控制。
监听与通知
-
设置节点数据观察:
bashget path [watch]
如前所述,通过
get
命令并指定watch
参数,可以设置对节点数据变化的通知。 -
设置子节点列表观察:
bashls [-w] path
使用
ls
命令并指定-w
参数,可以设置对节点子节点列表变化的通知。
访问控制
-
查看节点ACL:
bashgetAcl path
显示指定节点的访问控制列表(ACL)。
-
设置节点ACL:
bashsetAcl path acl
修改指定节点的访问控制列表(ACL)。
其他操作
-
检查节点是否存在:
bashexists path [watch]
检查指定节点是否存在,可选地设置数据观察者(watcher)。
-
重置客户端会话:
bashsession [-password password] [-read [-watches]] | [-write] | [-delete|-create|-multi|-reconfig] | [-setid id]
用于管理客户端会话,如设置会话密码、切换会话模式(只读/读写)等。
以上列举的是 ZooKeeper 客户端常用的命令,实际使用时请根据具体版本的 ZooKeeper 和客户端工具(如 zkCli.sh
)提供的功能进行操作。部分高级功能或特定版本的特性可能未在此处涵盖,建议查阅官方文档或使用时的命令帮助信息以获取最准确的信息。