跳到正文

Kafka 监控指标与告警 ​

一句话:Kafka 的告警要同时看数据面和控制面——副本与 ISR 决定还能不能安全写,Controller/KRaft quorum 决定还能不能选主和改元数据,lag 只是最后表现出来的结果。

适用版本:Kafka 3.9 / 4.0。4.0 起仅支持 KRaft,3.9 是最后一个支持 ZooKeeper 的版本。指标名、MBean 路径和默认值以官方文档为准;阈值只是起点,按自己的基线校准。

相关:01-架构与ISR、03-消费者与可靠性、05-Kafka生产踩坑。

为什么需要 ​

Kafka 的故障常常是「静默」的:生产者开着重试,消费者 lag 在涨,业务侧只看到延迟变大;等应用开始报错,副本冗余可能早就没了。acks=all 在 ISR 不足时拒写,这是保护,不是故障本身;如果等到拒写才告警,已经失去了提前处置的窗口。

监控要回答三个问题:副本还够不够、控制面还有没有人负责、消费还能不能追上。三个问题的指标不同,处置顺序也不同。

核心机制 ​

四个观察面 ​

观察面主要指标(JMX/MBean)反映什么恶化后的先兆
副本kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions、UnderMinIsrPartitionCount、IsrShrinksPerSec/IsrExpandsPerSec副本是否齐全、ISR 是否在收缩冗余丢失,下一步就是拒写
分区可用性kafka.controller:type=KafkaController,name=OfflinePartitionsCount有没有分区没有 Leader生产、消费直接失败
控制面KafkaController,name=ActiveControllerCount、ControllerStats,name=LeaderElectionRateAndTimeMs、KRaft quorum元数据操作是否有人负责建 Topic、选主、重分配卡住
请求处理KafkaRequestHandlerPool,name=RequestHandlerAvgIdlePercent、SocketServer,name=NetworkProcessorAvgIdlePercent、DelayedOperationPurgatory,name=PurgatorySize请求线程和延迟操作是否排队延迟上升、超时、重试放大
流量BrokerTopicMetrics,name=MessagesInPerSec、BytesInPerSec、BytesOutPerSec负载大小与方向只作背景,不单独判故障
消费kafka-consumer-groups.sh 的 LAG;客户端 records-lag-max消费是否跟上积压、下游变慢
存储kafka.log:type=LogManager,name=OfflineLogDirectoryCount(部分面板叫 LogDirOffline)、LogFlushRateAndTimeMs、磁盘使用率日志目录和刷盘分区 offline
资源JVM GC、fd、网络进程是否停顿心跳和副本复制超时

消费 lag 不是 Broker 的 JMX 指标,要从消费组命令、客户端指标或 kafka_exporter 取。把 lag 当成「Broker 健康度」会误判:Broker 一切正常,消费者也可能因为下游慢而积压。

链一:ISR 收缩 → 低于 minISR → 拒写 → 重试放大 ​

Follower 的复制进度落后超过 replica.lag.time.max.ms=30000(3.x 默认)就被移出 ISR,UnderReplicatedPartitions 大于 0。此时如果 ISR 数量仍然大于等于 min.insync.replicas,分区还能写,只是冗余在减少。

一旦 ISR 小于 min.insync.replicas(Broker 默认 1,RF=3 时通常设 2),acks=all 的生产者会收到 NotEnoughReplicas / NotEnoughReplicasAfterAppend。这是 Kafka 用「拒写」换「不丢数据」:宁可不可写,也不让少数派副本接管。

生产者的重试会继续打同一批分区,RequestHandlerAvgIdlePercent 下降、PurgatorySize 上升;请求排队又让 Follower 的 fetch 更慢,ISR 继续收缩。这条链的入口不是 lag,而是副本复制速度和请求处理余量。

链二:磁盘满 → 分区离线 → 消费停滞 ​

