Skip to content
缓存、消息与检索故障排查 · 第 2 篇 / 共 5 篇
领域生产问题
专题数据与基础设施排障专题
当前序列缓存、消息与检索故障排查
阅读位置第 2 篇 / 共 5 篇当前专题第 2 个序列 / 共 5 个序列

RabbitMQ 队列积压时怎么排查

RabbitMQ 队列积压和 Kafka lag 一样,都是非常典型的“系统已经不再顺畅流动”的信号。

业务侧通常看到的是:

  • 队列消息数一路上涨
  • 消费接口延迟越来越高
  • 消费者实例明明在线,但积压就是降不下去
  • 重试、死信、数据库压力开始一起抖

这类问题最怕的两种误判是:

  • 一上来就扩消费者,却没看到真正瓶颈在数据库或外部接口
  • 一看到队列堆积就怀疑 MQ 自身性能,却没看到消费端已经被重试风暴和下游阻塞拖住了

先说结论

  • RabbitMQ 队列积压先判断是生产变快、消费变慢,还是消费几乎停住
  • 第一目标是止血,保护核心队列和下游依赖,不要让重试和堆积一起滚雪球
  • 第二目标是判断瓶颈在消费者逻辑、prefetch/ack、线程池、数据库、RPC 还是队列设计本身
  • 很多积压问题本质不在 RabbitMQ broker,而在消费端吞吐、失败重试策略和下游依赖退化

一个典型故障现场

一个典型场景是订单支付结果消费队列。

平时队列深度接近 0,某次活动开始后突然出现:

  • ready 消息快速升高
  • unacked 也在增加
  • 消费者实例数没变化
  • 下游 MySQL RT 变慢
  • 死信队列和重试队列也开始上涨

这时如果只盯着 RabbitMQ 管理台,很容易看不清真正的问题:

  • 是不是消费者已经拿到消息但处理太慢
  • 是不是 ack 太晚导致 unacked 占住了吞吐
  • 是不是失败消息在不断重回主队列
  • 是不是 prefetch、并发模型和下游能力不匹配

第一阶段:先止血,保护主链路和下游

1. 先分优先级,保护核心队列

如果有非核心消费者、异步通知、统计类消费,必要时可以先降级,优先保住核心订单、支付、状态流转链路。

2. 控制失败重试和死循环回投

RabbitMQ 的积压特别容易被失败重试放大。你会看到:

  • 主队列在涨
  • 重试队列也在涨
  • 死信也在涨
  • 数据库和接口压力继续被放大

这时先把重试节奏放缓、切断错误消息的快速回投,比继续压榨主消费线程更重要。

3. 不要盲目提并发

扩消费者、调大 prefetch、增加线程池都可能短时有效,但前提是:

  • 下游数据库还能承受
  • 单条消息处理不是长事务
  • 失败消息没有在持续重试

否则只是把积压更快传导到下游。

第二阶段:先判断积压落在哪一层

1. ready 很高,unacked 不高

更像是消费者根本拿不动消息,可能是:

  • 消费并发不足
  • 消费者实例异常
  • 订阅中断
  • channel/connection 有问题

2. unacked 很高

更像是消费者已经拿到消息,但处理太慢或者迟迟不 ack。

这时更要看:

  • 单条消息耗时
  • 下游依赖
  • 事务边界
  • ack 时机

3. ready 和 unacked 一起涨

通常意味着:

  • 消费端整体吞吐已经不够
  • 处理链路变慢
  • 批量失败和重试一起在放大

第三阶段:最值得看的几组指标和现象

1. 生产速率和消费速率

先判断:

  • 是发送量突然大了
  • 还是消费速率先掉了

RabbitMQ 队列深度只是结果,真正关键的是这两条速率曲线谁先变。

2. ready、unacked、ack rate

这三个指标放在一起看,非常容易帮助判断问题在哪一层。

3. 消费者线程池、数据库、RPC

很多 RabbitMQ 积压,本质上就是消费者在等:

  • 等数据库连接
  • 等 SQL
  • 等外部 RPC
  • 等锁

RabbitMQ 只是把后面的慢链路暴露出来了。

4. prefetch 和消费模型

prefetch 太大时,少数消费者可能会拿到大量消息却迟迟处理不完;prefetch 太小又可能利用率不够。

所以它不是越大越好,而是要匹配:

  • 单条消息耗时
  • 并发模型
  • ack 策略

