队列深度持续上升。消费者看起来运行正常。日志没有任何异常。值班工程师正盯着你看。
这是我每次遇到RabbitMQ队列停止排空时执行的排查步骤——按顺序,最快速的检查排在最前面。
第一步:是否有消费者?
打开管理界面(或Qarote),查看阻塞队列的Consumers列。
如果显示0,问题不是谜题——而是缺少消费者。常见原因:
- 部署过程中消费者Pod崩溃且没有重启
- 网络分区导致消费者节点被隔离
- 消费者遭遇未捕获的异常后静默退出
- 自动扩缩容将实例数缩减为零
解决方案: 重启消费者进程并确认它们重新连接。检查你的进程管理器、Kubernetes Deployment或systemd单元。
第二步:消息是否已投递但从未确认?
消费者数量不为零并不意味着消息真的在被处理。对照Ready检查Unacknowledged计数。
如果Unacked很高而Ready接近零,说明消费者在接收消息但没有确认。这通常意味着:
- Prefetch count太低。 如果
prefetch_count = 1且处理耗时10秒,每个消费者每分钟只能处理6条消息。乘以消费者数量——如果低于你的发布速率,队列就会无限增长。 - 消费者被阻塞。 下游数据库调用、HTTP请求或锁一直挂起,消息处于飞行状态但永远无法完成。
- Bug导致确认静默失败。 消息被处理了,但ack从未发出——通常是缺少
try/finally或在ack行之前抛出了异常。
Prefetch修复: 调高prefetch_count以匹配你的预期处理时间和吞吐量。粗略公式:prefetch = 目标吞吐量(每消费者) × 平均处理时间(秒)。
# 示例:每个消费者目标50条/秒,平均处理时间200ms
prefetch = 50 × 0.2 = 10
消费者阻塞修复: 为所有外部调用添加超时。在每个下游操作前后记录日志,以便看清时间花在哪里。
第三步:检查消费者利用率
RabbitMQ跟踪消费者利用率——消费者真正忙碌的时间占等待下一条消息时间的比例。可以通过管理API查看:
curl -u guest:guest \
http://localhost:15672/api/queues/%2F/my-queue \
| jq '.consumer_utilisation'
接近1.0的值表示消费者已饱和。队列中有消息但值接近0表示存在其他问题(通常是未确认消息阻塞投递,见第二步)。
第四步:检查内存和磁盘告警
当RabbitMQ达到资源限制时,它会停止接受发布并暂停消费者。执行:
rabbitmqctl status | grep -A5 alarms
或查看管理界面的Overview页面。如果看到memory_alarm或disk_free_alarm的红色横幅,那就是问题所在。
常见触发原因:
- 大量消息在内存中累积(队列尚未分页到磁盘)
- 磁盘空间不足——RabbitMQ将消息分页到磁盘,磁盘满了它就会停止
vm_memory_high_watermark设置对你的工作负载来说太低了
解决方案: 在rabbitmq.conf中调高vm_memory_high_watermark,释放磁盘空间,或扩展Broker节点。
第五步:消息是否被发送到死信队列?
如果你的队列配置了x-dead-letter-exchange,被拒绝或过期的消息会进入死信队列(DLQ)。如果DLQ在增长,说明:
- 消费者在调用
basic.nack/basic.reject且requeue=false - 消息在消费者接收之前就已过期(达到TTL)
检查DLQ的深度。如果它以与主队列未排空相同的速率增长,说明消费者在处理消息但在拒绝它们——通常是由于验证Bug或下游服务返回错误。
解决方案: 检查DLQ中的消息,读取前几个Payload寻找规律。修复上游发布方或消费者的拒绝逻辑。
第六步:是否触发了通道级流控?
高发布速率可能在内存告警触发之前就触发通道级流控。在RabbitMQ日志中查找:
connection <x.x.x.x:y>, channel N: flow control
或查询API:
curl -u guest:guest http://localhost:15672/api/channels \
| jq '.[] | select(.flow_blocked == true) | .name'
如果看到通道被阻塞,Broker正在要求发布者减速。这不会阻止排空,但可能掩盖真正的问题——消慢的消费者让队列填满,直到Broker开始推回压力。
在一个界面看清全局
执行六条rabbitmqctl命令并从API读取JSON,偶尔一次还算可行。凌晨2点发生故障时就不行了。
Qarote在单个界面上实时显示消费者数量、未确认消息、消费者利用率、DLQ深度和活跃告警。免费的MIT自托管版本覆盖所有这些指标。无按主机计费,无数据离开你的网络。
当我在积压故障期间打开Qarote的队列详情时,通常能在不到一分钟内排除上述六个步骤中的五个,只剩真正的问题需要排查。
快速参考
| 症状 | 可能原因 | 首先检查 |
|---|---|---|
Consumers = 0 | 消费者进程崩溃 | Pod / 进程状态 |
Unacked高,Ready低 | Prefetch太低或消费者阻塞 | 处理时间 + prefetch设置 |
Consumer utilisation ≈ 1.0 | 消费者已饱和 | 增加更多消费者实例 |
| 红色告警横幅 | 达到内存或磁盘限制 | rabbitmqctl status |
| DLQ以相同速率增长 | 消费者在拒绝消息 | 检查DLQ中的Payload |
| 通道被阻塞 | 流控激活 | 降低发布者速率或提升消费者速度 |