消息积压清不掉,ZEEKEAI 上用 Claude Fable 5.1 从消费指标里找到瓶颈

消息队列消费组积压了八十多万条消息,消费速率死活上不去。加了消费者实例,积压没降,反而因为 rebalance 短暂上升。这事我在 ZEEKEAI(zeekeai.com) 上用 Claude Fable 5.1 配合消费端指标分析了一轮,从消费速率和分区分布里定位到两个分区拖了后腿。


先把消费组的指标导出来。用命令行工具拉取每个分区的消费位点和最新位点,算出积压量:

bash

bash 复制代码
#!/usr/bin/env bash
# 导出消费组每个分区的积压量
GROUP="order-consumer"
BOOTSTRAP="kafka-broker:9092"

kafka-consumer-groups.sh --bootstrap-server "$BOOTSTRAP" \
  --describe --group "$GROUP" 2>/dev/null \
  | awk 'NR>1 && $2 != "" {
      # 列:GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST
      printf "%s\t%s\t%s\t%s\t%s\n", $2, $3, $4, $5, $6
    }' | sort -t$'\t' -k5 -rn > lag.tsv

# 按主题汇总积压量
awk -F'\t' '{sum[$1]+=$5} END {for (t in sum) printf "%s\t%d\n", t, sum[t]}' lag.tsv \
  | sort -k2 -rn

跑出来积压集中在两个主题上,其中一个主题的积压量占了总量的七成。按分区看,这个主题的十二个分区里,只有两个分区的积压特别高,其他分区的积压是个位数。


把分区积压数据喂给模型,让它按分区分布判断瓶颈在哪:

text

复制代码
下面是 Kafka 消费组各分区的积压量,按主题分组。
只做一件事:分析积压的分区分布特征,判断瓶颈在消费者整体还是个别分区。
输出格式:主题 | 分区总数 | 高积压分区数 | 积压分布特征 | 初步判断。
不要给解决方案,只给分析。

分析结果很明确:积压集中在两个分区,其他分区消费正常。消费者整体消费速率没问题,是两个分区对应的消费者线程卡住了。


查这两个分区为什么慢。看消费端的日志,这两个分区的消费线程里有大量重复的 WARN 日志,内容是"等待数据库连接"。让模型结合消费逻辑分析:

text

markdown 复制代码
两个 Kafka 分区的消费线程日志里频繁出现"等待数据库连接",其他分区没有。
消费逻辑是:每条消息解析后写入数据库,单条写入耗时约 10 毫秒。
只回答三个问题:
1. 为什么只有这两个分区的消费线程在等数据库连接?
2. 这两个分区的消息有什么特征?
3. 连接等待和积压的因果关系是什么?
每条给依据,不要推测。

查了这两个分区的消息内容,消息里带的业务类型恰好是需要写大字段的订单,单条写入耗时是普通消息的几十倍。消费线程处理慢,连接被长时间占用,其他线程也在等连接,形成连锁反应。

让模型确认连接池配置和消费并发是否匹配:

text

markdown 复制代码
消费端线程数 12,数据库连接池最大连接数 10。
这两个分区的消息单条写入耗时是普通消息的几十倍。
只回答两个问题:
1. 线程数和连接池大小是否匹配?
2. 大字段消息占着连接不放,对其他分区的消费有什么影响?
每条给依据,不要推测。

确认了:12 个消费线程抢 10 个连接,本来就不够。大字段消息让连接被占用时间变长,普通消息的消费线程也在排队等连接,整体消费速率被拖慢。


改法分两步。第一步,把大字段消息拆到独立的消费组和连接池,不让它跟普通消息抢资源:

java

typescript 复制代码
// 按消息类型路由到不同的消费逻辑
@KafkaListener(topics = "order-events", groupId = "order-consumer")
public void onMessage(ConsumerRecord<String, String> record) {
    String type = extractType(record.value());
    if ("BIG_FIELD".equals(type)) {
        // 大字段消息转到独立队列,由独立消费者处理
        bigFieldProducer.send("order-events-bigfield", record.value());
        return;
    }
    // 普通消息正常处理
    processNormal(record.value());
}

大字段消息的消费组单独配连接池,最大连接数按消费线程数配,互不干扰。

第二步,消费端的线程数和连接池大小对齐:

yaml

yaml 复制代码
spring:
  datasource:
    hikari:
      maximum-pool-size: 16    # 从 10 加到 16,和消费线程数匹配
      connection-timeout: 3000

连接池从 10 加到 16,比消费线程数 12 多留几个余量,避免线程抢连接。

改完观察一天,积压从八十多万降到两万以内,消费速率恢复到正常水平。


这次分析的关键步骤

步骤 做法 效果
导出分区积压 用消费组命令按分区拉位点 看到积压集中在两个分区
分析分布特征 让模型判断是整体还是局部 定位到个别分区拖后腿
查分区消息特征 看消费日志和消息内容 发现大字段消息写入慢
核对资源配置 对比线程数和连接池大小 确认资源不匹配

最后一句

消息积压清不掉,先看积压是均匀分布还是集中在个别分区。均匀分布是消费者整体能力不足,集中在个别分区是那部分消息处理慢。定位到之后,看慢消息是不是占了本该给普通消息的资源,把慢消息隔离到独立消费组,比加消费者实例管用。

你们消息队列积压时是怎么排查的?有没有遇到过个别分区拖后腿的情况?评论区聊聊。

相关推荐
nice_lcj5202 小时前
【从零理解 Spring AI · 16】Agent 与工作流:什么该写死,什么该让模型决定
java·人工智能·后端·spring ai·ai应用开发
yimiagent实验室2 小时前
封装一个限流退避器:指数退避 + 等抖动 + 最大等待的一次封装
人工智能
丘山录2 小时前
llama.cpp 完整教程,放错盘读一遍多等 1 小时
人工智能
AI前端工程狮2 小时前
用户点了「取消」,我的服务进程退出了
人工智能·程序员
网易云信2 小时前
别急着让 AI 出方案:学会追问三步走,医美咨询全跑通
人工智能
panyz2 小时前
不想再开 7 个标签页查AI额度,我用 Node 写了个本地看板
人工智能·开源·github
炫酷的大高个2 小时前
3.2TB 权重开源了,我算了 4bit 之后还要几张卡
人工智能·架构·开源
字节跳动开源2 小时前
AI 原型几分钟,设计返工一整天?OpenViking 让 AI 用上你的 Figma 设计稿
人工智能·开源
陈工大模型4 小时前
解压工具的三个技术分水岭:编码、分卷、容器格式
人工智能·windows·安全·解压工具·免费国内办公软件