Kafka + KRaft模式架构基础介绍

Kafka + KRaft模式架构基础介绍

适用版本:Kafka 3.3+(生产推荐)


一、概述:为什么使用 KRaft?

自 Kafka 2.8 起,社区引入 KRaft(Kafka Raft Metadata)模式 ,旨在完全移除对 ZooKeeper 的依赖。从 Kafka 3.3 开始,KRaft 成为官方推荐的生产部署模式。

核心优势

  • 架构简化:无需独立部署、监控、备份 ZooKeeper;
  • 性能提升:元数据变更吞吐提升 5--10 倍,延迟更低;
  • 高可用增强:基于 Raft 协议,选举更快、防脑裂;
  • 云原生友好:StatefulSet 部署更简单,适合 Kubernetes;
  • 统一运维:日志、监控、告警全部集中于 Kafka。

注意 :KRaft 仅改变元数据管理方式消息存储、副本机制、ISR 等数据平面逻辑完全不变


二、KRaft 架构模式

KRaft 支持两种部署模式:

模式 说明 适用场景
Combined Mode 单节点同时承担 Broker + Controller 角色 中小集群(≤ 20 节点)
Dedicated Mode Controller 与 Data Broker 物理分离 超大集群(> 20 节点)或高安全要求

三、Combined Mode 架构与工作流程

架构图

graph LR subgraph "KRaft Controller Quorum" C1[Controller 1
Active] C2[Controller 2
Follower] C3[Controller 3
Follower] end subgraph "Data Brokers" B1[Broker 1] B2[Broker 2] B3[Broker N] end C1 -->|Append Log| MT[__cluster_metadata] C2 -->|Replicate| MT C3 -->|Replicate| MT B1 -->|Metadata Request| C1 B2 -->|Metadata Request| C1 B3 -->|Metadata Request| C1

在 Combined Mode 中,C1 = B1C2 = B2C3 = B3,即角色合一。

工作流程步骤

  1. 集群启动

    • 所有节点启动 Kafka 服务;
    • 每个节点根据 process.roles=broker,controller 初始化双重角色;
    • Controller 模块尝试加入 Raft Quorum。
  2. Raft 选举

    • 节点通过 CONTROLLER 监听器(如 9093 端口)通信;
    • 选举出一个 Active Controller(Leader)
    • 其余节点成为 Follower,仅同步元数据日志。
  3. Broker 注册

    • 每个 Broker 向 Active Controller 发送注册请求;
    • Active Controller 将 Broker 信息写入 Metadata Log (内部 Topic __cluster_metadata);
    • 日志通过 Raft 协议复制到所有 Follower。
  4. 元数据变更(如创建 Topic)

    • 客户端请求 → 任意 Broker → 转发至 Active Controller;
    • Active Controller 生成元数据变更记录,追加到 Metadata Log;
    • 日志复制成功后,广播新元数据给所有 Broker。
  5. 消息读写(数据平面)

    • Producer/Consumer 连接任意 Broker;
    • 若非目标分区 Leader,Broker 返回 Redirect;
    • 客户端直连 分区 Leader Broker不经过 Controller
    • 消息路径完全独立于控制平面
  6. 故障恢复

    • Active Controller 宕机 → Raft 心跳超时 → 触发新选举;
    • 新 Leader 从本地 Metadata Log 恢复全量状态;
    • 继续提供元数据服务,业务无感知。

关键结论

  • 控制平面:Client → Broker → Active Controller → Metadata Log(Raft 复制);
  • 数据平面:Client ↔ Partition Leader Broker(直连,高效);
  • Controller 不参与消息收发

四、Raft Controller 选举流程详解

sequenceDiagram participant C1 as Controller 1 participant C2 as Controller 2 participant C3 as Controller 3 Note over C1,C3: 集群启动或 Leader 宕机 C1->>C2: RequestVote(term=1) C1->>C3: RequestVote(term=1) C2-->>C1: VoteGranted C3-->>C1: VoteGranted Note right of C1: C1 成为 Leader (term=1) loop Heartbeat C1->>C2: AppendEntries(term=1) C1->>C3: AppendEntries(term=1) end Note over C1: C1 宕机 C2->>C3: RequestVote(term=2) C3-->>C2: VoteGranted Note right of C2: C2 成为新 Leader (term=2)

KRaft 使用标准 Raft 协议实现 Controller 高可用。

触发条件

  • 集群首次启动;
  • Active Controller 宕机或网络隔离;
  • Follower 在 election.timeout.ms(默认 1--2 秒,随机化)内未收到心跳。

详细步骤

步骤 1:Follower 转为 Candidate
  • 某 Follower(如 Controller 2)未收到 Leader 心跳;
  • 自增 term(任期)(如 1 → 2);
  • 投票给自己;
  • 向其他 Quorum 成员发送 RequestVote RPC,包含:
    • 自身 term;
    • 最后一条日志的 index 和 term。
步骤 2:接收投票
  • 其他节点判断:
    • 自身 term ≤ 请求 term;
    • 请求者日志 不比自己旧
  • 若满足,则投出 唯一一票
  • 返回 VoteGranted = true
步骤 3:赢得选举
  • Candidate 收到 多数派投票(3 节点需 2 票);
  • 转为 Leader
  • 向所有 Follower 发送空 AppendEntries(心跳),宣告领导权。
