集群架构解剖:Broker、Topic、Partition、Replica、Controller、ZooKeeper 的角色与协作机制

很多人学 Kafka,上来就配参数、调吞吐量,结果集群一出问题就抓瞎。为什么?因为没搞懂这几个核心角色到底在干什么。

今天我就带你把这些角色拆开来看。Broker、Topic、Partition、Replica、Controller、ZooKeeper——它们各自管什么,怎么配合,踩过哪些坑。这部分搞透了,后面调优你才有底气。

1. Broker:集群里的每一台机器

Broker 说白了就是一台 Kafka 服务器进程。你部署一个 Kafka 实例,就启动了一个 Broker。多个 Broker 组成集群。

每个 Broker 有一个唯一 ID(broker.id),启动时注册到 ZooKeeper。客户端生产或消费数据,本质上就是跟 Broker 打交道。

核心职责:

  • 接收生产者发来的消息,写入磁盘
  • 响应消费者的拉取请求
  • 管理分区副本的同步
  • 参与 Controller 选举

我在项目中遇到过一个问题:某台 Broker 磁盘写满了,整个分区不可用。后来才意识到,Broker 的磁盘容量规划不能只看总量,要看每个 Broker 上的分区分布是否均匀。

2. Topic 与 Partition:逻辑与物理的分层

Topic 是逻辑概念,你往 Kafka 写数据,先得指定一个 Topic。但真正存数据的是 Partition。

一个 Topic 可以拆成多个 Partition,每个 Partition 是一个有序的、不可变的日志文件。Partition 内部的消息按 offset 编号,追加写入。

我的习惯:Topic 的分区数一般设为 Broker 数的 2-3 倍。太少会导致并发瓶颈,太多会增加管理开销。具体多少,得结合你的生产消费速率来压测。

为什么要分区?说白了就是为了并行。一个 Partition 只能被一个消费者实例消费,分区多了,消费者就能并行拉取,吞吐量就上去了。

概念 层级 特点
Topic 逻辑 面向业务,一个 Topic 对应一类消息
Partition 物理 实际存储单元,有序、可并行

3. Replica:副本机制与数据安全

Kafka 的高可用靠的就是副本。每个 Partition 可以有多个副本,分布在不同的 Broker 上。

副本分两种角色:

  • Leader:负责处理读写请求。生产者和消费者只跟 Leader 交互。
  • Follower:只做一件事——从 Leader 拉取数据,保持同步。

Leader 挂了怎么办?Controller 会从 ISR(In-Sync Replica)列表里选一个新的 Leader。ISR 是那些跟 Leader 保持同步的副本集合。

我曾经踩过的坑:副本数设成了 3,但 Broker 只有 2 台。结果 Leader 挂了之后,ISR 里没有可用副本,整个分区不可用。副本数不能超过 Broker 数,这是铁律。

4. Controller:集群的“大脑”

Controller 是集群里最特殊的 Broker。它负责管理整个集群的元数据和状态变更。

Controller 的职责包括:

  • 处理 Broker 上下线
  • 分配分区 Leader
  • 管理分区副本的重新分配
  • 监听 ZooKeeper 的变更通知

Controller 是通过 ZooKeeper 选举出来的。所有 Broker 启动时都会尝试在 ZooKeeper 上创建临时节点 /controller,谁创建成功,谁就是 Controller。

你想想看,如果 Controller 挂了怎么办?ZooKeeper 的临时节点会消失,其他 Broker 收到通知,重新发起选举。整个过程几秒钟内完成。

注意:Controller 是单点的。虽然选举很快,但如果 Controller 本身负载过高,会影响整个集群的元数据操作。我建议监控 Controller 的 CPU 和网络 IO,别让它成为瓶颈。

5. ZooKeeper:集群的“注册中心”

ZooKeeper 在 Kafka 里扮演的角色,说白了就是存元数据和做协调。

它主要存这些东西:

  • Broker 列表(/brokers/ids)
  • Topic 与 Partition 的元数据(/brokers/topics)
  • Controller 信息(/controller)
  • 消费者组的 offset(旧版本,新版本已移到 Kafka 内部 Topic)

ZooKeeper 的节点是临时节点,Broker 挂了,节点自动消失,Controller 就能感知到。

我的建议:ZooKeeper 集群一定要独立部署,别跟 Kafka Broker 混在一起。ZooKeeper 对 IO 敏感,混部容易互相影响。另外,ZooKeeper 的版本要跟 Kafka 版本匹配,不匹配会导致各种奇怪问题。

6. 协作机制:一次消息写入的完整路径

光讲概念不够,我们走一遍流程。假设生产者要往 Topic-A 写一条消息:

  1. 生产者向集群请求 Topic-A 的元数据,拿到每个 Partition 的 Leader 所在的 Broker。
  2. 生产者根据分区策略(比如 key 哈希),决定写入哪个 Partition。
  3. 生产者直接向该 Partition 的 Leader Broker 发送消息。
  4. Leader 将消息写入本地日志,同时 Follower 从 Leader 拉取数据。
  5. 当 ISR 中所有副本都确认写入后,Leader 向生产者返回 ack。
  6. 如果 Leader 挂了,Controller 从 ISR 中选出新 Leader,生产者自动重试。

整个过程,ZooKeeper 只负责存元数据和通知变更,不参与数据路径。这也是 Kafka 高性能的原因之一——数据不走 ZooKeeper。

核心原则:ZooKeeper 管“谁是谁”,Broker 管“数据在哪”,Controller 管“谁来干”。各司其职,互不干扰。

7. 架构全景图

下面这张图把整个协作关系画出来了。你看一眼,应该就能记住。

Kafka 集群架构协作全景图 ZooKeeper 集群 存储元数据 管理临时节点 通知变更事件 Controller Leader 选举 / 分区分配 Broker 集群 Broker 1 (Leader) Broker 2 (Follower) Broker 3 (Follower) Topic-A Partition 0/1/2 协作流程: 1. ZooKeeper 存储 Broker 列表和 Topic 元数据 2. Controller 监听 ZooKeeper 变更,管理 Leader 选举和分区分配 3. Broker 之间通过副本同步数据,生产消费只跟 Leader 交互

8. 避坑总结

最后,我把这些年踩过的坑和总结的经验列出来,你直接拿去用:

  • 副本数不要超过 Broker 数。否则 Leader 挂了,ISR 里没副本可用。
  • 分区数不是越多越好。太多分区会导致文件句柄暴增、Leader 选举变慢。一般单 Broker 分区数不超过 2000。
  • ZooKeeper 必须独立部署。混部会导致 ZooKeeper 响应变慢,进而影响 Controller 的选举和元数据操作。
  • Controller 要监控。如果 Controller 的 CPU 飙高,检查是不是有频繁的 Broker 上下线或分区重分配。
  • ISR 大小要关注。如果 ISR 经常小于副本数,说明 Follower 跟不上 Leader,可能是网络或磁盘 IO 问题。

嗯,这部分内容就到这里。你把这些角色和协作机制理清楚了,后面调优的时候,你才知道改哪个参数会影响谁,不会瞎调。