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,两周磁盘就满了。嗯,这里要注意:保留策略要按业务评估,别拍脑袋

我的建议:生产环境至少同时设置时间和大小两个维度。比如「保留 3 天,且不超过 100GB」,哪个先到就删哪个。

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
注意:compact 不是实时清理的,后台线程每隔 log.cleaner.backoff.ms(默认 15 秒)才跑一次。别指望改了策略立刻见效。

4.2 分区重分配:让负载均匀起来

集群跑久了,分区分布肯定不均匀。新加 broker 后,旧 broker 上的分区不会自动挪过去。这时候就需要手动做分区重分配。

4.2.1 什么时候需要重分配?

  • 新增 broker,想把部分分区挪过去。
  • 某个 broker 磁盘快满了,需要把分区移走。
  • 集群整体负载不均,某些 broker CPU 高、网络带宽吃紧。

4.2.2 手动重分配步骤

我一般用 kafka-reassign-partitions.sh 这个工具。流程分三步:

  1. 生成分配方案:指定 topic 和 broker 列表,工具会推荐一个均匀分布。
  2. 执行分配:把方案文件传进去,开始挪数据。
  3. 验证结果:检查是否完成。
# 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 生产者超时或写入失败

现象:生产者报 TimeoutExceptionNotLeaderForPartitionException

排查步骤

  1. 先看 broker 的 CPU 和内存,是不是负载过高。
  2. 检查 RequestQueueSize,如果队列积压,说明 broker 处理不过来。
  3. 看网络带宽,是不是被重分配或备份流量占满了。
  4. 检查分区 Leader 是否正常,用 kafka-topics.sh --describe 看。

我曾经遇到一个 case,生产者一直超时,查了半天发现是磁盘 IO 被打满了。原来有个 topic 的 retention 设得太短,后台清理线程疯狂删文件,把磁盘 IO 吃光了。

4.4.2 消费者组重平衡频繁

现象:消费者频繁报 RebalanceInProgress,消费速率骤降。

原因

  • 消费者心跳超时(session.timeout.ms 太短)。
  • 消费者处理消息太慢,超过了 max.poll.interval.ms
  • 消费者实例频繁加入或退出。

解决办法

  • 调大 session.timeout.msmax.poll.interval.ms
  • 减少单次拉取的消息数(max.poll.records)。
  • 检查消费者代码,是不是有慢查询或阻塞操作。
我的经验:重平衡最怕「雪崩效应」。一个消费者挂了,触发重平衡,其他消费者也要停掉处理逻辑,导致整体吞吐下降。我一般把 session.timeout.ms 设成 30 秒以上,给消费者留足缓冲时间。

4.4.3 磁盘空间不足

现象:broker 日志报 java.io.IOException: No space left on device

紧急处理

  1. 立即调小 log.retention.hours,比如从 7 天改成 1 天。
  2. 手动删除一些不重要的 topic 日志(慎用!)。
  3. 如果还不行,临时扩容磁盘或加 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 监控一定要配全,故障排查要有套路。嗯,这些经验都是我用加班和事故换来的,希望能帮你少踩几个坑。