日志目录写满后,Broker 无法追加,分区可能变成 offline,OfflinePartitionsCount 大于 0。生产端失败、消费端取不到数据,上游重试继续放大压力。

保留策略按整段删除,retention.ms 调小后不会立刻释放空间;活跃 Segment 也不会被删。所以磁盘告警必须在 70% 左右就开始处理,不能等到写失败。OfflineLogDirectoryCount 大于 0 说明目录已经不可用,通常伴随挂载、权限或磁盘故障。

链三:rebalance 风暴 → lag 暴涨 ​

消费者在 rebalance 期间停止消费。单次 poll() 处理超过 max.poll.interval.ms=300000、session.timeout.ms=45000 内没心跳、滚动发布没配 group.instance.id、eager 与 cooperative 分配策略混用,都会让成员反复进出。

成员一变,分区重新分配,lag 在短时间内跳升;上游看到积压又加消费者,继续触发 rebalance。重启消费者不是恢复手段,它本身就是一次成员变更。

链四:控制面失联 ​

各 Broker 的 ActiveControllerCount 之和应为 1。为 0 表示没有 Controller,建 Topic、分区重分配、Leader 选举都卡住;大于 1 在 ZooKeeper 模式下意味着脑裂风险。数据面可能还在跑,但故障一旦发生就无法自动恢复。

KRaft 下用 kafka-metadata-quorum.sh describe --status 看 LeaderId、HighWatermark、CurrentVoters;LeaderId=-1 或 HighWatermark 不再推进,说明元数据提交停了。describe --replication 能看到每个 voter 的 Lag。

指标怎么串起来读 ​

先看 OfflinePartitionsCount 和 UnderMinIsrPartitionCount:大于 0 是「已经不可用/不可写」。再看 UnderReplicatedPartitions:大于 0 但未低于 minISR,是「还能写,冗余在丢」。最后看请求侧 RequestHandlerAvgIdlePercent、NetworkProcessorAvgIdlePercent 和 PurgatorySize,判断是容量问题还是副本问题。MessagesInPerSec 只用来解释负载背景。

最小上手 ​

bash
bin/kafka-topics.sh --bootstrap-server localhost:9092 \
  --describe --topic orders
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
  --describe --group order-worker
bin/kafka-log-dirs.sh --bootstrap-server localhost:9092 \
  --describe --topic-list orders
# KRaft 控制面(地址按 controller listener 替换)
bin/kafka-metadata-quorum.sh --bootstrap-controller localhost:9093 \
  describe --status

JMX 用 jmx_prometheus_javaagent 暴露到 9404:

bash
export KAFKA_OPTS="-javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=9404:/opt/jmx_exporter/kafka.yml"
bin/kafka-server-start.sh -daemon config/kraft/server.properties
yaml
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
  - pattern: 'kafka\.(server|controller|network|log)<type=([^,>]+), name=([^,>]+)><>(\w+)'
    name: 'kafka_$1_$2_$3_$4'
    type: GAUGE

规则决定最终指标名;带 delayedOperation=... 的 Purgatory 等复合 MBean 要另加带 labels 的规则。先用 curl -s localhost:9404/metrics | grep -E 'underreplicated|offlinepartitions|activecontroller' 确认,再写告警。

常见 PromQL(前三行按上面的规则生成,最后一行来自 kafka_exporter,按实际调整):

promql
sum(kafka_server_replicamanager_underreplicatedpartitions_value) > 0
sum(kafka_controller_kafkacontroller_offlinepartitionscount_value) != 0
sum(kafka_controller_kafkacontroller_activecontrollercount_value) != 1
sum by (consumergroup) (kafka_consumergroup_lag) > 10000

生产动作 ​

以下阈值均为起点,按基线校准;告警要带 Topic、分区和 Broker 维度。

