4、集群模式部署:集群规划、多 Broker 配置、集群启动与验证、Controller 选举机制

单机玩 Kafka,说白了就是尝个鲜。真要上生产,你得面对集群。

我记得刚带团队那会儿,有人问我:“Kafka 集群到底要几台机器?” 我说,你先别急着数机器,得先想清楚你要扛多少流量、留多少冗余。今天这一章,我就带你走一遍集群部署的完整流程。从规划到启动,再到背后的 Controller 怎么选出来的,咱们一次讲透。

4.1 集群规划:先算账,再动手

集群规划是地基。地基歪了,后面全是坑。

我个人习惯,先回答三个问题:

  • 数据量多大? 每天写入多少 GB?保留几天?
  • 吞吐要求? 峰值 QPS 多少?消息大小平均多少?
  • 高可用等级? 允许几分钟不可用?还是秒级故障转移?

有了这些数,才能算节点数。我一般给个经验公式:

节点数 = ceil( (每日数据量 × 副本数 × 保留天数) / (单盘容量 × 0.75) )

再额外加 1~2 台做冗余。别把磁盘塞到 90% 以上,Kafka 在磁盘快满时性能会断崖式下跌。

举个例子。假设每天 500GB 数据,副本数 2,保留 7 天。单台挂 4TB 盘,可用 3TB。

算一下:500 × 2 × 7 = 7000GB。7000 / 3000 ≈ 2.33,向上取整 3 台,再加 1 台冗余,总共 4 台。

小提示: 我建议 Broker 节点数最好是奇数。为什么?后面讲 Controller 选举时你就明白了。

4.2 多 Broker 配置:别复制粘贴就完事

集群配置的核心文件还是 config/server.properties。但每个 Broker 的配置有差异,不能全用同一份。

关键参数如下:

参数 说明 集群中必须唯一?
broker.id 每个 Broker 的唯一标识 是
listeners 监听地址和端口 端口不冲突即可
log.dirs 数据目录,建议多盘挂载 否
zookeeper.connect ZooKeeper 地址列表 集群内一致
offsets.topic.replication.factor 偏移量主题的副本数 建议统一设为 3

下面是一个三节点集群的配置示例。假设三台机器 IP 为 192.168.1.10、192.168.1.11、192.168.1.12。

Broker 1 (192.168.1.10) 的 server.properties:

broker.id=1
listeners=PLAINTEXT://192.168.1.10:9092
log.dirs=/data/kafka/logs
zookeeper.connect=192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181
offsets.topic.replication.factor=3
num.partitions=3
default.replication.factor=3

Broker 2 (192.168.1.11) 的 server.properties:

broker.id=2
listeners=PLAINTEXT://192.168.1.11:9092
log.dirs=/data/kafka/logs
zookeeper.connect=192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181
offsets.topic.replication.factor=3
num.partitions=3
default.replication.factor=3

Broker 3 (192.168.1.12) 的 server.properties:

broker.id=3
listeners=PLAINTEXT://192.168.1.12:9092
log.dirs=/data/kafka/logs
zookeeper.connect=192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181
offsets.topic.replication.factor=3
num.partitions=3
default.replication.factor=3

注意: 我曾经见过有人把三台机器的 broker.id 都设成 1,结果启动后只有一台注册成功,另外两台一直报错。broker.id 必须全局唯一,这是铁律。

4.3 集群启动与验证:别急着高兴

配置写好了,怎么启动?

每台机器上依次执行:

# 先确保 ZooKeeper 集群已启动
# 然后启动每个 Broker
bin/kafka-server-start.sh -daemon config/server.properties

启动顺序有讲究吗?其实没有。Broker 之间是平等的,谁先启动都行。但 ZooKeeper 必须先于 Kafka 启动,这个顺序不能乱。

启动后怎么验证?我一般做三件事:

  1. 看进程: jps -l 能看到 Kafka 进程。
  2. 看日志: 检查 logs/server.log,搜索 INFO [KafkaServer id=1] started 字样。
  3. 用工具查: 执行下面命令,看集群是否返回了所有 Broker。
