订阅更新

Kafka 消息积压了,你怎么排查?

面试问 004 约 6 分钟读完 4 次阅读

本文目录
  1. 面试怎么回答
  2. 第一步:先确认是不是真的在持续积压
  3. 第二步:看 Lag 是整体增长,还是集中在少数 Partition
  4. 第三步:沿着消费链路找第一个变慢的位置
  5. 第四步:根据根因选择处理方式
  6. 一个典型场景
  7. 为什么增加消费者不一定有效?

面试怎么回答

我会先看 Consumer Group 的 Lag 趋势和 Partition 分布,判断是整体积压还是少数分区积压,并对比生产、消费速率。然后检查 Group 成员和分区分配,确认是否有 Consumer 异常退出或频繁 Rebalance。接着按拉取、业务处理、下游 IO、Offset 提交拆开定位瓶颈:全部分区慢重点查整体能力和下游,少数分区慢重点查热点 key。最后再决定优化代码、批量或异步处理、治理热点,还是在 Partition 数允许范围内增加 Consumer,而不是看到 Lag 就直接扩容。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

很多人一上来就回答:

  • 增加消费者
  • 增加分区
  • 调大消费参数

这些方法有时候确实有效。

但如果只回答这些,面试官很可能会继续追问:

你怎么判断是消费能力不足,而不是数据倾斜、下游变慢或者 Consumer 一直在 Rebalance?

因为消息积压只是一个结果。

真正有价值的排查思路是:

先看 Lag 怎么增长、集中在哪些 Partition,再沿着消费链路定位第一个变慢的位置。


第一步:先确认是不是真的在持续积压

排查时,不要只看某一刻的 Lag 数字。

先看三个问题:

  • Lag 是持续上升、保持稳定,还是已经开始下降?
  • 是所有 Partition 都在涨,还是只有少数 Partition 在涨?
  • 是生产流量突然增加,还是消费吞吐突然下降?

可以先查看 Consumer Group 的消费位置:

bin/kafka-consumer-groups.sh \
  --bootstrap-server <broker> \
  --describe \
  --group <consumer-group>

重点关注 CURRENT-OFFSET、LOG-END-OFFSET 和 LAG,同时结合生产速率、消费速率观察趋势。

如果 Lag 很大,但正在持续下降,说明系统已经具备追平能力,只是还需要时间。

如果 Lag 持续上升,才说明当前消费能力长期低于生产速度。


第二步:看 Lag 是整体增长,还是集中在少数 Partition

Lag 的分布,往往能直接缩小排查范围。

所有 Partition 都在积压

更像是消费者整体处理能力不足,例如:

  • 消费实例数量减少
  • CPU 或 GC 出现瓶颈
  • 单条消息处理逻辑变慢
  • 数据库、接口等下游系统响应变慢

只有少数 Partition 积压

更像是分区数据不均匀。

例如热点 key、默认值或者某个大客户的数据集中进入少数 Partition。此时即使增加消费者,热点 Partition 仍然只能由一个 Consumer 实例处理,积压不一定会缓解。

Consumer 数量变少或频繁变化

要重点查看 Group 状态、成员数量和 Partition 分配情况。

如果 Consumer 频繁退出、加入,或者 Group 长时间不稳定,就要继续排查异常重启、心跳超时、处理时间过长和 Rebalance。

Kafka Lag 分布与排查方向


第三步:沿着消费链路找第一个变慢的位置

一条完整的消费链路通常是:

拉取消息 → 反序列化 → 业务处理 → 调用外部服务 → 提交 Offset

排查时要把每一段拆开看。

拉取阶段

检查网络、Broker 响应、单次拉取量和消息大小,确认 Consumer 是否能正常拿到数据。

业务处理阶段

检查 CPU、GC、线程池、锁等待、异常重试以及单条消息处理耗时。

如果一次 poll() 返回的数据处理时间过长,下一次 poll() 迟迟没有执行,超过 max.poll.interval.ms 后,Consumer 可能被认为失效并触发重新分配。

下游写入阶段

数据库慢 SQL、连接池耗尽、接口限流、批量写入过小,都可能让 Consumer 表面上“消费慢”。

这时 Kafka 只是积压发生的地方,真正的瓶颈在下游。

提交 Offset 阶段

检查 Offset 是否正常推进,以及提交失败、重复消费、异常重试是否让处理链路反复回退。

不要只通过“Offset 没变化”判断 Consumer 没有工作,也要确认它是在处理、阻塞,还是提交失败。


第四步:根据根因选择处理方式

定位根因后,再决定怎么处理。

整体消费能力不足

先优化处理逻辑、批量大小和线程模型,再在 Partition 数允许的范围内增加 Consumer 实例。

少数 Partition 热点

检查分区 key,拆分热点数据,或者重新设计分区策略。增加普通 Consumer 无法拆开一个已经存在的热点 Partition。

下游 IO 变慢

考虑批量写入、异步处理、限流和降级,同时确认数据库或接口本身的容量。不要用更多 Consumer 把压力继续放大到下游。

Consumer 不稳定

排查异常重启、长时间处理、心跳和 Rebalance。结合单批处理耗时合理设置 max.poll.records 与 max.poll.interval.ms,但参数调整不能代替代码和下游优化。

如果积压已经影响时效,还要同时评估消息保留时间,确保数据不会在追平之前过期删除。


一个典型场景

比如一个 Consumer 从 Kafka 读取订单消息,处理后调用外部接口。

监控发现所有 Partition 的 Lag 都在上涨,于是第一反应是增加 Consumer 实例。

扩容后,Lag 只短暂下降,很快又继续增长,Group 还频繁发生 Rebalance。

继续看日志和调用耗时,才发现外部接口响应变慢,一批消息处理时间过长,导致 Consumer 长时间没有再次执行 poll()。

这种情况下,根因不是 Kafka 吞吐不足,而是外部 IO 把消费线程拖住了。

真正的处理方向应该是:

优化接口调用和批量策略 → 隔离慢请求 → 控制单批处理时间 → 再根据 Partition 数评估是否扩容。


为什么增加消费者不一定有效?

因为 Kafka 的消费并行度受到 Partition 数限制。

同一个 Consumer Group 内,一个 Partition 在同一时间只会分配给一个 Consumer。Consumer 数量超过 Partition 数后,多出来的实例不会获得有效分区。

而且,如果瓶颈是:

  • 单个热点 Partition
  • 数据库达到写入上限
  • 外部接口正在限流
  • Consumer 频繁 Rebalance

继续增加 Consumer 也无法解决根因,甚至可能加重下游压力和 Group 波动。

所以最关键的问题不是“要不要扩容”,而是:

Lag 为什么在增长,具体是哪一段处理能力跟不上?


刷题进度保存在当前浏览器