Logo
Section 1 / 3

Zookeeper:简介

本课程介绍 Zookeeper 服务。

导入

Zookeeper:简介

本课程介绍 Zookeeper 服务。

Zookeeper 是企业级大数据部署中不可或缺的关键组件。它是一个集中式服务,用于维护配置信息、命名管理、提供分布式同步以及组服务。这些服务均被分布式应用程序所使用。根据官方网站的说明,Zookeeper 的名字来源于“协调分布式系统就像一个动物园”这一概念。

从核心来看,Zookeeper 非常易于理解。可以将其视为一种分层的文件系统或树形结构。Zookeeper 的基本构建单元是 znode。一个 znode 可以存储数据(如同文件),也可以包含子 znode(如同目录)。Zookeeper 整体设计提供了一个高可用的系统,由构成层次化命名空间的 znode 组成。以下是 znode 结构的示意图:

...
Zookeeper node hierarchy

Zookeeper 可以以单机模式运行在单一服务器上,也可以在多台机器组成的集群中以复制模式运行,这种集群被称为 ensemble。在复制模式下,通过确保对 znode 树的修改被复制到大多数节点来实现高可用性。如果 ensemble 中少数机器发生故障,至少仍有一台存活的机器保存着最新的状态。举个例子:假设有五台机器(A、B、C、D 和 E)组成 Zookeeper ensemble。当需要更新时,必须有大多数机器(即多数派,称为 quorum)完成更新。假设 A、C 和 E 成功接收了更新。如果其中两台机器(少数派)发生故障(例如 A 和 E),服务仍能正常运行。此时,仍有 C 保持最新状态,而 B 和 D 两台存活的机器可以追赶至最新状态。这个看似简单的高可用性算法实际上非常难以正确实现。

Zookeeper 使用一种名为 Zab 的协议来实现上述机制。该协议的细节超出了本文范围。但总体而言,该协议分为两个阶段:第一阶段是选举领导者,其余节点成为跟随者,并与领导者同步状态;第二阶段所有写请求都转发给领导者,由其广播更新给跟随者。一旦变更被大多数机器确认提交,发起请求的客户端就会收到成功提交的通知。ensemble 中的所有机器都会先将更新写入磁盘,再更新内存中的 znode 树。客户端可以向任意机器发送读请求,响应直接来自内存,因此查询速度很快。

如果领导者失效,将重新进行选举。当原来的领导者恢复后,会以跟随者的身份重新加入集群。Zab 协议与另一个著名的领导者选举协议 Paxos 类似,但在多个方面存在差异。

数据模型

每个 znode 都关联有一个访问控制列表(ACL),用于控制谁可以读取或写入特定的 znode。此外,对 znode 的读写操作是原子性的:一次读或写请求要么完全成功,要么完全失败,绝不会出现部分读写的情况。znode 通过路径进行引用。例如,“/config/hostname” 指的是位于父节点 “config” 下的子节点 “hostname”。通过路径引用 znode,使得我们可以将 Zookeeper 视为一个分层的文件系统。

除了临时 znode 外,还有 顺序 znode,它们的名称中附带一个递增的序列号。该序列号由父 znode 维护的一个单调递增计数器生成。序列号可用于在分布式系统中对事件施加全局顺序。我们将在后续实现分布式锁时看到它的实际应用。Zookeeper 还支持在 znode 上设置监听器(watches),当 znode 发生变化时触发通知。一个典型的应用场景是监控应用程序配置的变化。应用程序可以在存放配置的 znode 上设置监听器,一旦其他程序修改了该配置,就能立即收到通知。

快速入门

为了感受 Zookeeper 的工作方式,我们将执行一系列命令来启动 Zookeeper 服务,并通过 telnet 查询其版本信息。

1## 查看配置文件 2cat /opt/zookeeper/conf/zoo.cfg 3 4## 启动 Zookeeper 服务 5zkServer.sh start 6 7## 使用 telnet 连接 Zookeeper 服务 8telnet 127.0.0.1 2181 9 10## 连接成功后输入以下命令 11srvr 12 13## 查看所有四字母命令列表 14curl http://localhost:8080/commands
...

Zookeeper 的配置文件位于 zoo.cfg。其中的 tickTime 设置是 Zookeeper 使用的基本时间单位(以毫秒为单位),用于控制心跳和超时机制。例如,客户端在 Zookeeper 服务器上的最小会话超时时间为两个 tick。默认情况下,Zookeeper 服务器在端口 21812181 接受客户端连接。系统还提供了一些四字母命令,如 srvr,用于管理 Zookeeper 服务。默认仅允许执行 srvr 命令。此外,可通过 curl 访问 Zookeeper 内建 Web 服务器(运行在端口 8080)的 /commands 端点,获取所有四字母命令的列表。未来,四字母命令将被 AdminServer 所取代。

连接终端后,请按顺序执行下方代码框中的命令。

1# 查看配置文件 2cat /opt/zookeeper/conf/zoo.cfg 3 4# 启动 Zookeeper 服务 5zkServer.sh start 6 7# 使用 telnet 连接 Zookeeper 服务 8telnet 127.0.0.1 2181 9 10# 连接成功后输入以下命令 11srvr 12 13# 查看所有四字母命令列表 14curl http://localhost:8080/commands
Terminal

一致性

在本节课结束前,我们来讨论一下一致性问题。Zookeeper 对所有 znode 树的变更都会分配一个全局唯一的标识符,称为 Zookeeper 事务 ID(zxid)。这些事务 ID 保证了更新的顺序性:如果 zxid A 小于 zxid B,则 A 必然发生在 B 之前。这带来了以下数据一致性的保障:

  • 顺序一致性:来自同一客户端的更新按顺序应用。如果客户端将某个 znode 从状态 s 修改为 s',那么在该客户端观察到 s' 之后,其他任何客户端都不会看到该 znode 处于状态 s。

  • 原子性:修改操作要么全部成功,要么全部失败,不存在部分成功或失败的情况。

  • 单一系统视图:无论客户端连接的是 ensemble 中的哪一台服务器,看到的系统视图都是一致的。设想一种情况:客户端断开了与已失效服务器的连接,尝试连接到另一台尚未同步到最新状态的服务器。由于该服务器尚未追赶到失效服务器的状态,它将拒绝客户端连接,直到完成同步。

  • 持久性:一旦更新成功,数据就是持久化的。

  • 及时性:客户端对系统的视图在一定时间范围内(通常为几十秒)始终是最新的。要么系统变更能在该时限内被客户端感知,要么客户端能检测到服务不可用。

Zookeeper 不支持 跨客户端的同时一致视图。这意味着,如果客户端 X 将某个 znode 从 s 更新为 s',并通知客户端 Y 读取新值,客户端 Y 仍可能读取到旧值 s 而非 s'。为了让客户端 Y 读取到最新值,必须对该 znode 调用 sync 操作(Zookeeper API 的一部分)。Zookeeper 并不保证不同客户端始终拥有完全相同的数据视图,因为网络延迟等因素可能导致一个客户端在另一个客户端收到变更通知之前就完成了更新。

结论

Zookeeper:示例