bin/kafka-broker-api-versions.sh --bootstrap-server 192.168.1.10:9092,192.168.1.11:9092,192.168.1.12:9092

如果返回了三个 Broker 的版本信息,说明集群通信正常。

再创建一个测试主题验证读写:

bin/kafka-topics.sh --create --topic test-cluster \
  --bootstrap-server 192.168.1.10:9092 \
  --partitions 3 --replication-factor 3

bin/kafka-topics.sh --describe --topic test-cluster \
  --bootstrap-server 192.168.1.10:9092

输出里你会看到类似这样的信息:

Topic: test-cluster	PartitionCount: 3	ReplicationFactor: 3
	Topic: test-cluster	Partition: 0	Leader: 1	Replicas: 1,2,3	Isr: 1,2,3
	Topic: test-cluster	Partition: 1	Leader: 2	Replicas: 2,3,1	Isr: 2,3,1
	Topic: test-cluster	Partition: 2	Leader: 3	Replicas: 3,1,2	Isr: 3,1,2

看到 Leader 分布在不同的 Broker 上,ISR 列表完整,说明集群部署成功。

4.4 Controller 选举机制:谁说了算?

集群里这么多 Broker,总得有个管事的。这个管事的就叫 Controller。

Controller 负责什么?说白了,就是管理集群的元数据。比如:

  • 谁当 Partition 的 Leader
  • 新 Broker 加入或旧 Broker 宕机时怎么重新分配
  • 主题的创建和删除

那 Controller 是怎么选出来的?

Kafka 依赖 ZooKeeper 来做选举。具体流程是这样的:

  1. 每个 Broker 启动时,都会尝试在 ZooKeeper 上创建一个临时节点 /controller。
  2. 谁先创建成功,谁就是 Controller。
  3. 其他 Broker 创建失败,就会在这个节点上注册 Watcher,监听它是否消失。
  4. 如果 Controller 宕机,ZooKeeper 上的临时节点自动消失。
  5. 所有监听的 Broker 收到通知,重新发起选举。

这个过程,说白了就是“先到先得”。没有复杂的投票算法,简单但有效。

关键点: 这就是为什么我建议 Broker 数量是奇数。如果集群偶数台,Controller 挂了重新选举时,可能会出现“脑裂”风险吗?不会,因为 ZooKeeper 的强一致性保证了只有一个节点能创建成功。但奇数节点在 ZooKeeper 集群自身选举时更稳定,间接让 Kafka 集群更可靠。

下面这张图展示了 Controller 选举的完整流程:

Kafka Controller 选举流程 ZooKeeper Broker 1 Broker 2 Broker 3 尝试创建 /controller 尝试创建 /controller 尝试创建 /controller Controller (Broker 2) 说明: Broker 2 最先在 ZooKeeper 上创建了 /controller 临时节点,成为 Controller。 Broker 1 和 Broker 3 创建失败,注册 Watcher 监听 /controller 节点。

选举完成后,Controller 会做一件重要的事:向所有 Broker 发送元数据更新请求。每个 Broker 都会收到一份最新的集群状态,包括谁是谁的 Leader、ISR 列表等。

如果 Controller 挂了怎么办?

我刚才说了,ZooKeeper 上的 /controller 是临时节点。Broker 2 宕机后,这个节点自动消失。剩下的 Broker 1 和 Broker 3 收到 Watcher 通知,再次发起创建。谁先抢到,谁就是新的 Controller。

避坑指南: 我曾经遇到过一个问题:Controller 频繁切换。查了半天,发现是 ZooKeeper 集群网络抖动,导致临时节点超时被删除。解决方案是调大 ZooKeeper 的 session.timeout.ms,默认 6 秒,我改成了 18 秒。网络不稳的环境下,这个参数值得注意。

最后说一句,Controller 本身不处理数据读写。它只负责“管人”,不负责“干活”。所以即使 Controller 压力大,也不会影响消息的生产和消费。但 Controller 切换期间,会有短暂的元数据不可用,比如创建主题会失败。生产环境里,这个窗口通常只有几秒钟。