4、Kafka集群搭建:单机部署、集群配置、ZooKeeper角色、常用配置参数调优

好,咱们进入第四章。前面聊完了Kafka的设计理念和核心概念,现在该动手了。

这一章,我会带你从零搭一个Kafka集群。单机怎么玩、集群怎么配、ZooKeeper到底在里头干啥、哪些参数必须调——咱们一次说透。

我个人习惯,学一个新东西,先跑通单机,再上集群。这样出问题了,排查范围小。

4.1 单机部署:先跑起来再说

单机部署其实就三步:下载、解压、启动。但这里头有几个坑,我先帮你踩一遍。

4.1.1 环境准备

  • JDK:Kafka 3.x 要求 JDK 11+。我建议用 JDK 17,稳。
  • ZooKeeper:Kafka 3.x 虽然开始去ZK依赖,但生产环境还是建议带着ZK跑。
  • 操作系统:Linux 首选。Windows 也能跑,但别在生产上用。

4.1.2 下载与配置

# 下载 Kafka(以 3.5.0 为例)
wget https://downloads.apache.org/kafka/3.5.0/kafka_2.13-3.5.0.tgz
tar -xzf kafka_2.13-3.5.0.tgz
cd kafka_2.13-3.5.0

解压完,看一眼目录结构。核心就几个:bin/(启动脚本)、config/(配置文件)、logs/(运行日志)。

改一下 config/server.properties:

# 基础配置
broker.id=0
listeners=PLAINTEXT://localhost:9092
log.dirs=/tmp/kafka-logs
zookeeper.connect=localhost:2181

嗯,这里要注意:log.dirs 别用默认的 /tmp 目录。我遇到过,系统重启后 /tmp 被清空,Kafka 直接报错找不到日志段文件。改成持久化路径,比如 /data/kafka/logs。

4.1.3 启动验证

# 先启动 ZooKeeper
bin/zookeeper-server-start.sh config/zookeeper.properties &

# 再启动 Kafka
bin/kafka-server-start.sh config/server.properties &

# 创建测试主题
bin/kafka-topics.sh --create --topic test-topic --bootstrap-server localhost:9092 --partitions 3 --replication-factor 1

# 查看主题列表
bin/kafka-topics.sh --list --bootstrap-server localhost:9092

看到 test-topic 出现在列表里,单机部署就成功了。简单吧?

小技巧:启动时加上 & 让进程后台运行。但生产环境建议用 systemd 或 supervisor 管理进程,不然终端一关服务就停了。

4.2 集群配置:三台机器才是起步

单机只能玩玩,生产环境至少三台 broker。为什么是三台?你想想看,副本因子通常设3,如果只有两台机器,一台挂了,ISR 就只剩一个副本,容错能力大打折扣。

4.2.1 集群规划

假设有三台机器:kafka1、kafka2、kafka3。每台机器上都要部署 Kafka 和 ZooKeeper。

节点 broker.id 监听端口 日志目录
kafka1 0 9092 /data/kafka/logs
kafka2 1 9092 /data/kafka/logs
kafka3 2 9092 /data/kafka/logs

4.2.2 核心配置项

每台机器的 server.properties 配置大同小异,区别主要在 broker.id 和 listeners。

# kafka1 的配置
broker.id=0
listeners=PLAINTEXT://kafka1:9092
advertised.listeners=PLAINTEXT://kafka1:9092
log.dirs=/data/kafka/logs
zookeeper.connect=kafka1:2181,kafka2:2181,kafka3:2181
offsets.topic.replication.factor=3
transaction.state.log.replication.factor=3
transaction.state.log.min.isr=2

这里有个关键点:advertised.listeners。这个配置是告诉客户端「你应该连哪个地址」。如果配错了,客户端能连上集群,但生产消费会报错。我曾经踩过这个坑,配成了 localhost,结果远程客户端连上来,拿到的是 localhost:9092,当然连不上。

4.2.3 启动集群

每台机器上依次启动 ZooKeeper 和 Kafka:

# 在 kafka1 上
bin/zookeeper-server-start.sh config/zookeeper.properties &
bin/kafka-server-start.sh config/server.properties &

# 在 kafka2 上(同样操作)
# 在 kafka3 上(同样操作)

启动完成后,验证集群状态:

bin/kafka-broker-api-versions.sh --bootstrap-server kafka1:9092,kafka2:9092,kafka3:9092

如果看到三个 broker 都返回了版本信息,集群就搭好了。

集群验证小技巧:创建一个副本因子为3的主题,然后手动停掉一台 broker,看看生产和消费是否正常。这是检验集群容错能力最直接的方法。

4.3 ZooKeeper 角色:集群的「大脑」

ZooKeeper 在 Kafka 集群里到底干啥?说白了,它就是个协调者。Kafka 自己搞不定的事情,交给 ZK 来管。

