Kafka 从 Zookeeper 迁移到 KRaft
摘要
-
本文介绍 如何将 Kafka 集群从 Zookeeper 模式迁移到 KRaft 模式
-
本文使用的 Kafka 版本为 3.9.1。Kafka 团队宣布 3.9 会是 最后一个还带有被弃用的 ZooKeeper 模式 的主要版本。以后版本(如 4.0)将完全弃用 ZooKeeper。
从 Zookeeper 模式迁移到 KRaft 模式(平滑迁移)
-
Kafka 官方在 3.4+ 引入了完整的 Zookeeper → KRaft 平滑迁移机制,称为
ZK to KRaft (ZkMigration)
。 -
迁移背景与前提
项目 | 说明 |
---|---|
支持版本 | Kafka 3.4.0+(建议至少使用 3.6.x ,目前最新版为 3.9.x) |
迁移目的 | 摆脱 ZooKeeper,完全切换为 KRaft 自管理模式 |
迁移模式 | 在线迁移(无停机或最小停机) |
最终目标 | Kafka 的控制器与元数据完全由 KRaft 管理,不再依赖 ZooKeeper。 |
-
整体迁移流程概览
阶段 | 控制器类型 | Broker 模式 | ZooKeeper 角色 | KRaft 角色 | 特征说明 |
---|---|---|---|---|---|
初始阶段 | ZooKeeper 控制器 | 全部为 ZK 模式 | 管理所有元数据 | 尚未启用 | 所有 Broker 都运行在 ZK 模式下,由 ZK 控制器管理集群。 |
初始元数据加载阶段 | KRaft 控制器开始加载 | 部分(或全部)仍为 ZK 模式 | 提供元数据源 | 从 ZK 加载元数据 | KRaft 法定节点(controller.quorum.voters)从 ZK 中读取并同步当前集群元数据。 |
混合阶段 | KRaft 控制器 | 部分 ZK 模式,部分 KRaft 模式 | 保留只读元数据 | 管理并更新元数据 | KRaft 控制器成为主控,ZK 仍存在但只提供读取,Broker 可处于不同模式(混合状态)。 |
双写阶段 | KRaft 控制器 | 全部为 KRaft 模式 | 接收 KRaft 同步写入 | 管理元数据并写入 ZK | 所有 Broker 都运行在 KRaft 模式,控制器将元数据同时写入 ZK 和 KRaft 日志。 |
迁移完成阶段 | KRaft 控制器 | 全部为 KRaft 模式 | 不再使用 | 独立运行 | 停止向 ZK 写入元数据,ZK 可安全关闭,Kafka 完全运行在无 Zookeeper 的 KRaft 模式下。 |
开始迁移
-
这里以前文 Kafka 的安装:基于 Zookeeper 中的3个节点的集群为例。
启动一个 Controller 节点
-
在任意一个节点上启动一个 Controller 节点,这里为 worker1
-
启动前需要先获取当前 Kafka 集群的 Cluster ID
1 | $ zookeeper-shell.sh localhost:2181 get /cluster/id |
-
准备好 Controller 节点的配置文件,这里可以用
config/kraft/controller.properties
为模板进行修改
1 | # 配置当前节点的角色,这里只能是controller |
-
启动 Controller 节点
千万不要在已有 broker 的数据目录(包含消息数据的 log.dirs)上运行 kafka-storage.sh format ,那会把原有数据结构重置或踩坏。
必须明确:格式化只针对 新 controller 的 metadata 目录(且该目录必须为空)。
1 | # 格式化元数据目录,log.dirs 参数指定元数据存放目录,首次运行前必须为空目录 |
模式 | format 命令 | quorum 状态 | 是否从 ZK 加载 |
---|---|---|---|
迁移阶段(standalone) | --standalone |
无(单节点) | ✅ 是 |
正式 KRaft 模式 | 无 --standalone |
✅ 多节点 | ❌ 否(独立运行) |
将原先的三个节点作为 Broker 节点重新启动
-
修改原先的配置文件
server.properties
,只需要修改如下内容即可
1 | # 在最后加入 CONTROLLER:PLAINTEXT |
-
分别重新启动三个节点
1 | # 关闭 kafka |
-
当三个节点都以必要的配置重新启动后,迁移将自动开始。迁移完成后,可以在 Controller(worker1)节点 上看到类似如下日志:
1 | # ✅ 意味:从 ZooKeeper 到 KRaft 的初始元数据迁移已成功,共写入 62 条记录,当前 KRaft metadata offset 为 3179。这是迁移成功的明确证据。 |
-
上面的日志总体上表明,元数据迁移已成功完成并且控制器进入了双写(DUAL_WRITE)阶段。
将三个Broker节点的配置修改为 KRaft 模式的 broker 节点
-
修改三个节点的配置文件
server.properties
1 | # 添加process.roles=broker |
-
分别重新启动三个节点
1 | # 关闭 kafka |
将 Controller 节点的配置修改为 KRaft 模式的 controller 节点
-
修改 controller 节点的配置文件
controller.properties
1 | ## 去掉去下内容 |
-
重启启动 controller 节点
1 | # 关闭后重新启动 |
-
此时你可以关闭 zookeeper 集群了,新的 kafka 集群将不再使用 ZooKeeper,也无法在恢复到 ZooKeeper 模式。
加入新的 Controller 节点
-
Controller 尽量保持 奇数个节点。
-
之前已经在
worker1
节点上启动了 controller ,现在worker2
和worker3
上也来启动 controller 节点,并将它们加入到 kafka 集群中。 -
在开始配置前,先将上面的 controller 节点 和 三个 broker 节点 的如下配置进行修改,并重启启动。
1 | # 将 controller.quorum.bootstrap.servers 替换为 controller.quorum.voters |
配置项 | 作用 | 适用阶段 | 是否必需 | 说明 |
---|---|---|---|---|
controller.quorum.voters |
定义 正式的 KRaft 控制器投票成员列表(voter set) | 集群正常运行时 | ✅ 是 | 所有节点必须配置相同的值 |
controller.quorum.bootstrap.servers |
定义 迁移阶段或初始化阶段的控制器连接地址(bootstrap controller endpoint) | ZK → KRaft 迁移阶段 或 KRaft 集群初次启动 | ⚙️ 可选(仅特定阶段) | 用于在 controller quorum 尚未形成时的临时发现 |
-
参考 worker1 上的 controller 节点的配置文件
controller.properties
,配置 woker2 的 controller 节点配置文件controller.properties
,worker3 也是类似的。
1 | # 配置当前节点的角色,这里只能是controller |
-
初始化日志目录
1 | # 只有 Controller 节点才需要初始化日志目录 |
-
分别启动 worker2 和 worker3 上的 controller 节点
1 | kafka-server-start.sh -daemon /usr/local/kafka/kafka3/config/kraft/controller.properties |
-
此时新的 controller 节点不会立刻加入选举队列,新节点初始状态默认是 observer,需要执行下面的命令将节点加入选举队列
1 | # 分别在 worker2 和 worker3 上执行 |
-
查看集群节点状态
1 | $ kafka-metadata-quorum.sh --bootstrap-server worker1:9092 describe --replication |
加入 新的 Broker 节点
-
创建新的 Broker 节点时,参考其它 Broker 节点 配置好配置文件
server.properties
,并启动 Broker 节点即可。 -
无需运行日志目录初始化命令,因为 Broker 节点只存放 消息 数据。
迁移后注意事项
-
迁移完成后,Kafka 客户端(Producer / Consumer / AdminClient)依然连接的是 Broker 节点,而不是 Controller 节点。
-
Kafka 在 ZooKeeper 模式与 KRaft 模式下的区别主要在于:
- 控制平面(Control Plane):ZK 模式下由 ZooKeeper + Controller Broker 共同管理;KRaft 模式下由 独立的 Controller 进程或角色 管理(通过 Raft 协议同步元数据)。
- 数据平面(Data Plane):无论是哪个模式,客户端发送、消费消息仍然是通过 Broker 节点 完成的。
- 也就是说,Controller 管理集群元数据(主题、分区、副本、Leader 选举等),而 Broker 节点处理实际的消息流。