3. Kafka 集群部署:从单机到集群,再到 KRaft 模式
部署 Kafka,说白了就是搭一个能扛住生产压力的消息管道。我见过不少团队,开发环境跑单机挺顺,一上生产就各种脑裂、磁盘写爆、Controller 挂了集群瘫痪。嗯,这里面的坑,多半是部署阶段埋下的。
这一章,咱们从最基础的单机部署开始,一步步走到真正的集群搭建。然后我会聊聊 ZooKeeper 在旧版 Kafka 里到底扮演什么角色,最后重点介绍 KRaft 模式——这个去掉 ZooKeeper 的新玩法,我个人觉得是未来趋势。
3.1 单机部署:先跑起来再说
单机部署其实就三步:下载、解压、启动。但别小看它,很多配置项的理解,都是从单机开始的。
具体步骤很简单:
- 从 Apache 官网下载 Kafka 二进制包(比如
kafka_2.13-3.5.0.tgz) - 解压到指定目录,比如
/opt/kafka - 修改
config/server.properties里的log.dirs,指向你的数据盘 - 启动 ZooKeeper(旧版需要):
bin/zookeeper-server-start.sh config/zookeeper.properties - 启动 Kafka:
bin/kafka-server-start.sh config/server.properties
启动成功后,你可以用 kafka-topics.sh 创建一个测试主题,再用 kafka-console-producer.sh 和 kafka-console-consumer.sh 验证一下。能发能收,单机就通了。
broker.id 默认是 0。如果你以后要扩集群,记得提前规划好 ID 分配,别到时候冲突了。
3.2 集群搭建:三个节点起步
生产环境至少三个节点,这是铁律。为什么?因为 Kafka 的副本机制需要多数派才能正常工作。两个节点,挂一个就完蛋;三个节点,挂一个还能撑住。
搭建集群的核心步骤:
- 准备三台机器(或三个容器),每台都装好 Kafka
- 每台机器的
server.properties里,broker.id分别设为 0、1、2 zookeeper.connect指向同一个 ZooKeeper 集群地址,比如zk1:2181,zk2:2181,zk3:2181- 启动顺序:先启动所有 ZooKeeper 节点,再依次启动 Kafka Broker
集群启动后,你可以用 kafka-broker-api-versions.sh --bootstrap-server broker1:9092,broker2:9092,broker3:9092 来验证所有节点是否都在线。
关键参数:
broker.id:集群内唯一,不能重复log.dirs:建议用多块磁盘,用逗号分隔,Kafka 会自动做数据均衡num.partitions:默认分区数,生产环境建议设为 3 或更高default.replication.factor:默认副本数,生产环境至少 2,推荐 3
我曾经遇到过一个案例:某团队把 default.replication.factor 设成了 1,结果一台机器磁盘坏了,整个主题的数据全丢。嗯,血的教训。
3.3 ZooKeeper 角色:集群的“大脑”
在 KRaft 模式出现之前,ZooKeeper 是 Kafka 集群的“大脑”。它负责三件事:
| 职责 | 说明 |
|---|---|
| Controller 选举 | 从所有 Broker 中选出一个 Controller,负责分区 leader 的分配 |
| 元数据存储 | 记录主题、分区、副本、Broker 列表等集群元数据 |
| 集群成员管理 | Broker 上下线时,ZooKeeper 能感知并通知 Controller |
说白了,ZooKeeper 就是 Kafka 的“注册中心”加“协调器”。没有它,Broker 之间不知道谁活着谁死了,分区 leader 也没人管了。
但 ZooKeeper 本身也是个分布式系统,它也有自己的集群部署要求。这就带来了一个问题:你为了管好 Kafka,还得先搭一套 ZooKeeper 集群。运维成本翻倍了。
3.4 KRaft 模式:去掉 ZooKeeper 的新时代
Kafka 2.8 开始引入了 KRaft 模式,到了 3.x 版本已经逐步成熟。它的核心思想是:Kafka 自己管自己的元数据,不再依赖 ZooKeeper。
怎么做到的?KRaft 模式引入了一个新的角色叫 Controller(注意,这和旧版的 Controller 不是一回事)。新 Controller 是一个独立的进程,或者内嵌在 Broker 里,它使用 Raft 共识算法来管理元数据变更。
对比一下两种模式:
| 对比项 | ZooKeeper 模式 | KRaft 模式 |
|---|---|---|
| 依赖组件 | Kafka + ZooKeeper | 只有 Kafka |
| 元数据存储 | ZooKeeper 存储 | Kafka 内部主题 __cluster_metadata |
| Controller 选举 | 依赖 ZooKeeper 临时节点 | Raft 算法自选举 |
| 运维复杂度 | 高(需要维护两套集群) | 低(一套集群搞定) |
| 成熟度 | 非常成熟 | 持续完善中(3.x 已可用于生产) |
KRaft 模式的部署也简单一些。你只需要在 server.properties 里配置 process.roles=broker,controller,然后指定 controller.quorum.voters 列表即可。
# KRaft 模式配置示例
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@kafka1:9093,2@kafka2:9093,3@kafka3:9093
node.id 替代了原来的 broker.id。而且 controller.quorum.voters 里的端口(9093)是 Controller 之间的通信端口,和客户端用的 9092 不一样。
我个人建议,新项目可以直接上 KRaft 模式。虽然它还在完善中,但 3.x 版本已经足够稳定。而且少维护一套 ZooKeeper,运维同学会感谢你的。
3.5 一张图看懂 Kafka 部署模式
下面这张图展示了从单机到集群,再到 KRaft 模式的演进路径。你可以看到 ZooKeeper 在旧模式中的位置,以及 KRaft 如何简化架构。
3.6 部署时的几个坑
最后,分享几个我踩过的坑,希望能帮你省点时间:
- 磁盘选择: 别用 NAS 或网络存储,Kafka 对磁盘延迟极其敏感。本地 SSD 是最佳选择。
- 内存分配: Kafka 本身不占太多内存,但操作系统会拿剩余内存做 Page Cache。所以给 Kafka 留足系统内存,别把机器内存全部分给 JVM。
- 网络带宽: 集群节点之间最好用万兆网络。千兆网络在数据量大的时候会成为瓶颈。
- 监控先行: 部署完第一时间配上监控。我习惯用 Prometheus + Grafana,重点看
UnderReplicatedPartitions和RequestHandlerAvgIdlePercent这两个指标。
fio 工具测一下磁盘的随机写性能。Kafka 的写入性能很大程度上取决于磁盘的 IOPS,而不是顺序读写速度。我曾经遇到过一块号称“高性能”的云盘,实际 IOPS 不到 2000,跑 Kafka 直接拉胯。