乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • ZooKeeper 学习路径
  • 第1章 分布式协调与ZooKeeper概述

    • ZooKeeper 概述
  • 第2章 单机与集群搭建

    • 配置参数详解
    • 集群搭建
  • 第3章 数据模型与ZNode

    • ZNode 详解
    • 节点类型对比
    • 顺序节点
    • ACL 权限控制
  • 第4章 会话与Watcher机制

    • 会话机制
    • Watcher 机制
  • 第5章 ZAB协议与一致性保证

    • ZAB 协议
    • 一致性保证
    • 数据同步
  • 第6章 Leader选举

    • Leader 选举
  • 第7章 典型应用:分布式锁

    • 分布式锁
  • 第8章 典型应用:配置中心与命名服务

    • 配置中心
    • 命名服务
  • 第9章 客户端编程基础(Java原生API)

    • Java 原生 API 编程
  • 第10章 运维与监控

    • 四字命令
    • 监控体系
  • 第11章 面试考点与设计思想

    • 设计思想
    • 面试考点汇编

本章定位:掌握 ZooKeeper 服务端的部署与配置,是后续所有内容的基础。集群部署是 ZooKeeper 高可用的前提,理解其拓扑和节点角色至关重要。

定义与作用

ZooKeeper 集群(Ensemble)由一组 Server 组成,通过 ZooKeeper Atomic Broadcast(ZAB)协议在节点间同步状态。集群部署的核心目标是高可用——当部分节点故障时,只要多数节点存活,服务就不会中断。

ZooKeeper 提供两种部署模式:

模式节点数适用场景
单机模式1本地开发、学习测试
集群模式≥3(奇数)生产环境

核心原理

集群拓扑

ZooKeeper 集群中的节点有三种角色:

  • Leader:所有写请求的唯一入口,负责发起 Proposal 并协调投票
  • Follower:参与投票,处理读请求,将写请求转发给 Leader
  • Observer:不参与投票,仅处理读请求,用于横向扩展读能力

集群中只有 Leader 处理写请求,Follower 和 Observer 均可处理读请求。Observer 不参与投票,因此增加 Observer 不会降低写性能。

配置核心参数

在 conf/zoo.cfg 中定义集群成员:

server.1=host1:2888:3888
server.2=host2:2888:3888
server.3=host3:2888:3888
  • 第一个端口(2888):Follower 连接 Leader 的端口
  • 第二个端口(3888):Leader 选举端口
  • 每个节点需要在 dataDir 下创建 myid 文件,内容为该节点的数字 ID

完整示例

示例一:单机模式部署

场景说明:本地开发环境搭建一个 ZooKeeper 服务。

操作前状态:已下载并解压 ZooKeeper 3.7+ 安装包。

步骤 1:创建配置文件

cd apache-zookeeper-3.7.0-bin
cp conf/zoo_sample.cfg conf/zoo.cfg

步骤 2:编辑 zoo.cfg

tickTime=2000
dataDir=/tmp/zookeeper
clientPort=2181

步骤 3:启动服务

bin/zkServer.sh start

执行结果:

ZooKeeper JMX enabled by default
Using config: /path/to/apache-zookeeper-3.7.0-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

步骤 4:验证服务

bin/zkCli.sh -server 127.0.0.1:2181

执行结果:

Connecting to 127.0.0.1:2181
Welcome to ZooKeeper!
JLine support is enabled
[zkshell: 0]

操作后状态:ZooKeeper 单机模式运行在 2181 端口,可执行 ls、create、get 等命令。

示例二:三节点集群部署(单机模拟)

场景说明:在单台机器上启动 3 个 ZooKeeper 实例,模拟生产集群的部署流程。

操作前状态:已有 ZooKeeper 安装包,需配置 3 套独立的环境。

步骤 1:创建 3 份配置与数据目录

mkdir -p /tmp/zk-data/{1,2,3}
echo 1 > /tmp/zk-data/1/myid
echo 2 > /tmp/zk-data/2/myid
echo 3 > /tmp/zk-data/3/myid

步骤 2:编写 zoo-1.cfg(zoo-2.cfg、zoo-3.cfg 类似,分别修改 dataDir 和 clientPort)

# zoo-1.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zk-data/1
clientPort=2181
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
# zoo-2.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zk-data/2
clientPort=2182
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
# zoo-3.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zk-data/3
clientPort=2183
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890

