Zookeeper 集群搭建
这篇记录在 Debian 上搭建 5 节点 Zookeeper 集群的完整过程,先梳理 Znode、ZAB 协议这些基础概念,再动手配置并做一次 Leader 宕机选举实验。
部署环境
操作系统 Debian 11.5.0
运行环境 OpenJDK-1.8.0_332 64-Bit Server VM
Zookeeper版本:3.8.0
官方介绍
Zookeeper官方文档地址(下载的zip压缩包中\docs目录也自带文档):ZooKeeper: Because Coordinating Distributed Systems is a Zoo (apache.org)
ZooKeeper 是一种用于分布式应用程序的分布式开源协调服务。它公开了一组简单的基元,分布式应用程序可以基于这些基元来实现更高级别的同步、配置维护以及组和命名服务。它被设计为易于编程,并使用类似文件系统目录树结构的数据模型。它以 Java 运行,并提供 Java 和 C 的绑定。
ZooKeeper 的实现非常重视高性能、高可用、严格有序的访问。高性能意味着它可以在大型分布式系统中使用;可靠性使其不会成为单点故障;严格的排序意味着可以在客户端上实现复杂的同步基元。

从官方的介绍中可以得出结论,Zookeeper主要作用于 meta 信息存储、配置信息同步,是一个高性能、高可用、没有单点故障的应用服务。
个人理解
中文翻译:动物园管理员。Apache 的项目大都用动物做 Logo 与命名,所以 Zookeeper 的 Logo 像一个铲屎官,还拿着一把铲子(doge)。Zookeeper本身架构设计得也很简单,容易上手。
Apache Zookeeper 也是 Apache Hadoop 整个架构中的一员,在Hadoop架构中担任统一配置管理、域名服务、重点数据存储等功能的中间件。一句话概括:Zookeeper = 文件系统 + 通知机制。
Zookeeper(以下简称ZK)本身存储数据的方式类似于Key-Value形式,只不过ZK中数据是以Znode方式存储,类似于Linux中的文件系统管理:Key都以文件路径的方式表达,有多级目录。这和Redis中的Key很像,只不过Redis中的Key习惯用:符号分级,ZK完全使用Linux中的/符号分级。ZK的数据存储在内存中,并持久化到硬盘,在内存中维护Znode的树状数据结构(文件系统)。
数据结构
ZK的Value没有提供丰富的数据结构(不像Redis提供了list、set、hashmap、zset、string等多种结构),ZK的Value只有String类型。ZK的定位本来就不是数据库,它设计出来只是为了存储架构中的关键配置信息,并提供通知与同步能力,所以每个Znode最大存储数据为1M。
Znode类型
1) 持久节点
持久节点创建后,只要不人为执行Delete命令删除,则一直存在。
2) 临时节点
临时节点依赖连接客户端的会话:创建后,如果客户端一直保持连接,则临时节点一直存在;如果客户端连接断开,则清除临时节点。有没有感觉到它的作用?特别适合做注册中心的功能——Dubbo启动则连接,宕机则删除Znode节点,并通知其他客户端。
3) 顺序节点
创建顺序节点时会自动在节点路径后面追加10位数字作为计数器。
例如我创建 /node 顺序节点,则 file path 是:/node0000000001。
下次再次创建 /node 节点,会在计数器上 +1 并创建新的Znode节点(旧的/node0000000001不会删除,仍然保留),此时 file path 是:/node0000000002。
但当计数器的大小超过2147483647时,将会发生溢出。
4) 临时顺序节点
临时节点的特性 + 顺序节点的特性。
ZK特性
- 顺序一致性 - 来自客户端的更新将按其发送顺序应用。
- 原子性 - 更新成功或失败。无部分结果。
- 单个系统映像 - (全局数据一致)集群中每个Server都保存着相同的数据副本,无论Client连接到哪个Server,数据都是一致的【虽然理论上是一致的,但是在数据同步过程中还是会出现某些时刻不一致,不过可以通过sync命令解决】。
- 可靠性 - 应用更新后,它将从该时间开始一直存在,直到客户端覆盖更新。
- 及时性 - 保证系统的客户端视图在特定时间范围内是最新的。
其中原子性是通过ZAB协议进行保证的,ZAB协议的全称是 Zookeeper Atomic Broadcast(Zookeeper原子广播)。
ZAB 协议
ZAB有两种模式:一种是消息广播模式,另一种是崩溃恢复模式。
消息广播模式
在 Zookeeper 集群中数据副本的传递策略采用消息广播模式。Zookeeper 中的数据副本同步方式与2PC相似但并不相同:2PC要求协调者必须等待所有参与者全部反馈ACK确认消息后,再发送 commit 消息,要求所有参与者要么全成功要么全失败,因此2PC会产生严重的阻塞问题。
而 Zookeeper 中 Leader 等待 Follower 的 ACK 反馈是指:只要半数以上的 Follower 成功反馈即可,不需要收到全部的 Follower 反馈,这样可以减少等待时间。
崩溃恢复模式
一旦 Leader 服务器出现崩溃,或者由于网络原因导致 Leader 服务器失去了与过半 Follower 的联系,就会进入崩溃恢复模式,重新选举出新的 Leader。
集群搭建(5节点)
ZK的集群最少需要3个节点,并且节点个数需要是奇数,可以容忍宕机的数量是节点数/2:3台可以容忍1台宕机继续提供服务,5台可以容忍2台宕机继续提供服务,遵循的是过半节点正常,整个集群则可以继续对外提供服务。
ZK集群中的三种角色
Leader(领导者):整个集群中只有一个节点可以选举为Leader,并且只有Leader可以进行写操作。(这样的设计注定ZK的写入性能会成为瓶颈,不过大部分都是内存操作,且每个Znode节点数据量很小,仍然可以保持较高的写入性能。)
Follower(跟随者):Follower 在集群中可以有多个,要和Leader保持心跳连接,该节点只能读不能写,在Leader节点宕机时需要参与新的Leader选举投票。
Observer(观察者):Observer节点在整个集群中是最边缘的存在,只能读,不能参与Leader选举。为什么需要Observer这样的角色呢?因为ZK集群的写入操作需要半数以上的Follower同步确认才能写入成功,当ZK集群中节点越多时,写入性能就越低。为了在提升ZK集群读能力的同时不影响写入性能,才设计了Observer这样的节点。Observer只负责同步Leader中的数据,并提供读操作。

