Kafka 有几种选举过程?
结论:Kafka 里有三种性质完全不同的"选举"——Controller 选举(集群管理节点,ZK 模式下靠抢占临时节点、KRaft 模式下靠 Raft)、分区 Leader 选举(Controller 从 ISR 里挑一个副本)、消费组 Leader 选举(组协调器挑一个消费者负责分配方案)。面试里问"几种选举",要能分别说清触发条件、参与者与算法。
一、三种选举对比
| 选举 | 触发条件 | 参与者 | 算法 | 影响范围 |
|---|---|---|---|---|
| Controller 选举 | Controller 所在 Broker 宕机 | 所有 Broker | ZK:抢占 /controller 临时节点;KRaft:Raft 多数派 | 整个集群的元数据管理暂停 |
| 分区 Leader 选举 | Leader 副本所在 Broker 下线,或副本被踢出 ISR | ISR 内副本(可配置含非 ISR) | Controller 从 ISR 列表取第一个可用副本 | 仅该分区短暂不可读写 |
| 消费组 Leader 选举 | 组内 Leader 消费者下线或新成员加入 | 组内所有消费者 | 组协调器指定第一个加入的成员 | 触发一次重平衡,全组暂停消费 |
二、Controller 选举
ZK 模式:
Broker 启动 ──> 尝试创建 /controller 临时节点
├─ 创建成功 → 成为 Controller,并写入自己的 brokerId
└─ 创建失败 → 监听该节点,等待旧 Controller 会话过期后重新抢占
KRaft 模式:
Controller 节点组成 Raft 组(controller.quorum.voters)
└─ 多数派选出一个 Active Controller,其余为 Follower
└─ 元数据变更写入 __cluster_metadata 日志,按 Raft 复制
ZK 模式靠临时节点(Ephemeral Node)+ 会话超时避免脑裂,但切换要等会话过期,通常是秒级到十几秒;KRaft 用 Raft 的 term 与多数派,切换在亚秒级,且不再依赖外部组件。
三、分区 Leader 选举
Controller 监听 Broker 变化
│
├─ Broker-2 下线 → 它上面的 Leader 分区 P0、P3 需要重新选主
│
├─ 读取每个分区的 ISR 列表(如 P0: [1,2,3])
│
├─ 从 ISR 中选一个存活副本(通常是列表第一个)作为新 Leader
│
├─ 更新元数据并广播给所有 Broker
│
└─ 若 ISR 为空 → 检查 unclean.leader.election.enable
├─ false(推荐):分区保持不可用,等原 Leader 恢复
└─ true:从非 ISR 副本中选主,可用性恢复但会丢数据
unclean.leader.election.enable=true 是"用数据换可用"的开关:选出的副本可能缺一段消息,且新 Leader 一旦写入,旧 Leader 回来后会截断日志(Log Truncation),那段消息就永久丢了。
四、消费组 Leader 选举
消费组的 Leader 并不"管理"其他消费者,它只负责计算分区分配方案:
组协调器(GroupCoordinator) Consumer Leader 其他成员
│ 收到 JoinGroup │ │
├─────────────────────────────────>│ │
│ 指定第一个加入者为 Leader │ │
│ │ 计算分配:c1→P0,P1 │
│ │ c2→P2,P3 │
│<───────── SyncGroup(分配方案) ─────┤ │
├──────────────────────────────────┼────────────────────>│
│ │ │
└─ 各成员按方案开始消费 ────────────────────────────────────>
分配策略(Range、RoundRobin、Sticky、CooperativeSticky)会影响重平衡的代价,CooperativeSticky 是增量式重平衡,可以避免全量停止消费。
五、观察与配置
# 查看分区 Leader/ISR 状态
kafka-topics.sh --bootstrap-server 10.0.0.31:9092 --describe --topic order
# KRaft 下查看 Controller 状态与 quorum
kafka-metadata-quorum.sh --bootstrap-server 10.0.0.31:9092 describe --status
# 触发一次 Preferred Leader 选举(把 Leader 迁回首选副本)
kafka-leader-election.sh --bootstrap-server 10.0.0.31:9092 \
--election-type preferred --all-topic-partitions
六、常见追问
- 为什么优先选 ISR 里的副本? ISR 是与 Leader 同步的副本,选它不会丢已提交的消息;非 ISR 副本落后,选它就意味着丢数据。
- Controller 选举期间集群还能读写吗? 已有分区的读写不受影响,但不能创建 Topic、不能选举新 Leader,故障分区的恢复会被推迟。
- 消费者 Leader 挂了会怎样? 组协调器重新选一个 Leader 并触发重平衡,整个组在重平衡期间暂停消费,因此要尽量避免频繁成员变更。
- KRaft 里还有 Controller 选举吗? 有,但变成 Raft 组内的选主,不再是抢 ZK 节点;Broker 与 Controller 可以合设,也可以分离部署。
小结
- 三种选举分别对应:集群管理节点、分区主副本、消费组分配者。
- Controller 选举影响元数据操作,分区选举只影响单个分区,消费组选举影响整组消费。
- 分区选举优先 ISR,
unclean开关决定可用性与数据安全的取舍。 - KRaft 用 Raft 取代 ZK 抢占,切换更快、依赖更少,是当前主流部署方式。