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

    • 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章 面试考点与设计思想

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

本章定位:Leader 选举是 ZooKeeper 高可用的核心保障。理解 FastLeaderElection 的投票规则和选举流程,才能诊断集群不可用的根因。

定义与作用

当 ZooKeeper 集群启动或 Leader 失效时,所有参与节点通过**FastLeaderElection(FLE)**算法选出新的 Leader。Leader 是集群中唯一处理写请求的节点,选举的快速和正确直接决定集群的可用性。

选举解决的核心问题:

问题选举如何解决
避免脑裂(Split Brain)Quorum 机制:必须过半数节点同意
选出最优 LeaderZXID 最大者优先(拥有最新数据)
处理并发选举两阶段投票 + 选举轮次(epoch)
快速收敛直接通信(P2P),无需协调者

核心原理

选举投票交互

投票规则:比较 ZXID(越大越新)→ myid(越大越优先)。Server 3 因 ZXID=101 最大而当选 Leader。

投票比较规则

节点状态转换

状态含义何时进入
LOOKING正在寻找 Leader启动时、Leader 失效时
LEADING当前是 Leader获得多数票后
FOLLOWING当前是 Follower确认 Leader 后
OBSERVING当前是 Observer确认 Leader 后(不参与投票)

完整示例

示例一:观察 Leader 选举日志

场景说明:启动 3 节点集群,观察选举日志输出。

# 启动 Server 1
bin/zkServer.sh start conf/zoo-1.cfg

# 日志关键输出:
# LOOKING - 进入选举
# Notification: myid=1, zxid=0x0, state=LOOKING
# Notification: myid=1, zxid=0x0, state=LOOKING(给自己投票)

# 启动 Server 2
bin/zkServer.sh start conf/zoo-2.cfg
# LOOKING - 进入选举
# Notification: myid=2, zxid=0x0, state=LOOKING
# 收到 Server 1 的投票: myid=1, zxid=0x0
# 比较:myid 2 > 1 → 维持 vote=2
# Server 1 收到 Server 2 投票:myid 2 > 1 → 更新 vote=2

# 启动 Server 3
bin/zkServer.sh start conf/zoo-3.cfg
# Server 2 收到第三票 → 确认 LEADING
# LEADING - LEADER ELECTION TOOK - 200 MS
# Server 1、3 变为 FOLLOWING

操作前后对比:

阶段Server 1 (myid=1)Server 2 (myid=2)Server 3 (myid=3)
启动 S1LOOKING(投自己)——
启动 S2改投 myid=2LOOKING(投自己)—
启动 S3维持投 myid=2LEADINGFOLLOWING

示例二:Leader 宕机后的重新选举

场景说明:模拟 Leader 宕机,观察新 Leader 的选举过程。

# 查看当前状态
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

# 向 Leader 写入数据
zkCli.sh -server 127.0.0.1:2182
[zkshell: 0] create /election-test/node1 "data"
Created /election-test/node1
[zkshell: 1] create /election-test/node2 "data"
Created /election-test/node2
# 停掉 Leader (Server 2)
bin/zkServer.sh stop conf/zoo-2.cfg

# 查看状态 —— Server 1 成为新 Leader
bin/zkServer.sh status conf/zoo-1.cfg  # Mode: leader

# Server 1 的日志:
# Notification: myid=1, zxid=0x100000003, state=LOOKING
# Notification: myid=3, zxid=0x100000003, state=LOOKING
# 比较:zxid 相同,myid 1 < 3?

Server 1 和 Server 3 的 zxid 在大多数情况下相同(因为 Leader 宕机前已同步),此时 myid 较大的 Server 3 获胜。但时序因素可能使结果不绝对。

操作前后对比:

时间点LeaderFollower说明
宕机前Server 2Server 1, 3正常运行
宕机后Server 1 或 3另一个仅需 ~200ms 选举

示例三:Java API 监听 Leader 选举事件

场景说明:通过 Watcher 感知集群 Leader 变化。

public class LeaderElectionWatcher implements Watcher {
    @Override
    public void process(WatchedEvent event) {
        if (event.getState() ==
                Event.KeeperState.Disconnected) {
            System.out.println("Disconnected from Server");
        } else if (event.getState() ==
                Event.KeeperState.SyncConnected) {
            System.out.println("Reconnected to Server");
            // 此时 Leader 可能已变更
        }
    }
}

// 客户端自动重连到新 Leader
ZooKeeper zk = new ZooKeeper(
    "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",
    15000,
    new LeaderElectionWatcher()
);

执行输出(Leader 宕机期间):

Disconnected from Server
... <~200ms 选举 + 同步 ...
Reconnected to Server

操作前后对比:

事件客户端状态说明
Leader 正常SyncConnected正常读写
Leader 宕机Disconnected连接断开
新 Leader 就绪SyncConnected自动重连,Session 未过期

易错场景与面试考点

易错场景

1. 两节点集群的选举陷阱

2 节点集群:一个节点宕机后,剩下 1 个节点无法达到 Quorum(需要过半数,即 ≥2),集群停止服务。2 节点集群的可用性不如 3 节点。

2. 选举期间的写请求

选举期间客户端写请求会失败(ConnectionLossException 或 SessionExpiredException)。客户端应实现重试逻辑(指数退避),而不能假设写操作一定成功。

3. Observer 的误区

Observer 不参与投票,Leader 选举时 Observer 被忽略。如果集群包含 2 个 Follower + 3 个 Observer,宕机 1 个 Follower 仍然只剩 1 票,达不到 Quorum。

面试高频题

Q:FastLeaderElection 为什么叫 Fast?

A:相对于原始的 LeaderElection 算法(基于 Zab 协议的简化版),FLE 有两个加速:

  1. P2P 直接通信:节点直接向所有其他节点发送投票,无需选出一个协调者(Coordinator)
  2. 快速收敛:收到更高优先级的投票后立即转投,减少选举轮次

Q:选举过程中如何避免脑裂?

A:

  1. Quorum 机制:必须过半数节点选举同一 Leader
  2. epoch 机制:每次选举 epoch 递增,旧 epoch 的投票自动失效
  3. 过半确认:Leader 激活前需要过半数 Follower 确认(FLE 阶段结束后的同步阶段)

Q:如果两个节点同时认为自己应该是 Leader 怎么办?

A:不会发生。FLE 算法中每个节点根据相同的规则(先比 ZXID,再比 myid)做决策,最终所有节点会收敛到同一个最优节点。最坏情况是多轮投票,但结果唯一。

Q:ZXID 相同的情况下谁当选?

A:myid 大者当选。ZXID 相同说明所有节点拥有相同数据,此时 myid 作为仲裁(Tiebreaker),保证选举的确定性。

小结

要点说明
投票规则ZXID 最大者优先,相同则 myid 大者优先
选举算法FastLeaderElection(P2P 直接通信)
状态转换LOOKING → LEADING / FOLLOWING / OBSERVING
Quorum必须过半数节点(ceil(N/2) + 1)
Observer不参与选举,不计入 Quorum
收敛时间通常在 200ms 以内

Leader 选举保障了集群的自动故障转移。下一章进入 ZooKeeper 的最经典应用——分布式锁。