步骤 3:依次启动 3 个实例

bin/zkServer.sh start conf/zoo-1.cfg
bin/zkServer.sh start conf/zoo-2.cfg
bin/zkServer.sh start conf/zoo-3.cfg

步骤 4:查看各节点状态

bin/zkServer.sh status conf/zoo-1.cfg
# Mode: follower

bin/zkServer.sh status conf/zoo-2.cfg
# Mode: leader

bin/zkServer.sh status conf/zoo-3.cfg
# Mode: follower

步骤 5:验证数据同步

在 Leader(2182)上写入数据:

bin/zkCli.sh -server 127.0.0.1:2182
[zkshell: 0] create /cluster_test "hello cluster"
Created /cluster_test

在 Follower(2181)上读取:

bin/zkCli.sh -server 127.0.0.1:2181
[zkshell: 0] get /cluster_test
hello cluster

操作后状态:

节点端口角色myid
Server 12181Follower1
Server 22182Leader2
Server 32183Follower3

集群正常运行,数据在 3 个节点间同步。

示例三:添加 Observer 节点

场景说明:集群读压力增大,需要横向扩展但不影响写性能。

配置 Observer(zoo-obs.cfg):

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zk-data/obs
clientPort=2184
peerType=observer
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
server.4=127.0.0.1:2891:3891:observer

操作前后对比:

维度操作前(3 节点)操作后(3+1 Observer)
参与投票节点33(不变)
读处理能力3 个节点4 个节点
写性能受 Leader/Follower 限制不变

动态重配置(Dynamic Reconfiguration)

ZooKeeper 3.5.0 引入了动态重配置机制,支持在不停止集群服务的情况下增删节点。这对于在线扩容、故障节点替换、机房迁移等生产运维场景至关重要。

前置条件

  • ZooKeeper 3.5.0+ 版本
  • zoo.cfg 中需包含 dynamicConfigFile 路径,或直接在 zoo.cfg 中声明 server 行
  • reconfig 操作需要超级用户权限(或关闭 skipACL)

查看当前配置

# 通过 zkCli 连接到集群
bin/zkCli.sh -server 127.0.0.1:2182

# 查看当前集群成员
[zkshell: 0] reconfig -members

返回当前集群的 server 列表:

server.1=127.0.0.1:2888:3888:participant;0.0.0.0:2181
server.2=127.0.0.1:2889:3889:participant;0.0.0.0:2182
server.3=127.0.0.1:2890:3890:participant;0.0.0.0:2183

集群扩容流程

添加节点

命令格式:

reconfig -add server.<id>=<host>:<port1>:<port2>:<role>;<clientPort>

示例:向 3 节点集群添加第 4 个节点(参与投票):

# 1. 先以 non-voting 角色加入,同步数据。
#    语法:role=observer 或 role=participant
#    participant 表示参与投票,observer 表示只读节点
[zkshell: 0] reconfig -add \
  server.4=192.168.1.14:2891:3891:participant;192.168.1.14:2184

# 输出:
# Committed new configuration:
# server.1=127.0.0.1:2888:3888:participant;0.0.0.0:2181
# server.2=127.0.0.1:2889:3889:participant;0.0.0.0:2182
# server.3=127.0.0.1:2890:3890:participant;0.0.0.0:2183
# server.4=192.168.1.14:2891:3891:participant;192.168.1.14:2184

操作前后对比:

维度操作前操作后
投票节点34
容错能力容忍 1 台故障仍容忍 1 台故障(4 节点多数 = 3)
集群服务状态持续运行持续运行(无停服)
dynamicConfigFile3 条 server4 条 server(自动更新)

移除节点

# 移除 server.4
[zkshell: 0] reconfig -remove 4

# 输出:
# Committed new configuration:
# server.1=127.0.0.1:2888:3888:participant;0.0.0.0:2181
# server.2=127.0.0.1:2889:3889:participant;0.0.0.0:2182
# server.3=127.0.0.1:2890:3890:participant;0.0.0.0:2183

移除节点后,被移除节点检测到自身被移出 quorum 会自动关闭服务——无需手动停进程。

动态配置文件(dynamicConfigFile)

当使用动态重配置后,集群成员信息不再仅存在于 zoo.cfg 的 server.X=... 行中,而是持久化到 dynamicConfigFile(默认路径为 dataDir/zoo.cfg.dynamic):

