Kafka 生产部署拓扑与组件职责
Kafka 的部署单元包括控制器、保存分区副本的 Broker,以及运行生产者、消费者和数据管道的应用进程。三类进程承担不同负载,扩容和故障恢复也有不同边界。只画几个 Broker,容易漏掉元数据多数派、客户端网络地址和内部主题这些影响可用性的条件。
本文以 Apache Kafka 4.3 文档中的 KRaft 部署为参照。Kafka 4.0 起不再支持 ZooKeeper 模式;旧集群迁移需要经过兼容的 3.x 版本。图中的三控制器、三 Broker 是解释故障域的示例,不是所有业务的容量配置。
控制面与数据面
控制器维护 Broker 注册、主题和分区元数据,决定分区领导者等集群状态。Broker 保存业务日志副本并响应生产和消费请求。业务消息无需经过控制器转发,控制器的副本数也不决定业务主题的副本数。
图 1:KRaft 控制面与业务数据面的部署边界
flowchart TB
subgraph CP[控制面:独立控制器进程]
C1[Controller 1] --- C2[Controller 2]
C2 --- C3[Controller 3]
end
subgraph DP[数据面:独立 Broker 进程]
B1[Broker 1] --- B2[Broker 2]
B2 --- B3[Broker 3]
end
DP -. 注册、心跳与元数据同步 .-> CP
P[生产者应用] -->|Produce| DP
DP -->|Fetch 响应| U[消费者应用]
图 1 中的虚线是管理通信,实线表示业务数据路径或组内关系。独立进程允许分别重启和扩容两类角色;合并模式会把 Broker 的资源争用和重启同时带给控制器,适合开发验证,关键生产环境应拆开部署。KRaft 部署说明给出了角色与多数派要求。
故障域与副本放置
三个控制器要分散到独立故障域,三个投票成员需要两个存活才能维持多数派。业务主题也应按故障域放置副本;配置 broker.rack 后,还需要检查实际分区分配,不能只凭副本因子判断容灾能力。
图 2:三个故障域中的控制器与单分区副本
flowchart LR
subgraph AZA[故障域 A]
CA[Controller A]
BA[Broker A:P0 Leader]
end
subgraph AZB[故障域 B]
CB[Controller B]
BB[Broker B:P0 Follower]
end
subgraph AZC[故障域 C]
CC[Controller C]
BC[Broker C:P0 Follower]
end
CA --- CB
CB --- CC
BA -->|日志复制| BB
BA -->|日志复制| BC
图 2 中一个故障域退出后,还剩两个控制器和两个 P0 副本。能否继续写入仍取决于存活副本是否同步、min.insync.replicas、选举状态和网络连通性。跨可用区复制还会增加网络成本和确认延迟,跨地域则通常采用独立集群与镜像复制。副本布局依据见Broker 的 rack 配置。
客户端发现与监听地址
bootstrap.servers 是客户端发现集群的起点。拿到元数据后,客户端会连接目标分区的 Broker 地址。负载均衡器能够接受第一次连接,并不代表后续生产与消费可用。
图 3:从 bootstrap 发现到分区领导者直连
sequenceDiagram
participant C as 客户端
participant B1 as Bootstrap Broker
participant B2 as P0 Leader Broker
C->>B1: 请求元数据
B1-->>C: P0 位于 B2,返回可连接地址
C->>B2: Produce 或 Fetch
B2-->>C: 写入结果或数据
图 3 的第二次连接使用 Broker 公布的地址。listeners 定义本机监听端点,advertised.listeners 定义对客户端公布的端点;后者必须能从对应客户端网络解析和访问。Controller listener、Broker 间通信和外部客户端入口要分别设计安全边界,不能把容器内部主机名直接公布给外部应用。监听配置与公布地址说明解释了这两个配置的区别。
分区数量与复制因子
分区切分业务日志,副本复制同一分区。一个 Broker 可以是 P0 的领导者,同时是 P1 的跟随者。新增 Broker 不会自动把现有主题平均搬过去,已有副本通常需要重分配。
图 4:三个分区在三个 Broker 上交错放置副本
flowchart TB
T[orders:3 个分区,副本因子 2]
T --> P0[P0:独立 offset 序列]
T --> P1[P1:独立 offset 序列]
T --> P2[P2:独立 offset 序列]
P0 --> A[Broker A:P0 Leader / P2 Follower]
P0 --> B[Broker B:P1 Leader / P0 Follower]
P1 --> B
P1 --> C[Broker C:P2 Leader / P1 Follower]
P2 --> C
P2 --> A
图 4 中一共是六份分区副本,而不是六个独立分区。把副本因子从二改成三会增加存储与复制开销,不会把普通消费者组的分区分配并行度从三提高到六。Kafka 设计文档分别描述了分区与副本机制。
写入确认与故障恢复
在三副本主题上,acks=all 配合 min.insync.replicas=2 可以要求写入满足至少两个同步副本的条件。acks=all 等待当前 ISR 的复制条件,并不等于固定等待所有配置副本,也不表示每台机器已同步刷盘。
图 5:三副本写入时的复制与确认路径
sequenceDiagram
participant P as Producer
participant L as Leader
participant F1 as ISR Follower 1
participant F2 as ISR Follower 2
P->>L: Produce,acks=all
L->>L: 追加本地日志
F1->>L: Fetch
L-->>F1: 新日志批次
F2->>L: Fetch
L-->>F2: 新日志批次
F1->>L: 后续 Fetch 报告新位点
F2->>L: 后续 Fetch 报告新位点
L-->>P: 满足复制与最小 ISR 条件后确认
图 5 中复制由 follower 拉取,Producer 不逐个请求副本。生产故障检查应同时查看 ISR 和选举相关特性:Kafka 4.1 起新集群默认启用 ELR,安全候选者可能来自符合条件的 ISR 外副本,不能把所有 ISR 外选举都归为脏选举。具体边界见生产者确认配置和ELR 说明。
消费分配与组协调
普通 consumer group 内一个分区在同一时刻分配给一个成员;不同组可以独立消费同一分区。Group Coordinator 是某个 Broker 上的职责,不需要另起一个 Controller 进程。
图 6:两个消费者组独立读取同一组分区
flowchart LR
P0[orders P0] --> A1[组 A:消费者 1]
P1[orders P1] --> A2[组 A:消费者 2]
P2[orders P2] --> A2
P0 --> B1[组 B:消费者 1]
P1 --> B1
P2 --> B1
A1 -. 组管理与位点提交 .-> G[Broker 上的 Group Coordinator]
A2 -. 组管理与位点提交 .-> G
图 6 的组 A 可以扩容到三个有效成员,继续增加成员不会增加这三个分区的分配并行度。它讨论的是普通 consumer group,不包含 Share Group。Kafka 4.x 同时支持 classic 和新 consumer 协议;group.protocol=consumer 使用服务端分配与增量协调,classic 的 JoinGroup/SyncGroup 时序不适用于它。Consumer Rebalance Protocol说明了协议切换及配置边界。
三类内部状态
元数据、消费位点和事务状态拥有不同的存储与协调职责。某个业务 Broker 正常,不代表它所在集群的所有协调功能都正常。
图 7:集群元数据、消费位点与事务状态的归属
flowchart LR
C[Controller quorum] --> M[专用元数据日志:__cluster_metadata]
G[Broker 上的 Group Coordinator] --> O[内部主题:__consumer_offsets]
T[Broker 上的 Transaction Coordinator] --> X[内部主题:__transaction_state]
O --> D[Broker 的数据目录与副本]
X --> D
图 7 把元数据日志与两个普通复制机制下的内部主题分开。__cluster_metadata 使用 KRaft 专用协议,不能按业务主题随意创建或消费。位点与事务主题也需要副本及容量规划;单 Broker 开发环境常见的降副本配置不能直接带入生产。Broker 配置列出了这两类内部主题的复制与最小 ISR 参数。
Kafka Connect 的运行位置
Connect worker 是独立于 Broker 的 JVM 进程。Connector 描述连接配置并生成 task 配置,task 执行搬运;扩容 worker 提供运行槽位,但 task 数量仍受连接器和源系统的切分能力限制。
图 8:Connect worker、任务与外部数据源的关系
flowchart LR
DB[外部数据源] --> S[Worker A:Source Task]
S --> K[Kafka 业务主题]
K --> T[Worker B:Sink Task]
T --> OUT[外部存储]
API[管理端 REST API] -. 配置 Connector .-> S
S -. 配置、状态与 Source 位点 .-> I[Connect 内部主题]
T -. 配置与状态 .-> I
图 8 的 Source 位点与业务消费者组位点不同。分布式 Connect 利用 Kafka 内部主题保存配置、状态和 Source 位点;Sink 消费位置使用消费者组机制。Source exactly-once 还要求连接器自身支持,框架开关不能为任意外部数据源制造事务能力。Connect 用户指南给出了模式与一致性条件。
Kafka Streams 的运行位置
Kafka Streams 是嵌入业务应用的库。部署的是应用实例,不是附加到 Broker 上的计算服务。任务分配给应用的流线程,持久状态可以保存在本地 RocksDB,并通过 changelog 恢复。
图 9:Streams 应用中的任务、本地状态与恢复日志
flowchart LR
IN[输入主题] --> TASK[应用 JVM:StreamThread / Task]
TASK --> OUT[输出主题]
TASK <--> STORE[本地 State Store]
TASK -->|状态变更| LOG[Kafka changelog 主题]
LOG -. 故障后恢复 .-> NEW[接管任务的应用实例]
TASK -. 需要重分区时 .-> RP[Kafka repartition 主题]
图 9 中应用扩容影响计算任务的分配,Broker 扩容影响日志存储和服务能力,两者不能互相替代。恢复时间与状态规模、changelog 读取速度和 standby 配置有关,增加实例并不自动消除状态恢复成本。Streams 架构描述了任务、线程与容错关系。
事务覆盖的范围
Kafka 事务能把输出记录与输入消费位点关联到同一次提交,事务消费者以 read_committed 读取结果。外部数据库和 HTTP 服务不会自动加入这个事务。
图 10:Kafka 事务内的输出与位点及事务外的副作用
flowchart TB
A[消费并处理输入]
subgraph TX[单个 Kafka 集群的事务范围]
O[输出分区记录]
P[输入消费位点]
C[事务协调与提交标记]
C --> O
C --> P
end
A --> O
A --> P
A --> DB[外部数据库写入:独立一致性边界]
O --> R[read_committed 消费者]
图 10 的数据库箭头跨出了事务范围,重试处理可能再次执行它。需要数据库幂等键、Outbox 或目标系统自身的事务协议来处理这条路径。Kafka 的提交结果也不等于多个消费者在同一瞬间看见所有输出。消息交付语义解释了 exactly-once 对外部存储的要求。
跨地域复制与切换
跨地域容灾常用两个独立 Kafka 集群,MirrorMaker 2 基于 Connect 复制数据与相关检查点。目标端复制落后时,源集群已确认的数据可能尚未抵达目标。
图 11:独立地域集群之间的异步镜像与消费切换
flowchart LR
P[生产应用] --> A[地域 A:Kafka 集群]
A -->|读取源主题| MM[MirrorMaker 2 / Connect]
MM -->|异步复制| B[地域 B:Kafka 集群]
MM -. 检查点与位点映射 .-> B
A --> C1[A 地消费者]
B -. 切换后重新定位 .-> C2[B 地消费者]
图 11 的目标 offset 不应直接当成源 offset。切换方案需要验证位点映射、主题命名、ACL、重复处理和复制延迟,RPO 也要按实际未复制数据量评估。MirrorMaker 2 不提供跨集群同步事务。跨集群镜像文档介绍了这类独立集群拓扑。
监控沿职责分层
Producer 超时、消费落后和控制器失去多数派可能同时出现,但处置入口不同。控制面看元数据领导者与同步状态,数据面看离线分区、ISR、磁盘和请求队列,应用端看发送错误、消费位点和业务完成时间。
图 12:从业务现象定位控制面、数据面与应用故障
flowchart TB
S[业务写入失败或消费延迟] --> Q{主要异常在哪里}
Q -->|创建主题或选举异常| C[检查 Controller quorum 与元数据滞后]
Q -->|Produce / Fetch 错误| B[检查离线分区、ISR、磁盘与监听地址]
Q -->|应用处理变慢| A[检查 consumer lag、线程与下游耗时]
C --> V[恢复后验证真实写入、读取与业务结果]
B --> V
A --> V
图 12 的分支是排查入口,不能据此把多个故障域割裂。滚动维护前需确认剩余控制器多数派、分区同步副本和磁盘容量,单个节点恢复后再处理下一个。验收应包括一条可追踪记录的生产、消费与业务结果;进程存活和监控数值恢复不足以证明全链路恢复。监控文档列出了各层指标。
系列导航
本篇为 Kafka 系列第 18 篇。完整目录见系列导读。
| 相关章节 | 主题 |
|---|---|
| 01 | 架构总览:Broker、Controller 与元数据管理 |
| 07 | 副本与 ISR:高可用的代价和折中 |
| 08 | Controller 与 KRaft:从 ZooKeeper 到内置共识 |
| 16 | 生产运维:集群扩缩、监控指标与故障排查 |
| 17 | Kafka 与 RocketMQ:两种消息系统的设计选择 |
参考资料
文中链接均指向 Apache Kafka 官方文档的 4.3 版本页。部署时还应以实际 Broker、客户端和已启用的 feature level 为准,不能用网页版本代替集群状态。