步骤 4:维持领导
  • Leader 定期(如每 500ms)发送心跳;
  • Follower 收到后重置选举计时器;
  • 只要心跳正常,就不会发起新选举。
步骤 5:处理旧 Leader 回归
  • 原 Leader 恢复但 term 已过期;
  • 收到新 Leader 的 AppendEntries 后,自动降级为 Follower;
  • Raft 协议天然避免脑裂

Raft 安全性保障(KRaft 实现)

  • Election Safety:任一 term 最多一个 Leader;
  • Log Matching:相同 index + term 的日志内容一致;
  • Leader Completeness:已提交日志必存在于未来 Leader 中;
  • Pre-Vote(可选):防止网络抖动引发无效选举。

五、KRaft 配置详解

1. 生成集群 ID(首次部署必需)

bash 复制代码
CLUSTER_ID=$(bin/kafka-storage.sh random-uuid)
echo $CLUSTER_ID  # 保存用于格式化

2. server.properties(Combined Mode 示例)

properties 复制代码
# ===== 基础身份 =====
process.roles=broker,controller
node.id=1

# ===== 网络监听 =====
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
inter.broker.listener.name=PLAINTEXT
controller.listener.names=CONTROLLER
advertised.listeners=PLAINTEXT://kafka1.example.com:9092

# ===== Controller Quorum =====
controller.quorum.voters=1@kafka1:9093,2@kafka2:9093,3@kafka3:9093

# ===== 存储目录 =====
log.dirs=/data/kafka/data
metadata.log.dir=/data/kafka/metadata  # 强烈建议独立磁盘

# ===== 主题默认配置 =====
num.partitions=6
default.replication.factor=3
min.insync.replicas=2

# ===== 安全关闭 =====
controlled.shutdown.enable=true

3. 初始化存储目录(每个节点执行)

bash 复制代码
bin/kafka-storage.sh format -t <CLUSTER_ID> -c config/server.properties

4. 启动服务

bash 复制代码
bin/kafka-server-start.sh config/server.properties
# 无需启动 ZooKeeper!

六、关键配置参数说明

参数 默认值 说明 生产建议
process.roles --- 节点角色 broker,controller(Combined)
node.id --- 节点唯一 ID voters 中 ID 一致
controller.quorum.voters --- Quorum 列表 格式:id@host:port,...
metadata.log.dir log.dirs 元数据日志目录 独立 SSD 磁盘
metadata.max.retention.bytes Long.MAX 元数据日志保留大小 按需设置(如 1GB)
controller.quorum.election.timeout.ms 1000--2000 选举超时(随机) 无需调整

七、运维与监控

1. 查看 Quorum 状态

bash 复制代码
bin/kafka-metadata-quorum.sh --bootstrap-server kafka1:9092 describe --status

输出示例

makefile 复制代码
ClusterId: a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8
LeaderId: 1
VoterEndpoints: 1@kafka1:9093,2@kafka2:9093,3@kafka3:9093
HighWatermark: 12345

2. 查看元数据日志(调试)

bash 复制代码
bin/kafka-dump-log.sh --cluster-metadata-decoder \
  --files /data/kafka/metadata/00000000000000000000.log

3. 关键监控指标

指标 说明
ActiveControllerCount 应恒为 1
QueuedUnsentRequests Controller 请求积压
AppendRecordsRate 元数据写入速率
MetadataLogSize 元数据日志大小(应定期快照压缩)

八、常见问题与故障处理

问题 现象 解决方案
无法选举 Leader ActiveControllerCount = 0 检查 Quorum 节点数 ≥ 半数
Broker 无法注册 日志报 "NotControllerException" 检查 node.id 唯一性、网络通 CONTROLLER 端口
元数据日志损坏 启动失败,报 "Corrupt snapshot" 从 Snapshot 恢复,或重建集群(需备份数据)
客户端连接失败 报 "UnknownTopicOrPartition" 确认 Active Controller 正常,元数据已同步

九、总结与最佳实践

推荐场景

  • 新项目:强制使用 Kafka 3.5+ + KRaft;
  • 容器化部署:Kubernetes StatefulSet + Combined Mode;
  • 大规模集群:Dedicated Controller Mode + 独立元数据盘。

注意事项

  • 不可原地升级:ZooKeeper 模式需重建集群才能迁移到 KRaft;
  • 备份策略 :定期备份 metadata.log.dir 和 Topic 数据;
  • 监控重点:Quorum 健康度、元数据日志大小、选举频率。

延伸阅读


相关推荐
洛森唛2 小时前
Elasticsearch DSL 查询语法大全:从入门到精通
后端·elasticsearch
拳打南山敬老院3 小时前
Context 不是压缩出来的,而是设计出来的
前端·后端·aigc
初次攀爬者3 小时前
Kafka + ZooKeeper架构基础介绍
后端·zookeeper·kafka
LucianaiB3 小时前
Openclaw 安装使用保姆级教程(最新版)
后端
初次攀爬者3 小时前
Kafka 基础介绍
spring boot·kafka·消息队列
华仔啊3 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
哈密瓜的眉毛美3 小时前
零基础学Java|第五篇:进制转换与位运算、原码反码补码
后端
开心就好20254 小时前
免 Xcode 的 iOS 开发新选择?聊聊一款更轻量的 iOS 开发 IDE kxapp 快蝎
后端·ios
Java编程爱好者4 小时前
为什么国内大厂纷纷”弃坑”MySQL,转投PostgreSQL阵营?
后端