大量消息在 MQ 里长时间积压,该如何解决?

Kafka 的 consumer lag 监控突然开始涨,上游消息一直在打进来,消费者追不上。积压的原因只有两种:消费速度跟不上生产速度 ,或者消费者根本没在消费。方向不同,处理方式完全不一样,搞反了越修越乱。

先判断消费者是活的还是卡死的

看消费者的 lag 曲线。lag 在涨但消费者还有 offset 提交,是消费速度不够。lag 在涨但 offset 长时间没动,消费者要么挂了,要么卡在某条消息上出不来。

Kafka 看 consumer group 状态:

bash 复制代码
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
  --describe --group your-group-name

看 LAG 和 CONSUMER-ID 两列。CONSUMER-ID 都是空的,说明消费者全掉线了。有 CONSUMER-ID 但 LAG 持续增长,是速度问题。

消费者卡死的常见原因:消息反序列化失败一直重试、下游服务超时导致消费逻辑阻塞、消费者线程池打满。这种情况不是消费速度问题,先把卡死的消息处理掉,别急着扩容。一条格式异常的消息能把整个 consumer 卡住几个小时。

消费速度不够:临时扩分区、加消费者

Kafka 的消费并行度上限是分区数,一个分区同一时刻只能被一个消费者消费。topic 只有 4 个分区,启 8 个消费者实例也是浪费,有 4 个在闲置。

积压严重时的临时手段:

bash 复制代码
kafka-topics.sh --bootstrap-server localhost:9092 \
  --alter --topic your-topic --partitions 16

分区只能增不能减,增加后消费者组自动触发 rebalance,新分区分配到新消费者实例。分区数加了,同时拉起对应数量的消费者实例,并行度才真正提升。

注意这是应急操作,不是正常流程。分区数永久增加,消息的顺序性会被打乱(同一个 key 原来保证在同一分区,分区数变了 key 的 hash 落点变了)。如果业务依赖消费顺序,扩分区之前先确认影响范围。

消费逻辑本身太慢:批量消费、异步化

消费者一条一条拉,每条同步调用一次数据库。单条消费耗时 20ms,一个消费者线程一秒最多 50 条,分区再多也就这个吞吐量。

批量拉取:

java 复制代码
@KafkaListener(topics = "order-topic", containerFactory = "batchFactory")
public void consume(List<ConsumerRecord<String, String>> records) {
    List<Order> orders = records.stream()
        .map(r -> JSON.parseObject(r.value(), Order.class))
        .collect(Collectors.toList());
    orderMapper.batchInsert(orders);
}

批量 insert 比逐条 insert 快一个数量级,数据库连接开销从 N 次降到 1 次。max.poll.records 控制每次拉取的最大条数,根据单条消息处理耗时调整,不要设太大,否则处理时间超过 max.poll.interval.ms 会触发 rebalance。

消费逻辑里有外部调用(HTTP 接口、第三方 API)且不要求强一致,可以异步化:先把消息写本地数据库或者内存队列,立即提交 offset,另起线程批量处理。消费者不再被外部调用阻塞,速度能提升好几倍。代价是消费者重启可能丢失内存里还没处理的消息,本地数据库方案相对可靠。

积压太深:临时跳过或转移

积压量已经很大了,按正常消费速度需要好几个小时才能消化。如果这些是历史数据,业务上可以接受丢弃,直接重置 offset 到最新位置:

bash 复制代码
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
  --group your-group-name --topic your-topic \
  --reset-offsets --to-latest --execute

业务上不能丢的话,把积压的消息导到一个临时 topic,用专门的消费者集群在业务低峰期慢慢消化,主 topic 的消费者先处理新消息,不让积压继续扩大:

写一个转发消费者就行:从原 topic 消费,不做任何业务处理,直接 produce 到临时 topic。跑起来之后原 topic 的 lag 会快速下降,给正常消费者喘口气。

治标之后治本

积压消化完,还得找到为什么会积压。

最常见的是上游流量突增没有限流。促销活动订单量翻了好几倍,消费者没有弹性扩容机制,消费能力是固定的,生产端突然加速就积压了。消费者接入 Kubernetes HPA 按 lag 指标自动扩缩容可以缓解,但前提是消费逻辑本身能水平扩展。

还有一种更隐蔽的:还有一种更隐蔽的:消费逻辑里有慢查询,平时没问题,量大了之后数据库压力上来,SQL 执行时间翻了几十倍,消费速度直接掉一个数量级。这种不看 slow query 日志根本发现不了,以为是 Kafka 的问题,其实瓶颈在数据库。

积压告警本身也得提前配。lag 超过一定阈值就该响,等到积压量已经很大了再处理,扩分区、加消费者、转移消息,每一步都有风险。lag 还小的时候处理,可能加两个消费者实例就追上了。

相关推荐
http阿拉丁神猫2 小时前
Go语言入门笔记:从基础到开发环境搭建(二)
开发语言·笔记·golang
不会就选b3 小时前
C++补充部分(一)--lambda 表达式
开发语言·c++
Pniubi6 小时前
HashMap的扩容和树化边界
java·开发语言
gCode Teacher 格码致知7 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
发量惊人的中年网工7 小时前
分公司访问总部ERP慢怎么办?SD-WAN组网的排查与验收要点
服务器·开发语言·php
下页、再停留8 小时前
【C#桌面客户端系列学习-15】生成可视化图表之折线图、柱状图、饼状图
开发语言·c#
ShineWinsu8 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
益莱储中国9 小时前
深度解析:RF 实验室从 5G迈向 6G 的过程中保持技术领先与设备升级的路径
开发语言·php
benchmark_cc10 小时前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu10 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python