用单节点 Kafka 和慢消费者制造消费积压,练习按分区判断 lag 与扩容边界

演练目标

环境准备

安装 Docker,本机 9092 端口空闲。使用 Apache Kafka 官方镜像的单节点 KRaft 默认配置。

docker run -d --name lab-kafka -p 9092:9092 apache/kafka:3.7.0
for i in $(seq 1 60); do
  docker exec lab-kafka /opt/kafka/bin/kafka-topics.sh \
    --bootstrap-server localhost:9092 --list >/dev/null 2>&1 && break
  sleep 2
done
docker exec lab-kafka /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server localhost:9092 --create --if-not-exists \
  --topic lab-lag --partitions 3 --replication-factor 1

如果 60 秒内没有就绪,先看 docker logs lab-kafka,不要继续灌数据。

注入故障

写入 2 万条带 key 的消息,让数据分散到 3 个分区:

seq 1 20000 | awk '{print "k"$1":v"$1}' | \
  docker exec -i lab-kafka /opt/kafka/bin/kafka-console-producer.sh \
    --bootstrap-server localhost:9092 --topic lab-lag

然后用一个消费者组只消费 100 条就停止,模拟消费能力远低于生产速度:

docker exec lab-kafka /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 --topic lab-lag --group lab-group \
  --from-beginning --max-messages 100 \
  --consumer-property enable.auto.commit=true \
  --consumer-property auto.commit.interval.ms=500
sleep 2

观察现象

docker exec lab-kafka /opt/kafka/bin/kafka-consumer-groups.sh \
  --bootstrap-server localhost:9092 --describe --group lab-group
docker exec lab-kafka /opt/kafka/bin/kafka-consumer-groups.sh \
  --bootstrap-server localhost:9092 --describe --group lab-group --members --verbose
docker exec lab-kafka /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server localhost:9092 --describe --topic lab-lag

预期 --describe 输出 TOPIC、PARTITION、CURRENT-OFFSET、LOG-END-OFFSET、LAG 五列,3 个分区的 LAG 之和接近 2 万(100 条位点已提交时约为 19900);--members 显示当前活跃消费者,本例消费者已退出时为空,说明组处于 Empty 状态。--describe --topic 显示每个分区的 leader 和副本状态。

判断与定位

  1. 先按分区看 lag。总 lag 很大但只有一个分区积压,说明分区键倾斜或某个消费者处理慢;所有分区都积压才是整体消费能力不足。
  2. 看消费者组状态和成员数。成员数超过分区数时,多出来的消费者会空闲;成员数少于分区数时,单个消费者要处理多个分区。
  3. 如果 lag 持续增长,检查消费逻辑是否有同步外部调用、批量参数过小、下游数据库慢或频繁 rebalance。
  4. 容易误判:LAG 列显示 - 不一定是零,可能是该分区没有已提交位点,或消费者组从未成功提交。另一个误判是只看总 lag,忽略了单个热点分区已经拖垮业务。
  5. broker 磁盘、网络和副本同步也会影响消费,但应先排除消费端处理慢。

修复

继续消费一部分消息,观察 lag 下降:

docker exec lab-kafka /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 --topic lab-lag --group lab-group \
  --max-messages 1000 \
  --consumer-property enable.auto.commit=true \
  --consumer-property auto.commit.interval.ms=500
sleep 2
docker exec lab-kafka /opt/kafka/bin/kafka-consumer-groups.sh \
  --bootstrap-server localhost:9092 --describe --group lab-group

LAG 应减少约 1000。生产环境可以增加消费者实例(上限等于分区数)、提高单批处理量、并行化慢调用、优化下游写入,必要时增加分区;增加分区会改变 key 的路由,需要评估顺序性要求。

清理与回滚

docker rm -f lab-kafka

容器删除后 topic 和消费位点全部消失。若使用外部 Kafka,只删除 lab-lag topic 和 lab-group 消费组,不要误删生产 topic。

复盘

延伸阅读

读完自测

  1. 为什么消费者数量超过分区数后,增加实例不能继续提升吞吐?
  2. LAG 显示 - 可能代表什么?
  3. 总 lag 很高但只有一个分区积压,优先排查什么?
答案
  1. 一个分区在同一消费者组内只能分配给一个消费者,多出的消费者没有分区可消费。
  2. 可能是该分区没有已提交位点、消费者组不活跃,或尚未成功提交 offset,不一定代表 lag 为零。
  3. 排查分区键倾斜、热点 key 和该分区对应消费者的处理速度。