# zoo.cfg 中指定
dynamicConfigFile=/var/lib/zookeeper/zoo.cfg.dynamic

dynamicConfigFile 的内容是所有集群节点自动维护的当前 quorum 配置,每次 reconfig 操作都会更新此文件。重启节点时会优先读取 dynamicConfigFile 而非静态 zoo.cfg 中的 server 行。

易错场景

1. reconfig 后忘记更新静态 zoo.cfg

dynamicConfigFile 自动更新,但 zoo.cfg 中的 server.X=... 行不会自动更新。如果运维人员手动重启节点时,zoo.cfg 中的旧 server 行可能导致节点加入失败或形成脑裂。最佳实践:执行 reconfig 后同步更新 zoo.cfg 中 server 行(注释或对齐)。

2. 新节点数据同步未完成就提升为 participant

新加入的 observer 节点需要从 Leader 同步所有事务日志和快照。如果数据尚未追平就执行 reconfig -add ...:participant,该节点在投票时没有完整状态,可能导致 Proposal 提交延迟甚至失败。等待 srvr 或 stat 命令确认 zxid 追平后再提升。

面试高频题

Q:集群如何不停服扩容?

A:使用 ZooKeeper 3.5.0+ 的 reconfig 命令。步骤:① 新节点以 observer(non-voting)角色加入,从 Leader 同步数据;② 数据追平后通过 reconfig -add ...:participant 提升为投票节点;③ 集群在扩容全程保持服务,无需任何重启。

Q:reconfig 与手动修改 zoo.cfg 再滚动重启的区别?

A:三个核心差异:① reconfig 不中断集群服务,滚动重启至少需要逐台停服;② reconfig 是原子操作——Leader 发起 Proposal 并经多数 Follower 确认后提交,配置变更有严格的一致性保证;③ reconfig 自动更新 dynamicConfigFile,避免了多节点 zoo.cfg 配置不一致的风险。

易错场景与面试考点

易错场景

1. myid 与 server.X 不匹配

错误现象:启动时日志报 server.X 与 myid 不一致。

原因:dataDir/myid 文件内容(如 1)必须与配置中 server.1 的序号严格一致。

解决:检查 myid 文件内容,尤其是前后是否有空格或换行。

2. 两节点集群无法正常工作

错误现象:一个节点宕机后集群不可用。

原因:ZooKeeper 需要过半数(majority)存活。2 节点集群中任意一个节点宕机即失去多数,集群停止服务。2 节点比单节点更不可靠——因为增加了故障点却没有提高容错能力。

3. 端口冲突

错误现象:启动失败,日志显示端口被占用。

原因:单机模拟集群时 2888/3888 端口被其他进程占用,或不同实例的端口配置重复。

解决:使用 netstat -an | grep 2888 检查端口占用情况。

面试高频题

Q:为什么推荐奇数个节点?

A:ZooKeeper 使用多数派机制。在容错能力相同时,奇数节点更经济:

  • 3 节点 → 容忍 1 个节点故障
  • 4 节点 → 仍只能容忍 1 个节点故障(需 3 个存活形成多数)
  • 5 节点 → 容忍 2 个节点故障

4 节点比 3 节点多用了资源却未提升容错能力,因此推荐奇数。

Q:Observer 与 Follower 的核心区别?

A:Observer 不参与投票(不响应 Leader 的 Proposal ACK),因此:

  • 增加 Observer 不会降低写入延迟(写入仍需多数 Follower 确认)
  • Observer 只接收 INFORM 消息,不参与选举
  • Observer 适合跨数据中心部署,降低跨机房带宽消耗

Q:Leader 宕机后集群如何恢复?

A:Follower 检测到 Leader 心跳超时(syncLimit * tickTime)后进入选举,通过 FastLeaderElection 选出新 Leader,新 Leader 与 Follower 同步状态后恢复服务。

小结

要点说明
集群节点数生产环境 ≥ 3,推荐奇数
myid 文件必须与 server.X 序号一致
选举端口3888 默认,Leader 选举专用
通信端口2888 默认,Follower→Leader 连接
Observer不投票,仅处理读请求
动态重配置3.5.0+ reconfig 命令,不停服增删节点
单机模拟注意端口和数据目录唯一

集群部署是 ZooKeeper 使用的前提。下一节将深入配置参数详解,理解每个参数对集群行为的精确影响。

上一页
配置参数详解