3. Kafka集群搭建:从单机到生产环境
搭建Kafka环境,是每个入门者必须跨过的第一道坎。说实话,我见过太多人在这一步踩坑了——不是配置文件写错,就是启动时莫名其妙报错。这一章,我会把单机搭建、集群部署、JMX监控以及常见问题排查,一次性讲清楚。
本章核心脉络:单机环境 → 集群配置 → 监控开启 → 问题排查。每一步都是下一环的基础,别跳着看。
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 安装步骤
- 下载解压
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
- 配置ZooKeeper
# /opt/zookeeper/conf/zoo.cfg
tickTime=2000
dataDir=/data/zookeeper
clientPort=2181
maxClientCnxns=60
- 启动ZooKeeper
/opt/zookeeper/bin/zkServer.sh start
- 配置Kafka
# /opt/kafka/config/server.properties
broker.id=0
listeners=PLAINTEXT://localhost:9092
log.dirs=/data/kafka/logs
zookeeper.connect=localhost:2181
- 启动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 验证集群
搭建完了,怎么确认集群正常?我一般做三步验证:
- 查看broker列表
/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server 192.168.1.10:9092
- 创建测试topic
/opt/kafka/bin/kafka-topics.sh --create --topic test-topic --partitions 3 --replication-factor 2 --bootstrap-server 192.168.1.10:9092
- 生产消费测试
# 生产者
/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集群已经可以正常工作了。