RabbitMQ 故障排查:使用命令诊断队列和消息问题

掌握 `rabbitmqctl` 命令行工具,快速排查 RabbitMQ 问题。本指南提供实用、可操作的命令,用于诊断常见问题,如队列积压过多、消息卡住、消费者连接为零以及错误的交换机绑定。学习基本诊断方法,无需仅依赖 UI 即可快速恢复消息流。

RabbitMQ 故障排查:使用命令诊断队列和消息问题

当 RabbitMQ 队列看起来卡住时,最糟糕的第一步通常是清空它。第二糟糕的做法是重启代理并希望问题消失。大多数队列问题都会留下线索:就绪消息、未确认消息、缺失的消费者、被阻止的发布者、无法路由的消息、悄悄填满的死信队列,或者已连接但未确认任何内容的消费者。

本指南使用 RabbitMQ 命令从终端缩小问题范围。我倾向于使用 rabbitmqctl 获取代理端状态,并在需要管理 API 操作(如安全地采样消息)时使用 rabbitmqadmin。除非显示了 -p <vhost> 选项,否则示例假定使用默认虚拟主机。在实际系统中,始终包含虚拟主机;许多误诊是因为有人检查了 /,而应用程序使用了 paymentsprod

理解 rabbitmqctl

rabbitmqctl 命令充当与 RabbitMQ 管理层交互的命令行界面 (CLI)。它允许您管理用户、权限、交换机、队列、绑定,并且对于故障排查最重要的是,检查代理的运行时统计信息。

执行说明: 大多数命令需要 root 权限,或者运行命令的用户必须是 rabbitmq 组的成员,否则您可能需要使用 sudo

诊断队列积压和卡住的消息

最常见的问题之一是队列不断增长,表明消息的生产速度快于消费速度,或者消费者已停止处理。

从队列开始,但请求正确的列

默认的 list_queues 输出对于故障排查来说信息太少。请求那些区分“等待投递”和“已投递但未确认”的列。

rabbitmqctl -p / list_queues name messages_ready messages_unacknowledged messages consumers state

这样解读:

症状 可能含义
messages_ready 增长,consumers0 没有活动的消费者订阅该队列。检查部署、凭据、虚拟主机和队列名称。
messages_ready 增长,存在消费者 消费者太慢、被阻塞,或者预取值对于工作负载来说太低。
messages_unacknowledged 高且稳定 消费者已接收消息但未确认。查找卡住的处理程序或过高的预取值。
state 不是 running 队列可能不可用、正在同步或受节点问题影响。检查集群和队列领导者状态。

对于仲裁队列,添加领导者和成员列:

rabbitmqctl -p / list_queues name type leader members online messages_ready messages_unacknowledged consumers state

这很重要,因为一个队列可能在一个节点上有健康的消费者,而领导者却在另一个节点上,或者仲裁队列可能正在等待足够多的成员上线。

如果列表很长,使用标准 shell 工具进行过滤:

rabbitmqctl -p / list_queues name messages_ready messages_unacknowledged consumers state \
  | awk '$2 > 0 || $3 > 0 || $4 == 0'

检查代理是否阻止了发布者

rabbitmqctl status
rabbitmq-diagnostics alarms

内存和磁盘警报并不意味着队列配置错误,但它们可以解释很多“消息不流动”的事件。当 RabbitMQ 触发内存或磁盘空间不足警报时,它可能会阻止发布连接。消费者可能仍然会排空消息,因此可见的症状可能是不均匀的:一些队列缩小,另一些队列停止接收新工作,发布者超时。

同时检查监听器和节点健康:

rabbitmq-diagnostics ping
rabbitmq-diagnostics listeners
rabbitmq-diagnostics check_running
rabbitmq-diagnostics check_local_alarms

无需猜测即可检查消费者

list_connections 告诉您谁已连接。list_channels 告诉您这些连接是否打开了通道以及它们持有多少工作。