根据官方给出的ZK集群数量性能图可以看到,随着节点数量增加,ZK集群处理的请求数也有上升。但个人觉得准确点说应该是读能力上升,写能力会下降:毕竟节点越多,Leader写入数据时需要通过ZAB协议同步其他Follower节点确认,只有半数Follower节点同步数据成功才算写入成功,节点数量增加必然导致写能力下降。这种设计也说明ZK不适合大量写入的场景,官方给出的读写比例最好为7:3或8:2。
配置 zoo.cfg(教程跳过了下载和解压)
解压zip压缩包后,进入conf文件夹下,将 zoo_sample.cfg 重命名为 zoo.cfg,或 copy 一份出来命名为 zoo.cfg。
修改 zoo.cfg 中的部分默认配置,最重要的是修改 dataDir 文件夹路径。ZK默认存放在tmp路径下,但Linux系统会不定时清空该临时目录,所以我们需要改到其他文件夹路径下。

修改完成之后记得保存。我设置的地址为 /opt/zookeeper/data,后续几个节点都要设置。
创建 myid 文件
在修改后的 dataDir 路径文件夹下创建 myid 文件,并在文件中写入当前节点的唯一标识ID。
后续几个节点也都要设置自身节点对应的标识ID,不能重复。
配置集群节点列表
在每个节点的 zoo.cfg 中加入 server 节点的地址:

server.1 中的 1 代表着myid中的标识,后面的值可以写节点ip也可以写hostname,其中2888端口用于同步数据,3888端口用于选举投票。
启动所有节点
如果只启动了半数以下节点,则集群不会提供任何服务:
此时抛出异常无法连接ZK,所以需要把所有节点全部启动。
验证集群状态
所有节点都成功启动后:
可以通过 zkServer.sh 的 status 命令查看当前节点角色以及启动状态。
通过 zkCli.sh 连接集群,并执行命令测试是否正常:

再到其他节点进行命令测试:

一切正常,至此最简单的ZK集群已经搭建成功。本次搭建基于最简单的流程,后续可以通过修改配置继续调优整个集群细节,并添加ssl通讯与密码加强整个集群的安全性。
风险实验
我们把测试力度继续加深,停掉其中的 Leader 节点,查看集群是否会自动选举出新的 Leader 节点。
找到 Leader 节点后关闭该节点服务。

当前 Leader 节点为 debian4 服务器,我们立即执行 zkServer.sh stop 命令关闭其 ZK 服务。

通过 zkServer.sh status 命令查看,debian5 服务器已被选举为新的 Leader 节点,表示集群选举一切正常。

官方配置参数:动物园管理员:因为协调分布式系统是一个动物园 (apache.org)
小结
这次搭建走的是最基础的流程:改 dataDir、写 myid、在 zoo.cfg 中登记所有 server 节点,然后逐台启动。集群能否对外服务的核心规则只有一条——过半节点存活。风险实验也验证了这一点:停掉 Leader 后,剩余节点很快选举出新的 Leader,服务不中断。理解了 Znode 模型和 ZAB 协议的过半确认机制,这些配置项背后的设计意图就都说得通了。生产环境使用前,还应补上 ssl 与鉴权配置。
评论 / COMMENTS