rabbitmq消息积压:如何快速排查与处理

线上消息队列积压了,消费者处理不过来,老板在群里@你------这时候怎么办?

今天聊点实际的,从判断积压到快速处理,讲点能直接上手的东西。

怎么判断消息积压了

RabbitMQ

bash 复制代码
# 查看队列消息数量
rabbitmqctl list_queues name messages messages_ready messages_unacked

# 输出大概长这样
# name    messages  messages_ready  messages_unacked
# order   15234    15200           34

关键看这几个数字:

  • messages - 队列里总共有多少消息
  • messages_ready - 等待消费的消息(积压的主力)
  • messages_unacked - 已投递但还没确认的

一般来说,messages_ready 超过几千就该关注了,上万就是严重积压。

Kafka

bash 复制代码
# 查看消费 lag(落后多少)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
  --group my-consumer-group \
  --describe

# 输出大概长这样
# GROUP           TOPIC      PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG
# my-consumer     order      0          52341           67589           15248

LAG 就是积压量。LAG 几百几千问题不大,上万就得处理了。

为什么会积压

常见原因就几种:

1. 消费者挂了

最常见。消费者进程没了,但生产者还在往里扔消息。

2. 消费者变慢了

比如数据库慢查询、对外接口超时。消息在那儿等着,时间一长就堆起来了。

3. 消费者数量不对

分区数固定,但消费者少了或者消费者不干活了。

4. 消费逻辑有死循环或者阻塞

消费端卡在某个地方,不消费也不报错。

快速处理方案

方案一:临时增加消费者(推荐)

如果是 Kafka,把消费者实例扩几个:

yaml 复制代码
# Docker Compose 临时扩容
services:
  consumer:
    deploy:
      replicas: 5  # 从 1 临时改成 5

RabbitMQ 的话,多启动几个消费者实例就行。

注意:Kafka 一个分区只能被一个消费者消费,所以扩容数量别超过分区数。

方案二:提高消费并行度

java 复制代码
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(
        ConsumerFactory<String, String> consumerFactory) {
    ConcurrentKafkaListenerContainerFactory<String, String> factory =
            new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory(consumerFactory);
    factory.setConcurrency(10);  // 默认1,临时调大成10
    return factory;
}

RabbitMQ 的话,调整 prefetch 数量:

java 复制代码
factory.setPrefetchCount(50);  // 默认250,太大了会积压太久,太小了吞吐量上不去

方案三:跳过积压消息,先消费最新的

有时候积压太多了,处理完要很久。这时候可以先跳过旧消息:

Kafka 方案:重置 offset 到最新

bash 复制代码
# 把消费者组的 offset 重置到最新
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
  --group my-consumer-group \
  --topic order \
  --reset-offsets --to-latest \
  --execute

注意:这个方案会丢消息,只有在业务能接受丢消息的时候才用。

方案四:临时写个脚本消费掉

直接写个简单脚本,扫队列然后批量处理:

java 复制代码
@Service
public class FastConsumerService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void consumeAndDiscard(String queueName, int limit) {
        for (int i = 0; i < limit; i++) {
            Message message = rabbitTemplate.receive(queueName, 1000);
            if (message == null) {
                break;
            }
            // 空消费,直接确认。积压太多可以用这个临时方案
            // 但记得后续要补偿处理这些消息!
        }
    }
}

再次强调:空消费会丢消息,后续一定要有补偿机制。

排查积压的根本原因

处理完积压只是治标,找到根因才是治本。

看消费者日志

消费者有没有报错?有没有超时?有没 BLOCKED?

bash 复制代码
# RabbitMQ 查看连接状态
rabbitmqctl list_connections pid channels

# 查看消费者是否正常
rabbitmqctl list_consumers queue_name

看监控

RabbitMQ 管理界面:http://localhost:15672

Kafka 使用 Kafka Eagle 或者 JMX 监控:

properties 复制代码
# 开启 JMX
KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote=true"

常见坑

数据库连接池打满:消费者查询数据库,连接池耗尽,所有消费线程都在等连接。

对外接口超时:消费者调第三方接口,接口响应慢,消费速度断崖式下降。

内存泄漏:消费者 OOM 了但没死透,勉强撑着但几乎不消费。

怎么防止积压

几点经验:

  1. 监控先行。LAG 超过阈值就告警,别等老板@你。
  2. 消费者要快。IO 操作异步化,能批量处理就批量。
  3. 分区/队列数要够。Kafka 分区数决定了最大并发消费数。
  4. 做好限流。上游流量突增时,MQ 要能扛住。

总结

场景 推荐方案
消费者挂了 重启/扩容消费者
消费太慢 提高并发度、优化消费逻辑
积压太多,业务能接受丢消息 重置 offset 到最新
积压太多,业务不能丢消息 扩容 + 慢慢消费 + 加补偿

积压不可怕,怕的是没监控、没预案。下次遇到这种情况,希望你能从容应对。

相关推荐
rchmin2 小时前
阿里Tair分布式锁与Redis分布式锁的实现区别
数据库·redis·分布式
凌乱的豆包19 小时前
Spring Cloud Alibaba Nacos 服务注册发现和分布式配置中心
分布式
独隅20 小时前
PyTorch 分布式训练完整指南:策略、实现与模型选型
人工智能·pytorch·分布式
架构师老Y21 小时前
011、消息队列应用:RabbitMQ、Kafka与Celery
python·架构·kafka·rabbitmq·ruby
墨北小七1 天前
小说大模型的分布式训练——张量并行架构设计与实现
分布式
豆豆1 天前
政务服务平台站群一体化解决方案
大数据·分布式·微服务·cms·政务·网站管理系统·站群cms
昵称暂无11 天前
分布式事务难题:Seata框架在微服务中的落地实践
分布式·微服务·架构
都说名字长不会被发现1 天前
分布式场景下的数据竞争问题与解决方案
分布式·乐观锁·悲观锁·redission·redis 分布式锁·数据版本
甘露s1 天前
分布式与可重入性的一些问题
分布式