3. Kafka集群搭建:从单机到生产环境

搭建Kafka环境,是每个入门者必须跨过的第一道坎。说实话,我见过太多人在这一步踩坑了——不是配置文件写错,就是启动时莫名其妙报错。这一章,我会把单机搭建、集群部署、JMX监控以及常见问题排查,一次性讲清楚。

本章核心脉络:单机环境 → 集群配置 → 监控开启 → 问题排查。每一步都是下一环的基础,别跳着看。

Kafka 集群搭建知识体系 单机环境搭建 ZooKeeper + Kafka 集群部署配置 多Broker + 副本 JMX监控开启 JConsole / Prometheus 问题排查 常见错误 下载 & 解压 配置 server.properties broker.id 唯一 listeners 配置 JMX_PORT 环境变量 JConsole 连接 端口冲突 日志目录权限 建议:先跑通单机,再扩展集群,最后加监控

3.1 单机环境搭建

单机搭建其实不复杂。我习惯先装ZooKeeper,再装Kafka。为什么?因为Kafka从0.9版本开始虽然内置了ZooKeeper,但生产环境我从来不用内置的——你想想看,万一ZooKeeper挂了,Kafka也跟着完蛋,这不合理。

3.1.1 环境准备

  • JDK 8+:必须的,Kafka是Scala写的,跑在JVM上
  • ZooKeeper 3.5+:我推荐3.6.x,稳定
  • Kafka 2.8+:建议用最新稳定版,别追新

我的习惯:统一放在 /opt/ 目录下,建个软链方便升级。比如 /opt/kafka → /opt/kafka_2.13-3.2.0。

3.1.2 安装步骤

  1. 下载解压
wget https://downloads.apache.org/kafka/3.2.0/kafka_2.13-3.2.0.tgz
tar -xzf kafka_2.13-3.2.0.tgz -C /opt/
ln -s /opt/kafka_2.13-3.2.0 /opt/kafka
  1. 配置ZooKeeper
# /opt/zookeeper/conf/zoo.cfg
tickTime=2000
dataDir=/data/zookeeper
clientPort=2181
maxClientCnxns=60
  1. 启动ZooKeeper
/opt/zookeeper/bin/zkServer.sh start
  1. 配置Kafka
# /opt/kafka/config/server.properties
broker.id=0
listeners=PLAINTEXT://localhost:9092
log.dirs=/data/kafka/logs
zookeeper.connect=localhost:2181
  1. 启动Kafka
/opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties

注意:我第一次搭建时忘了创建 /data/kafka/logs 目录,结果启动报错。Kafka不会自动创建日志目录,你得手动 mkdir。

3.2 集群部署配置

单机跑通了,接下来就是集群。说白了,集群就是把多个Kafka实例连起来,让它们互相知道对方的存在。我建议至少3个节点,这样才能保证副本机制生效。

3.2.1 集群规划

节点 broker.id listeners 日志目录
node1 0 PLAINTEXT://192.168.1.10:9092 /data/kafka/logs
node2 1 PLAINTEXT://192.168.1.11:9092 /data/kafka/logs
node3 2 PLAINTEXT://192.168.1.12:9092 /data/kafka/logs

3.2.2 关键配置项

每个节点的 server.properties 都要改,别偷懒复制粘贴。我吃过这个亏——三个节点 broker.id 全设成0,结果启动后只有一个节点在线。

# node1 的配置
broker.id=0
listeners=PLAINTEXT://192.168.1.10:9092
advertised.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
num.partitions=3
default.replication.factor=2
offsets.topic.replication.factor=2

重点:advertised.listeners 必须写对外IP,不然客户端连不上。我遇到过有人写 localhost,结果远程客户端死活连不上,查了半天才发现。

3.2.3 启动集群

每个节点依次启动ZooKeeper,再启动Kafka。启动顺序不重要,但建议先启动ZooKeeper集群。

# 在 node1 上
/opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties

# 验证集群状态
/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server 192.168.1.10:9092

3.3 JMX监控开启

集群跑起来了,但你怎么知道它健康不健康?JMX就是干这个的。我个人习惯在启动脚本里直接配好JMX端口,省得后面再折腾。

3.3.1 配置JMX

修改 kafka-server-start.sh,在 export KAFKA_HEAP_OPTS 后面加上JMX配置:

# /opt/kafka/bin/kafka-server-start.sh
export JMX_PORT=9999
export KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote
  -Dcom.sun.management.jmxremote.authenticate=false
  -Dcom.sun.management.jmxremote.ssl=false
  -Dcom.sun.management.jmxremote.port=9999
  -Dcom.sun.management.jmxremote.rmi.port=9999
  -Djava.rmi.server.hostname=192.168.1.10"

安全提醒:生产环境别把 authenticate 设成 false,不然谁都能连你的JMX。我一般在测试环境这么配,生产环境会用SSL+认证。

3.3.2 使用JConsole连接

启动后,用JConsole连上去:

jconsole 192.168.1.10:9999

你会看到一堆MBean,重点关注这几个:

  • kafka.server:type=BrokerTopicMetrics:消息吞吐量
  • kafka.network:type=RequestMetrics:请求延迟
  • kafka.log:type=LogFlushStats:刷盘情况

3.3.3 用Prometheus+Grafana(推荐)

JConsole只能看单节点,集群大了就不够用了。我后来改用Prometheus + JMX Exporter,效果不错。

# 下载 JMX Exporter
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.17.0/jmx_prometheus_javaagent-0.17.0.jar

# 启动时加上 agent
export KAFKA_OPTS="-javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent-0.17.0.jar=8080:/opt/jmx_exporter/config.yml"

我的经验:JMX Exporter的config.yml里,我一般只采集关键指标,不然Prometheus压力太大。比如只采集BrokerTopicMetrics和RequestMetrics,其他的按需加。

3.4 常见启动问题排查

搭建过程中,你肯定会遇到问题。别慌,我列几个最常见的,你对照着查就行。

3.4.1 端口被占用

错误日志: java.net.BindException: Address already in use

原因:端口被其他进程占了,或者Kafka重复启动了。

解决:

# 查端口
netstat -tlnp | grep 9092
# 杀进程
kill -9 <PID>
# 或者换端口

3.4.2 ZooKeeper连接超时

错误日志: Timeout while connecting to ZooKeeper

原因:ZooKeeper没启动,或者防火墙挡住了2181端口。

解决:

  • 先确认ZooKeeper是否启动:zkServer.sh status
  • 检查防火墙:systemctl stop firewalld(测试环境临时关掉)
  • 检查zookeeper.connect配置是否正确

3.4.3 日志目录权限问题

错误日志: java.io.IOException: No space left on device 或 Permission denied

原因:磁盘满了,或者Kafka用户没权限写日志目录。

解决:

# 检查磁盘
df -h
# 给权限
chown -R kafka:kafka /data/kafka
# 或者换目录

避坑指南:我曾经在生产环境遇到过磁盘写满导致Kafka崩溃的情况。从那以后,我都在监控里加了磁盘使用率告警,超过80%就报警。

3.4.4 broker.id冲突

错误日志: Duplicate broker registration

原因:两个节点用了相同的broker.id。

解决:检查每个节点的server.properties,确保broker.id唯一。如果ZooKeeper里已经注册了旧的broker信息,可以手动清理:

# 连接ZooKeeper
zkCli.sh -server localhost:2181
# 查看broker列表
ls /brokers/ids
# 删除冲突的broker
rmr /brokers/ids/0

注意:清理ZooKeeper节点要小心,别删错了。我建议先备份ZooKeeper数据。

3.4.5 内存不足

错误日志: java.lang.OutOfMemoryError: Java heap space

原因:Kafka默认堆内存只有1G,数据量大时不够用。

解决:修改 kafka-server-start.sh 里的 KAFKA_HEAP_OPTS:

export KAFKA_HEAP_OPTS="-Xmx4G -Xms4G"

我建议根据机器内存来配,一般给机器内存的一半。比如16G内存的机器,给Kafka 8G堆内存。

3.5 验证集群

搭建完了,怎么确认集群正常?我一般做三步验证:

  1. 查看broker列表
/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server 192.168.1.10:9092
  1. 创建测试topic
/opt/kafka/bin/kafka-topics.sh --create --topic test-topic --partitions 3 --replication-factor 2 --bootstrap-server 192.168.1.10:9092
  1. 生产消费测试
# 生产者
/opt/kafka/bin/kafka-console-producer.sh --topic test-topic --bootstrap-server 192.168.1.10:9092
> hello kafka

# 消费者
/opt/kafka/bin/kafka-console-consumer.sh --topic test-topic --from-beginning --bootstrap-server 192.168.1.10:9092
hello kafka

如果能看到消息,说明集群搭建成功了。嗯,到这里,你的Kafka集群已经可以正常工作了。