监控与 lag
consumer lag、JMX、运维直觉。
监控与 lag
这一课你将能做到
- 写出 consumer lag 的公式,说出 lag 持续升高的至少三种常见原因与对应排查动作
- 用
kafka-consumer-groups --describe 读出 CURRENT-OFFSET / LOG-END-OFFSET / LAG,并解释每列含义
- 做一次「消费 sleep 制造积压 → 恢复后 lag 回落」的实验,并写出应用侧该盯的信号清单
为什么要学
Broker 活着 ≠ 业务健康。线上最常见的 Kafka 事故剧本是:生产很快、消费跟不上 → lag 爬升 → 通知延迟从秒变分钟 → 磁盘被日志撑满 → 频繁 rebalance 恶化积压。用户看到的现象只是「邮件晚到一小时」,等你被叫起来排查时,没有 lag 数据就得从应用日志一行行捞。
lag 是 Kafka 世界里第一健康指标:它直接回答「下游还有多少没消化」。本课用 CLI 把 lag 看懂、把积压复现出来;生产环境再把这些数值接进 Prometheus/Grafana 告警(配合你已有的 Spring Boot Actuator 体系)。
人话:lag = 「日记本已经写到第几页」减去「这组读者的书签停在第几页」——差值就是欠账。
先建立图像
Partition P0 日志: .........[newest] LOG-END-OFFSET = 1200(已写到的位置)
Consumer Group 书签:....^ CURRENT-OFFSET = 1000(已消费提交的位置)
LAG = 1200 - 1000 = 200 (还有 200 条没消化)
| 现象 | 可能原因 | 可尝试动作 |
|---|
| 单分区 lag 高 | 热点 key / 分区倾斜 | 查分区键,盐值/拆分 |
| 全组 lag 高 | 整体吞吐不足、下游变慢 | 加实例(≤分区数)、优化处理 |
| lag 锯齿状波动 | 频繁 rebalance | 查心跳超时、GC、慢处理 |
| LAG=0 但业务仍异常 | 消费失败被跳过 / 位点空转 | 看处理错误率与死信 |
跟着做
步骤 1:让组跑起来
按前课跑一个 group.id=coderoadmap-notify-lab 的消费者(Java demo 或 @KafkaListener),并对 Topic 持续生产几条,确认链路通。
步骤 2:describe 读表
docker exec kafka-lab /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group coderoadmap-notify-lab
应看到类似输出(列从左到右):
GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
coderoadmap-notify-lab coderoadmap.order-events 0 12 12 0 consumer-1 /127.0.0.1 ...
coderoadmap-notify-lab coderoadmap.order-events 1 - 3 3 - - -
把一行抄进笔记,逐列用中文标注:GROUP(哪个组)、PARTITION(哪个分区)、CURRENT-OFFSET(书签)、LOG-END-OFFSET(书写位置)、LAG(欠账)、CONSUMER-ID(谁在管;为空 = 没人管)。注意:--describe 不带 --group 会列出所有组。
步骤 3:制造 lag
// 实验:故意拖慢消费,观察 LAG 上升(切勿带进生产)
Thread.sleep(5000);
handle(payload);
同时用 console producer 或 Java 快速发 20 条,再执行步骤 2 的 describe。应看到:LAG 明显变大(3 分区、单实例、每条 5 秒,20 条要近百秒才能追完)。
步骤 4:恢复并观察回落
去掉 sleep,让消费者全力追赶,隔 10 秒 describe 一次。应看到:LAG 逐次下降趋近 0。若生产端仍高速写入,LAG 会稳定在某一水位波动——这说明吞吐刚好持平,也值得记录。
步骤 5:验证「加实例」的效果
先 Ctrl+C 让消费者全部退出,然后只起 1 个实例(3 分区一人扛),快速发 30 条;再补起第 2 个同组实例,describe 观察 CONSUMER-ID 列:分区重新分配、追赶速度近乎翻倍。这就是「扩展上限 = 分区数」的实操版。
步骤 6:应用侧指标入口(概念)
# Spring Boot Actuator / Micrometer 打标
management:
endpoints:
web:
exposure:
include: health,prometheus
metrics:
tags:
application: coderoadmap-api
生产清单:应用侧看监听器处理耗时、失败计数(kafka_listener_seconds / errors);集群侧用 Kafka Exporter 暴露 kafka_consumergroup_lag 到 Prometheus,Grafana 画 lag 曲线。与 Redis 监控(命中率、慢命令)不同:Kafka 健康叙事的中心是积压与再平衡。
讲清楚要点
- 因为LAG = LOG-END-OFFSET − CURRENT-OFFSET,所以它是消费落后量的直接度量,是第一告警候选。
- 因为追平后 LAG≈0 也可能是「两端都停了」,所以判断健康要结合生产速率与业务延迟(消息从产生到处理完的耗时),而不是只盯绝对值。
- 因为热点 key 会打满单分区,所以「总实例很多但单分区 lag 爆」先查分区键分布,而不是盲目加机器——机器救不了倾斜。
- 因为消费者数超过分区数无效,所以扩容顺序永远是:先优化处理耗时 → 加实例到分区数 → 再考虑加分区。
- 因为rebalance 会整组暂停消费,所以频繁平衡本身造成假性 lag 尖峰;先看 rebalance 频率再解读 lag 曲线。
- 因为位点前进 ≠ 业务成功,所以要同时盯「失败计数/死信量」:位点在走、错误率飙升,LAG 好看但业务全挂。
你可能会懵的地方
-
「LAG=0 就一定健康?」
不一定。生产也停了、消费全失败但位点照常推进(取决于提交策略),都能让 LAG 归零。搭配生产速率指标与错误率一起看。
-
「为什么只有某个分区 lag 高?」
该分区的 key 有热点(大客户、固定字符串 key 全打一个分区)。查 --describe 里该分区对应 CONSUMER-ID 的处理耗时,回生产者侧改 key 策略。
-
「describe 里 CONSUMER-ID 是空的?」
该分区没有活着的消费者(进程退了、或组只剩位点没有成员)。空组也能显示 LAG,但那是「欠账没人还」。先确认进程在线。
-
「和 MySQL 慢查询什么关系?」
消费里同步写库时二者耦合:慢查询拖慢消费 → lag 上涨。用「listener 处理耗时」指标把两层拆开:处理慢 → 修 SQL;处理快但 lag 高 → 修并行度。
-
「告警阈值设多少?」
不要「LAG>0 就报警」(微延迟是常态)。按持续时长 + 绝对量 + 增长趋势:如「lag > 10000 且持续 5 分钟」或「lag 每分钟净增 > 1000」。核心是捕捉「追不上」的趋势,不是瞬时波动。
错法对照
| 错法 | 问题 | 正解 |
|---|
| 只看 Broker CPU,不看 consumer lag | Broker 空闲但下游积压成灾 | 组 LAG 纳入常规巡检/大屏 |
| lag 高就无脑加到 30 个消费者(3 分区) | 超出分区数的实例全空转 | 先加到 ≤ 分区数,再评估加分区 |
| 处理里同步调 10s 慢 HTTP 还怪 Kafka | 消费被下游拖死 | 异步化/优化处理,监控 listener 耗时 |
| 告警「LAG>0 立刻打电话」 | 瞬时波动制造告警疲劳 | 持续时长 + 绝对阈值 + 增长趋势 |
| LAG=0 就宣布恢复 | 可能两端都停/全在报错 | 结合生产速率与失败率判断 |
卡点急救
- describe 报
Consumer group ... does not exist:组还没有任何成员提交过位点(从没跑过消费者)。先起消费者跑一轮,或确认组名拼写。
- LAG 高但看不出谁在消费:CONSUMER-ID 为空 → 消费者死了或卡在 rebalance。查应用日志(
rebalance 关键字)、GC 日志,必要时重启实例观察重新入组。
- 磁盘被撑爆:Topic retention 过长或生产暴涨。临时:扩磁盘 + 清理过期段(
retention.ms);长期:按流量规划保留策略与容量告警(磁盘使用率 80% 预警)。
面试常问
-
什么是 consumer lag?怎么监控和治理?
LAG = LOG-END-OFFSET(分区最新位点)− CURRENT-OFFSET(组已提交位点),即未消费量。监控:kafka-consumer-groups --describe 手动看,或 Kafka Exporter + Prometheus 持续采集 kafka_consumergroup_lag。治理三板斧:优化消费逻辑耗时(先做)→ 扩实例到分区数上限 → 扩分区;同时查热点 key 与下游依赖(DB/HTTP)是否拖慢。
-
你怎么设计 Kafka 的告警?
分层:①积压类——组 LAG 超阈值且持续 N 分钟、或净增速率为正且超速;②错误类——消费失败率、死信 Topic 新增消息;③基础设施——Broker 存活数、磁盘使用率、ISR 收缩(UnderReplicatedPartitions>0);④业务端到端——事件产生到处理完成的延迟 SLO。避免单点瞬时阈值制造告警疲劳。
-
UnderReplicatedPartitions 指标说明什么?
有分区的副本落后于 Leader 不在 ISR 里。可能原因:某 Broker 负载高/磁盘慢/网络抖动/Broker 宕机。它是集群健康的关键指标:URP 持续 > 0 说明副本冗余正在失效,此时再挂一台就可能丢数据或不可用。
自测三问
- 用自己的话写 LAG 公式,并解释 CURRENT-OFFSET 与 LOG-END-OFFSET 分别是谁的位置。
- 处理里 sleep 5s + 快发 20 条后,LAG 应如何变化?恢复后呢?
- 单分区 lag 高与全组 lag 高:排查顺序有何不同?
小结一句话
Lag 是消费健康的晴雨表:会 describe --group 读三列位点、会复现积压与回落、会分层设计告警,监控入门即过关。
延伸