4、Kafka运维与监控:Kafka Broker日志管理、分区重分配、使用JMX监控Kafka集群、常见故障排查
Kafka 跑起来容易,但想让它稳稳当当跑上一年不出事,那才是真功夫。我见过太多团队,集群搭好就撒手不管,结果某天半夜 broker 挂了,数据写不进去,全公司等着修。今天咱们就聊聊运维里最核心的几件事:日志怎么管、分区怎么挪、监控怎么搭、故障怎么查。
4.1 Broker 日志管理:别让磁盘撑爆了
Kafka 的日志,说白了就是消息文件。每个分区对应一个目录,里面一堆 .log、.index、.timeindex 文件。时间一长,磁盘空间就告急。
4.1.1 日志保留策略
我个人习惯,先定好保留策略。Kafka 支持三种:
- 基于时间:
log.retention.hours,默认 168 小时(7 天)。 - 基于大小:
log.retention.bytes,按分区算,默认 -1(不限)。 - 基于起始偏移量:配合日志压缩(compact)使用。
我在项目中遇到过,某团队把 retention 设成 30 天,结果 topic 日增 500GB,两周磁盘就满了。嗯,这里要注意:保留策略要按业务评估,别拍脑袋。
4.1.2 日志段(Log Segment)管理
Kafka 不是一条条删消息的,而是删整个段文件。log.segment.bytes 控制每个段的大小,默认 1GB。段越小,清理越频繁,但文件数也多。
我曾经调过一个小集群,把 segment 改成 256MB,结果 broker 上文件数暴增,打开文件句柄不够用。后来改回 1GB,世界清净了。
4.1.3 日志清理与压缩
Kafka 有两种清理策略:delete(删除过期段)和 compact(保留每个 key 的最新值)。
举个例子,你有个 topic 存用户信息,key 是用户 ID,value 是资料。用 compact 策略,Kafka 会保留每个用户的最新记录,旧版本自动清理。这招在「变更数据捕获」场景里特别好用。
# 设置 topic 为 compact 模式
bin/kafka-topics.sh --alter --topic user-info \
--config cleanup.policy=compact \
--bootstrap-server localhost:9092
log.cleaner.backoff.ms(默认 15 秒)才跑一次。别指望改了策略立刻见效。
4.2 分区重分配:让负载均匀起来
集群跑久了,分区分布肯定不均匀。新加 broker 后,旧 broker 上的分区不会自动挪过去。这时候就需要手动做分区重分配。
4.2.1 什么时候需要重分配?
- 新增 broker,想把部分分区挪过去。
- 某个 broker 磁盘快满了,需要把分区移走。
- 集群整体负载不均,某些 broker CPU 高、网络带宽吃紧。
4.2.2 手动重分配步骤
我一般用 kafka-reassign-partitions.sh 这个工具。流程分三步:
- 生成分配方案:指定 topic 和 broker 列表,工具会推荐一个均匀分布。
- 执行分配:把方案文件传进去,开始挪数据。
- 验证结果:检查是否完成。
# 1. 生成方案
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--topics-to-move-json-file topics.json \
--broker-list "0,1,2,3" \
--generate > plan.json
# 2. 执行
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--reassignment-json-file plan.json \
--execute
# 3. 验证
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--reassignment-json-file plan.json \
--verify
避坑指南:我曾经在高峰期执行重分配,结果网络带宽被打满,业务延迟飙升。后来学乖了,重分配一定要在低峰期做,或者限速。
4.2.3 限速重分配
Kafka 支持重分配限速,通过 --throttle 参数控制。单位是 bytes/s。
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--reassignment-json-file plan.json \
--execute --throttle 104857600 # 限速 100MB/s
限速后,重分配时间会拉长,但至少不影响线上业务。我个人习惯限到总带宽的 30% 左右。
4.3 使用 JMX 监控 Kafka 集群
Kafka 本身暴露了大量 JMX 指标,但默认没开。你得在启动脚本里加上参数。
4.3.1 开启 JMX
在 bin/kafka-server-start.sh 里,找到 export KAFKA_HEAP_OPTS,加上 JMX 配置:
export KAFKA_HEAP_OPTS="-Xmx4G -Xms4G"
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.100"
authenticate=false,至少配个用户名密码。不然谁连上 JMX 都能看到你的集群状态。
4.3.2 关键监控指标
我平时重点盯这几个指标:
| 指标名称 | MBean 路径 | 说明 |
|---|---|---|
| 消息入站速率 | kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec |
每秒写入的消息数 |
| 字节入站速率 | kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec |
每秒写入的字节数 |
| 请求队列大小 | kafka.network:type=RequestChannel,name=RequestQueueSize |
待处理的请求数,超过 100 说明 broker 扛不住了 |
| 分区 Leader 数量 | kafka.controller:type=KafkaController,name=LeaderElectionRateAndTimeMs |
Leader 选举频率,频繁选举说明集群不稳定 |
| 磁盘使用率 | java.lang:type=OperatingSystem 或系统级监控 |
磁盘满了 broker 会挂 |
你想想看,如果 RequestQueueSize 一直涨,说明 broker 处理不过来。这时候要么加机器,要么优化生产者 batch 大小。
4.3.3 集成 Prometheus + Grafana
JMX 指标直接用 jconsole 看太原始了。我习惯用 Prometheus 的 jmx_exporter 来抓取,然后扔到 Grafana 里展示。
# jmx_exporter 配置示例
startDelaySeconds: 0
hostPort: localhost:9999
username:
password:
rules:
- pattern: "kafka.server<>Count"
name: "kafka_$1"
type: GAUGE
配上 Grafana 的仪表盘,一眼就能看出集群健康度。我个人习惯把「请求队列大小」和「磁盘使用率」放在最显眼的位置。
4.4 常见故障排查
运维嘛,不出事是运气,出了事能快速定位才是本事。我总结几个高频故障。
4.4.1 生产者超时或写入失败
现象:生产者报 TimeoutException 或 NotLeaderForPartitionException。
排查步骤:
- 先看 broker 的 CPU 和内存,是不是负载过高。
- 检查
RequestQueueSize,如果队列积压,说明 broker 处理不过来。 - 看网络带宽,是不是被重分配或备份流量占满了。
- 检查分区 Leader 是否正常,用
kafka-topics.sh --describe看。
我曾经遇到一个 case,生产者一直超时,查了半天发现是磁盘 IO 被打满了。原来有个 topic 的 retention 设得太短,后台清理线程疯狂删文件,把磁盘 IO 吃光了。
4.4.2 消费者组重平衡频繁
现象:消费者频繁报 RebalanceInProgress,消费速率骤降。
原因:
- 消费者心跳超时(
session.timeout.ms太短)。 - 消费者处理消息太慢,超过了
max.poll.interval.ms。 - 消费者实例频繁加入或退出。
解决办法:
- 调大
session.timeout.ms和max.poll.interval.ms。 - 减少单次拉取的消息数(
max.poll.records)。 - 检查消费者代码,是不是有慢查询或阻塞操作。
session.timeout.ms 设成 30 秒以上,给消费者留足缓冲时间。
4.4.3 磁盘空间不足
现象:broker 日志报 java.io.IOException: No space left on device。
紧急处理:
- 立即调小
log.retention.hours,比如从 7 天改成 1 天。 - 手动删除一些不重要的 topic 日志(慎用!)。
- 如果还不行,临时扩容磁盘或加 broker。
说白了,磁盘监控一定要提前做。我习惯在磁盘使用率达到 70% 就报警,85% 就自动触发清理脚本。
4.4.4 Controller 频繁切换
现象:集群中多个 broker 轮流当 Controller,日志里一堆 LeaderElection 记录。
原因:ZooKeeper 连接不稳定,或者 Controller 所在的 broker 负载过高。
排查:
- 检查 ZooKeeper 集群的健康状态。
- 看 Controller broker 的 CPU 和内存。
- 检查网络延迟,Controller 和 ZooKeeper 之间不能有高延迟。
我记得有一次,Controller 每 5 分钟切换一次,查到最后发现是 ZooKeeper 的一台机器磁盘坏了,导致写操作超时。换了磁盘后,一切恢复正常。
4.5 小结
Kafka 运维,说白了就是管好日志、控好分区、盯好指标、备好预案。日志策略别设太死,分区重分配别在高峰期搞,JMX 监控一定要配全,故障排查要有套路。嗯,这些经验都是我用加班和事故换来的,希望能帮你少踩几个坑。