KafkaNotes

第 16 章:KRaft:Kafka 的新一代元数据架构

zjc 于 2026-01-16 发布

这是《Kafka 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 KRaft(Kafka Raft)是 Kafka 4.x 唯一的运行模式。本章深入它的动机、架构、元数据日志与运维要点,并说明如何从 ZooKeeper 集群迁移。

16.1 为什么要去掉 ZooKeeper

ZooKeeper 模式下的痛点:

  1. 两套系统:Broker 依赖 ZooKeeper 选举 Controller、存元数据;运维要同时维护两个分布式系统的安全、扩容、监控;
  2. 元数据双写:Controller 变更先写 ZooKeeper,再推送给 Broker,路径长、窗口内有不一致;
  3. 扩展瓶颈:分区数达到十万级时,Controller 故障切换要重放大量状态,收敛可能需要分钟级;
  4. 安全与网络复杂:客户端、Broker、ZooKeeper 三方网络与认证都要打通。

KRaft 的思路:既然 Kafka 本身就是高吞吐、高可用的分布式日志,那就用 Kafka 存 Kafka 的元数据

16.2 架构与角色

              ┌──────────────────────────────────┐
              │   __cluster_metadata (Raft log)  │
              │  topic 配置 / broker 注册 / 分区   │
              │  Leader 选举 / ACL / 配额 ...     │
              └───────────────┬──────────────────┘
                              │ 复制
        ┌─────────────┬───────┴──────┬─────────────┐
        v             v              v             v
   controller1    controller2    controller3     broker...
   (voter)        (voter)        (voter)        (learner)

角色由 process.roles 定义:

取值 含义 场景
controller 只参与仲裁,不存业务数据 大规模分离部署
broker 只存数据,作为 learner 同步元数据 分离部署的数据节点
broker,controller 兼具两种角色 中小集群合并部署

核心概念:

16.3 元数据变更如何发生

以“创建 topic”为例:

1. 客户端向任意 Broker 发 CreateTopics 请求
2. Broker 转发给 Leader Controller
3. Leader 把变更作为记录追加到 __cluster_metadata
4. Raft 多数派确认 -> commit
5. 所有 Broker 的元数据日志推进到该 offset
6. 客户端收到创建成功

对比 ZooKeeper 模式:不再存在“先写 ZK 再通知”的两阶段窗口,元数据的真相只有一份日志,所有节点按同一顺序回放。这从机制上消除了元数据分叉。

16.4 配置速览

# 节点角色与 ID
process.roles=broker,controller
node.id=1

# 仲裁者列表:id@host:controller端口
controller.quorum.voters=1@broker1:9093,2@broker2:9093,3@broker3:9093

# 监听器
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
advertised.listeners=PLAINTEXT://broker1:9092
controller.listener.names=CONTROLLER
listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT

# 数据目录
log.dirs=/data/kafka

运维要点:

16.5 常用运维命令

# 仲裁状态:谁是 Leader、HW、voter 列表
bin/kafka-metadata-quorum.sh \
  --bootstrap-server localhost:9092 describe --status

# 每个 voter 的同步详情
bin/kafka-metadata-quorum.sh \
  --bootstrap-server localhost:9092 describe --replication

# 查看元数据日志(排障)
bin/kafka-dump-log.sh \
  --files /data/kafka/__cluster_metadata-0/00000000000000000000.log \
  --cluster-metadata-decoder

describe --replication 里的 LastFetchTimestampLastCaughtUpTimestamp 能判断哪些 voter 落后。

16.6 故障场景

场景 影响
Leader Controller 宕机 多数派重新选出 Leader,期间元数据变更短暂不可用,数据读写基本不受影响
一个 Follower Controller 宕机 3 节点仲裁仍有多数派,无感知
两个 Controller 宕机(3 节点) 丢失多数派,元数据变更不可用;已有分区读写通常继续
Broker learner 落后 该 Broker 可能用旧元数据应答,客户端重试后纠正;持续落后需查网络/磁盘

和 Kafka 数据面一样:元数据面也是少数派服从多数派。3 节点 Controller 可以容忍 1 台故障,5 节点容忍 2 台。

16.7 从 ZooKeeper 迁移到 KRaft

Kafka 3.4-3.9 提供在线迁移工具,思路是“双写过渡”:

阶段1 ZK 模式:
  Controller <- ZooKeeper

阶段2 迁移中:
  ZK 里的元数据被迁移工具搬运到 __cluster_metadata
  新 KRaft Controller 作为 DualWriter 同时服务
  Broker 逐台切换为 KRaft 配置

阶段3 KRaft 模式:
  ZooKeeper 不再被依赖,可下线

操作要点:

  1. 先升级到支持迁移的 3.x 版本,做全量备份;
  2. 搭建 KRaft Controller 仲裁(通常 3 节点);
  3. 按 runbook 执行格式化与迁移准备;
  4. 触发 ZkMigrationState 切换,观察元数据一致性;
  5. 滚动重启 Broker 切到 KRaft 配置;
  6. 观察 kafka-metadata-quorum.sh 正常后,摘除 ZooKeeper。

迁移是高风险变更,务必在预发演练并准备好回退窗口。Kafka 4.0 已不支持 ZK 模式,老集群终将走上这条路。

16.8 监控要点

关键 JMX 指标:

告警建议:Controller Leader 长期缺失、voter 长期未追上、Broker 元数据 offset 滞后 Leader 过大。

本章小结

思考题

  1. 为什么 Broker 宕机不影响 KRaft 仲裁?为什么 Controller 宕机一般也不影响数据读写?
  2. 元数据日志和普通 topic 日志有什么相同与不同?
  3. 如果公司还在 ZK 模式,你会如何制定迁移评估清单?