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 启动,这个顺序不能乱。
启动后怎么验证?我一般做三件事:
- 看进程:
jps -l能看到Kafka进程。 - 看日志: 检查
logs/server.log,搜索INFO [KafkaServer id=1] started字样。 - 用工具查: 执行下面命令,看集群是否返回了所有 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 来做选举。具体流程是这样的:
- 每个 Broker 启动时,都会尝试在 ZooKeeper 上创建一个临时节点
/controller。 - 谁先创建成功,谁就是 Controller。
- 其他 Broker 创建失败,就会在这个节点上注册 Watcher,监听它是否消失。
- 如果 Controller 宕机,ZooKeeper 上的临时节点自动消失。
- 所有监听的 Broker 收到通知,重新发起选举。
这个过程,说白了就是“先到先得”。没有复杂的投票算法,简单但有效。
关键点: 这就是为什么我建议 Broker 数量是奇数。如果集群偶数台,Controller 挂了重新选举时,可能会出现“脑裂”风险吗?不会,因为 ZooKeeper 的强一致性保证了只有一个节点能创建成功。但奇数节点在 ZooKeeper 集群自身选举时更稳定,间接让 Kafka 集群更可靠。
下面这张图展示了 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 切换期间,会有短暂的元数据不可用,比如创建主题会失败。生产环境里,这个窗口通常只有几秒钟。