4.3.1 ZooKeeper 的核心职责

  • Broker 注册与发现:每个 broker 启动时,会在 ZK 上注册一个临时节点。其他 broker 和客户端通过 ZK 知道集群里有哪些节点。
  • Controller 选举:集群里有一个特殊的 broker 叫 Controller,负责分区 leader 的选举。Controller 挂了,ZK 会触发重新选举。
  • 主题与分区元数据:主题有哪些分区、分区 leader 是谁、ISR 列表是什么——这些信息都存在 ZK 里。
  • 消费者组偏移量:老版本的 Kafka 把消费偏移量存在 ZK 里。新版本虽然改存在内部主题 __consumer_offsets 里,但 ZK 仍然参与消费者组的协调。

4.3.2 ZooKeeper 集群部署

ZK 本身也是一个集群,通常部署奇数个节点(3、5、7)。为什么是奇数?因为 ZK 的选举机制需要过半同意,奇数节点能避免平票。

配置 config/zookeeper.properties:

dataDir=/data/zookeeper/data
clientPort=2181
maxClientCnxns=60
tickTime=2000
initLimit=10
syncLimit=5
server.0=kafka1:2888:3888
server.1=kafka2:2888:3888
server.2=kafka3:2888:3888

每台机器上还要在 dataDir 目录下创建一个 myid 文件,内容就是对应的 server ID:

# kafka1 上
echo "0" > /data/zookeeper/data/myid
# kafka2 上
echo "1" > /data/zookeeper/data/myid
# kafka3 上
echo "2" > /data/zookeeper/data/myid
注意:ZK 集群的节点数不要超过7个。节点太多,选举时间会变长,反而影响性能。我见过有人搭了9个 ZK 节点,结果一次网络抖动,选举花了十几秒,整个 Kafka 集群在那段时间里不可用。

4.4 常用配置参数调优

配置参数是门学问。调好了,性能翻倍;调不好,各种诡异问题。下面是我在实际项目中总结的几个关键参数。

4.4.1 Broker 核心参数

参数名 默认值 推荐值 说明
num.network.threads 3 CPU核数 × 2 网络线程数,处理客户端请求
num.io.threads 8 CPU核数 × 2 I/O线程数,处理磁盘读写
log.retention.hours 168 72(3天) 日志保留时间,根据业务调整
log.segment.bytes 1GB 1GB 日志段文件大小,一般不用改
log.retention.bytes -1 -1(不限) 日志保留总大小,按磁盘容量设

4.4.2 生产者参数调优

生产者的核心是吞吐量和可靠性之间的权衡。

  • acks:acks=all 最安全,但延迟高;acks=1 性能好,但可能丢数据。我建议核心业务用 all,日志采集用 1。
  • batch.size:默认16KB。如果消息体小,可以调到32KB或64KB,减少网络请求次数。
  • linger.ms:默认0。可以设成5-10ms,让消息在缓冲区多等一会儿,凑成一批再发,吞吐量能提升不少。
  • compression.type:建议用 snappy 或 lz4。压缩比高,CPU开销小。

4.4.3 消费者参数调优

  • fetch.min.bytes:默认1。可以调到1KB或更高,减少拉取次数。
  • max.poll.records:默认500。如果每条消息处理时间长,可以调小,防止超时导致 rebalance。
  • session.timeout.ms:默认45秒。如果网络不稳定,可以适当调大,避免误判消费者死亡。
避坑指南:我曾经把 max.poll.records 设成5000,结果消费者处理不过来,触发了 rebalance。rebalance 期间所有分区都暂停消费,整个系统吞吐量直接腰斩。后来我改成1000,配合 max.poll.interval.ms 设成5分钟,问题解决。

4.5 集群架构总览

说了这么多,咱们用一张图把整个集群架构串起来。这张图展示了三台 broker、三台 ZK、以及它们之间的交互关系。

Kafka 集群架构图(3 Broker + 3 ZooKeeper) ZooKeeper 集群 ZK1 (Leader) ZK2 (Follower) ZK3 (Follower) Kafka Broker 集群 Broker 0 (Controller) kafka1:9092 Broker 1 kafka2:9092 Broker 2 kafka3:9092 客户端 生产者 (Producer) 发送消息 消费者 (Consumer) 拉取消息 说明: • ZooKeeper 集群负责 broker 注册、Controller 选举、元数据存储 • Broker 之间通过内部协议同步数据,客户端通过 advertised.listeners 连接任意 broker

从这张图可以看得很清楚:ZK 集群在上层做协调,Broker 集群在下层做数据存储和转发,客户端通过任意 broker 接入集群。整个架构的核心就是「ZK 管元数据,Broker 管数据」。

4.6 本章小结

这一章我们走完了从单机到集群的全过程。单机部署是热身,集群配置是实战,ZooKeeper 角色是理解架构的关键,参数调优是性能保障。

我个人觉得,搭建集群本身不难,难的是理解每个配置背后的原理。你想想看,如果不知道 advertised.listeners 是干嘛的,出了问题只能瞎猜。所以,多动手、多踩坑、多总结——这是成为资深工程师的唯一路径。