rabbitmqctl list_connections name user peer_host peer_port state channels recv_oct send_oct
rabbitmqctl list_channels connection name number consumer_count messages_unacknowledged prefetch_count state

有用的模式很简单:

  • 没有来自预期主机的连接:应用程序已关闭、无法解析代理、无法进行身份验证或正在连接到其他环境。
  • 连接存在,但没有通道:客户端已连接,但在声明或消费之前失败。
  • 通道存在,但 consumer_count0:应用程序可能仅发布,或者消费者订阅失败。
  • 一个通道上的 messages_unacknowledged 很高:该消费者在内存中持有工作,并且没有快速返回确认。

如果您使用命名连接,请在客户端配置中包含 connection_name。像 10.42.8.17:52344 -> 10.42.1.20:5672 这样的行不如 billing-worker-7 有用。

在指责消费者之前验证绑定

当队列为空但应用程序声称已发布消息时,下一步是检查路由。

rabbitmqctl -p / list_exchanges name type durable auto_delete internal arguments
rabbitmqctl -p / list_bindings source_name source_kind destination_name destination_kind routing_key arguments

直连交换机需要精确的路由键匹配。主题交换机使用 * 匹配一个单词,使用 # 匹配零个或多个单词。扇出交换机忽略路由键。如果交换机没有匹配的绑定且没有备用交换机,则消息无法路由。它不会秘密地等待在某个地方。

对于发布者端确认,使用强制发布并在客户端处理返回的消息。在代理端,管理 UI 和指标通常比 rabbitmqctl 更适合查看速率,但 list_bindings 足以捕获常见错误:错误的虚拟主机、错误的交换机、拼写错误的路由键,或者部署后绑定到旧交换机的队列。

安全地采样消息

在现代 RabbitMQ 中没有通用的 rabbitmqctl queue_get 命令。通过 rabbitmqadmin 或 HTTP API 使用管理插件。小心操作:根据确认模式,获取消息可能会删除或重新排队它们。

rabbitmqadmin -V / get queue=orders.pending count=3 ackmode=ack_requeue_true

使用此命令回答具体问题:负载是否是有效的 JSON,消息类型是否是消费者期望的,是否缺少必需的标头,路由键是否与生产者团队所说的一致?不要将其用作繁忙生产队列上的批量检查工具。

查找死信移动

延迟处理通常表现为死信队列悄悄增长。

rabbitmqctl -p / list_queues name messages_ready messages_unacknowledged arguments policy
rabbitmqctl -p / list_bindings source_name destination_name routing_key arguments \
  | grep -E 'dead|dlx|retry|parking'

队列参数,如 x-dead-letter-exchangex-dead-letter-routing-keyx-message-ttlx-max-lengthx-overflow,决定了消息在过期、被拒绝或达到长度限制时的去向。如果应用程序通过延迟队列的死信进行重试,错误的绑定可能会造成循环。症状看起来像是“延迟消息”,但真正的问题是消息在队列之间循环,而不是到达最终处理队列或停车队列。

实用的命令序列

当有人报告“订单卡住”时,我通常运行以下序列:

rabbitmq-diagnostics ping
rabbitmq-diagnostics check_local_alarms
rabbitmqctl -p orders list_queues name type messages_ready messages_unacknowledged consumers state
rabbitmqctl list_connections name user peer_host state channels
rabbitmqctl list_channels connection consumer_count messages_unacknowledged prefetch_count state
rabbitmqctl -p orders list_bindings source_name destination_name routing_key arguments

如果 messages_ready 很高且 consumers 为零,则检查消费者部署。如果 messages_unacknowledged 很高,则检查消费者日志和预取设置。如果队列为空但发布者报告成功,则检查绑定和发布者确认。如果警报处于活动状态,则在排查应用程序逻辑之前先解决代理资源压力。这使调查基于代理实际正在执行的操作。