告警条件级别先做什么
副本不足UnderReplicatedPartitions > 0 持续 5mP1查掉队 Broker 的磁盘、GC、网络
低于 minISRUnderMinIsrPartitionCount > 0P0写入已被拒;恢复副本或切流,别先调大 lag 阈值
分区离线OfflinePartitionsCount > 0P0查 Leader 存活、磁盘、日志目录
控制面异常ActiveControllerCount 之和不为 1;KRaft LeaderId=-1 或 HW 不推进P0先恢复 quorum,不要重启全部 Controller
ISR 抖动IsrShrinksPerSec 持续大于 IsrExpandsPerSec;Leader 选举速率高于基线P1查网络、GC、单条大消息和 replica.fetch.max.bytes
请求饱和RequestHandlerAvgIdlePercent < 20% 或 NetworkProcessorAvgIdlePercent < 30% 持续 5mP1限流非核心生产或扩 Broker,不要先重启
Purgatory 堆积Produce/Fetch 的 PurgatorySize 持续增长P1对应 ISR 或 fetch 问题,先查副本
消费 lagLAG 超过阈值且 10m 斜率向上P1/P2扩消费者到分区数,再查 key 倾斜和下游
磁盘/目录使用率大于 70% 预警、大于 85% 严重;OfflineLogDirectoryCount > 0P1/P0降 retention、扩盘或迁分区;不删活跃 Segment
GCFull GC 停顿大于 1s 或老年代大于 80%P1调堆、查泄漏;GC 会触发心跳和副本超时

先扩容/限流还是先重启:

  • ISR 仍大于等于 minISR、OfflinePartitionsCount=0:还能写,优先限流非核心生产、查掉队 Broker,不要重启 Leader。
  • ISR 小于 minISR 或已有分区 offline:已经不可写/不可用,先恢复副本、磁盘或切流;重启 Broker 不会让磁盘变空,也不会让副本自动追上。
  • 请求线程饱和但副本健康:限流或扩 Broker/分区;重启只会让请求重新排队。
  • 消费 lag:先把消费者扩到分区数(不能超过),再优化单条处理;不要用 --reset-offsets --to-latest 消 lag。
  • rebalance 风暴:修 max.poll.interval.ms、静态成员和分配策略;不要靠反复重启消费者恢复。

边界 ​

Kafka 的优势是分区顺序写、PageCache + sendfile 零拷贝、高吞吐和可回放日志;Connect、Streams、Flink 生态让它适合做事件总线和流式管道。副本机制在 RF=3、minISR=2、acks=all 下能给出明确的持久性边界。

代价是并行度被分区数锁死:分区只能增不能减,扩分区会改变 key 落点;rebalance 有停顿成本;副本复制、Controller/KRaft quorum 和磁盘保留都需要专门运维。它不擅长低延迟点对点调用,也不擅长复杂路由、任意延迟消息和业务级事务;这些场景 RocketMQ 更合适。

扬长避短的做法:用 Kafka 承载高吞吐、可回放、按 key 有序的流;分区数按目标消费者数和吞吐一次规划;核心 Topic 固定 RF=3、minISR=2;监控按分区和 Broker 展开,不要只看集群总量;业务消息的延迟、事务、过滤需求交给 RocketMQ 或应用层实现。

讲清楚 ​

Kafka 的告警先分数据面和控制面。数据面看副本:URP 持续大于零说明冗余在丢,ISR 缩到 min.insync.replicas 以下时 acks=all 会拒写,这是保护;上游一重试,请求队列和 Purgatory 就堆,延迟更高又逼更多 Follower 掉队。消费面看 lag 斜率和 rebalance,重启消费者只会再触发一次重平衡。控制面看 ActiveControllerCount 是否恰好为一、KRaft quorum 有没有 Leader、HighWatermark 是否推进;控制面挂了,建 Topic 和选主都会停。磁盘满会让分区 offline,先降 retention、扩盘或迁分区,别删活跃 Segment。Kafka 强在分区顺序写和高吞吐,代价是并行度受分区数约束、rebalance 和副本运维成本高;延迟消息、事务和复杂路由交给 RocketMQ。

把一门技术讲透到既懂也会用