kafka 在协调机制下实现无感切流 & 受控关机是一个复杂的流程, 且在 zookeeper 时代和 KRaft 时代下的处理逻辑迥异;
通过 ZK 和 KRaft 两种机制对该场景处理的差异, 我们也能体会到 KRaft 模式对于 kafka 革命般的意义;

Zookeeper 下的 broker 受控关机流程

假设一个 kafka 集群初始状态如下:

初始状态
初始状态

目标 Broker 向 Controller 请求关机

ControlledShutdownRequest
ControlledShutdownRequest

当在 Broker-0 机器上执行 kill kafka broker 进程的命令, 该机器上的 broker 进程响应命令, 会先向 Controller 发送 ControlledShutdownRequest, 随后进程阻塞, 等待 Controller 的回复;

Controller 处理 Broker 关机请求

当 Controller 接收到 ControlledShutdownRequest 后, 将会对目标 broker 上的每一个 topic 的每一个 partition 依次执行以下步骤:

  1. Controller 会检查下线的 broker 是否是目标 partition 的 leader, 如是, 则 Controller 需要为该 partition 重新选举新的 leader:
    • Controller 会从该 partition 的 ISR (In-Sync Replicas) 列表中选择一个新的 leader, 默认选择 ISR 列表中的第一个副本作为新的 leader;
    • 如果 ISR 列表为空, Controller 会根据配置决定是否允许从非同步副本 (Out-of-Sync Replicas) 中选举 leader (通过配置 unclean.leader.election.enable);
  2. 收缩 ISR, 将下线的 broker 上的 partition 副本从 ISR 中摘除:
    从:
    变为:
  3. 将最新的 ISR 和 leader 信息写入 zookeeper;
  4. Controller 以同步阻塞的方式依次向目标 partition 其他副本所在的 broker 发送 LeaderAndIsrRequest:
    • 收到请求的 broker 从请求中解析出 leader、ISR 等信息并存储到本地后, 响应 Controller;
    • Controller 收到上一个 broker 的成功响应后才会向下一个 broker 发送请求;

Broker 正式下线

当 Controller 处理完所有的 topic 的 partition 后, 会向最初发起请求关机的 Broker-0 回复 ControlledShutdownResponse, 此时 Broker-0 正式结束进程;

性能改善

  • 在 kafka 1.1.0 之前, 以上过程是单线程全程同步阻塞执行的, 耗时很长;
    • 分区在重新选举 leader 时, 会暂停对外提供读写服务, 严重时会导致生产故障;
  • 从 kafka 1.1.0 开始, kafka 将上述过程改为多线程异步非阻塞的方式执行, 显著提升了处理速度;

KRaft 下的 broker 受控关机流程

参考资料