常见根因画像

1. 消费逻辑变重

最近发版后多了一步数据库写入、远程调用或同步校验,导致单位消息处理时间明显上涨。

2. 下游数据库或接口变慢

这类是最常见根因。RabbitMQ 本身没问题,但消费者一直在等下游返回。

3. 批量失败触发重试风暴

失败消息反复回队,正常消息也一起被拖住。

4. 单线程消费或线程池设计不合理

看起来消费者实例在线,但真正处理能力很有限。

5. ack 时机和事务边界设计不合理

消息已经拿到,但长事务或后置步骤迟迟不结束,导致 unacked 长期居高不下。

一个更实用的排查顺序

线上出现 RabbitMQ 积压时,我通常按这个顺序判断:

  1. 先看是发送量暴涨,还是消费速率下降。
  2. 再看 ready、unacked、ack rate 的组合关系。
  3. 看消费者线程池、数据库、RPC 是否同步变慢。
  4. 看是否有失败重试、死信回流、批量 nack。
  5. 最后再决定是扩消费者、调 prefetch、隔离重试,还是先处理下游瓶颈。

这样能避免把“消费链路问题”误当成“MQ 本身性能问题”。

止血后的治理方向

1. 主消费、重试、死信链路分开治理

不要让失败消息和正常消息长期抢同一条主通道。

2. prefetch、并发和下游能力一起评估

不能只看 MQ 吞吐,不看数据库和接口承载能力。

3. 为关键队列准备降级和恢复预案

包括:

  • 临时降级非核心消费
  • 批量补偿回放
  • 失败消息隔离
  • 高峰期扩容模板

总结

RabbitMQ 队列积压真正要看的,不是“队列里还有多少消息”,而是消息是卡在 ready、卡在 unacked,还是卡在消费者后面的处理链路。

把“发送速率、消费速率、ready/unacked、失败重试、下游依赖”这几条线理顺后,积压问题通常都能更快落到真正根因上。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 回看前文会更完整Kubernetes CrashLoopBackOff 时怎么排查适合把 K8s、RabbitMQ 和数据库锁等待问题放在一条故障治理主线上看。数据与基础设施排障专题 · 基础设施与中间件故障案例同一序列 · 顺着当前主线继续读数据库死锁和锁等待超时案例怎么复盘适合把 K8s、RabbitMQ 和数据库锁等待问题放在一条故障治理主线上看。数据与基础设施排障专题 · 基础设施与中间件故障案例同专题其他序列 · 共享标签:Kafka、线上排障MQ 积压排查为什么先看生产端不一定对适合把 Redis 抖动、MySQL 连接打满、MQ 积压、ES 发黄、ClickHouse 合并堆积和磁盘打满放在同一条基础设施排障主线上看。数据与基础设施排障专题 · 数据与基础设施故障的分层排查同专题其他序列 · 共享标签:线上排障、案例排障磁盘打满后为什么删除文件不一定立刻生效适合把 Redis 抖动、MySQL 连接打满、MQ 积压、ES 发黄、ClickHouse 合并堆积和磁盘打满放在同一条基础设施排障主线上看。数据与基础设施排障专题 · 数据与基础设施故障的分层排查跨专题关联 · 共享标签:Kafka、线上排障Kafka 积压突然飙升时怎么排查适合把 Redis 热点、Kafka 积压、ES 慢查询和 ClickHouse 超时放在一条排障线上看。应用运行时排障专题 · 应用运行时典型故障案例跨专题关联 · 共享标签:线上排障、案例排障大 Header、buffer、timeout 问题怎么排查适合把 location 匹配、缓冲区和负载均衡放在一起看。容器与站点部署专题 · Nginx 进阶路由与代理治理
继续阅读缓存、消息与检索故障排查当前序列第 2 篇 / 共 5 篇当前专题第 2 个序列 / 共 5 个序列
往前看
上一篇Redis 热 Key 突增时怎么止血和回查回到当前序列上一章上一序列数据库与网关故障排查从第 1 篇开始:MySQL 连接数打满时怎么排查
往后看
下一篇Kafka 积压突然飙升时怎么排查继续当前序列下一章下一序列容器与编排异常排查从第 1 篇开始:Kubernetes Pod Pending 时怎么排查

把零散经验整理成可查、可复用、可持续更新的企业级知识门户