rabbitmq monitoring war-story open-source

我们为何构建 Qarote:一次队列饱和故障实录

我们曾错过一次 RabbitMQ 队列饱和故障,因为整整一小时内没有任何可见性。这是我们构建的工具——以及背后的原因。

Qarote Team
7 min read

消息来自凌晨 2 点 47 分。不是 PagerDuty 告警——而是一位客户发来的 Slack 消息。

“嘿,你们现在有问题吗?我们的任务已经一个多小时没有在处理了。”

整整一个小时。

我打开了 RabbitMQ 管理插件。队列深度图表呈现为一条垂直线。847,000 条消息。我们的主任务队列在无人值守的情况下,已经积压了整整六十三分钟。两个消费者显示已连接,但没有任何一个在处理任何消息。

三十秒内,我打开了四个标签页:管理插件、Grafana、CloudWatch,以及一个 Slack 线程——我的同事们也在从各自的仪表盘尝试理解同一件事。

没有人知道发生了什么。

工具告诉了我什么

管理插件告诉我的,只是我从图表上已经知道的:队列很深,消息速率为零,显示有两个消费者已连接。

它无法告诉我的:

  • 这两个消费者是哪两个?是我预期的 worker,还是上次部署遗留的僵尸连接?
  • 它们为什么连接着却不处理消息?是卡在某条消息上?在悄无声息地崩溃重连?还是在等待下游服务?
  • 积压什么时候开始的?默认保留窗口是 24 小时,但图表精度太粗,无法精确定位问题开始的时刻。
  • 这是一个队列的孤立问题,还是级联故障?我有十五个队列,但插件每次只显示一个。

我切换到 Grafana。我们配置的 RabbitMQ Prometheus 指标提供了队列深度和消费者数量的时序数据,但采集间隔是 60 秒——这意味着我看到的数据已经滞后一分钟。而且仪表盘是按 broker 组织的,而不是按我真正需要的方式组织——一眼看出哪些队列当前表现异常。

故障发生四十分钟后,我终于定位到了根因:数据库连接池在高负载下耗尽了。消费者在拉取消息后,在第一次 DB 调用时悄悄失败,nack 消息但没有正确记录错误,然后重新入队——从管理插件来看,这就像”两个消费者已连接,吞吐量为零”的循环。

修复花了五分钟,诊断花了四十分钟。

真正的问题

自那次故障以来,我想了很多。

问题不在于我们有烂工具。管理插件对日常可见性确实有用,Prometheus + Grafana 也是合理的监控方案。问题在于,这些工具没有一个是为了回答我凌晨 3 点真正想问的问题而设计的:现在哪里出问题了,我该怎么办?

管理插件展示的是状态,Grafana 展示的是历史。没有一个工具展示的是因果关系。

要正确诊断一个 RabbitMQ 故障,你需要关联来自不同地方的信息:队列深度与消费者健康状态,消费者健康状态与消息确认速率,消息确认速率与具体卡住的队列。你需要看到哪些消费者在真正处理消息,哪些是连接着但处于冻结状态。你需要知道一个队列的积压是与消费者数量下降同时开始的,还是在此之前就开始了——因为这是两种不同的故障。

这些信息没有一项是自动呈现的。在故障期间,需要手动逐个标签页地拼凑,而且还得是那个知道该看哪里的人。

一个典型的生产环境 RabbitMQ 监控方案当时长这样:

  • 管理插件 — Web UI,适合手动检查
  • Prometheus 导出器 — 将 RabbitMQ 指标转换为可采集的端点
  • Alertmanager — 将基于指标的告警路由到 Slack 或 PagerDuty
  • Grafana — 趋势分析仪表盘
  • 自定义脚本 — 通常是 Python,通常用于检查 DLQ 深度,因为以上工具默认都不擅长这件事

五个工具,用于一个 broker。每个都需要配置、维护,以及一个知道出错时该看哪个标签页的人。

这不是一个监控方案,这是考古学。

我们想要的替代方案

故障之后,我开始思考:如果专门为了回答”现在哪里出问题了?“而非”这里是所有指标,祝你好运”而设计一个 RabbitMQ 监控工具,它应该是什么样的?

有几件事显然不可或缺:

变化率,而不仅仅是深度。 一个持有 50,000 条消息且以 +500/秒增长的队列,意味着 90 分钟后会有一个凌晨 3 点的告警。同一个队列以 -1,000/秒下降则是健康的。单纯的深度是滞后指标——你需要速度来判断是正在走向故障,还是正在从故障中恢复。

消费者健康状况作为一等指标。 不只是”有多少消费者已连接”,而是”它们是否真的在处理消息?“一个连接但不确认消息的消费者就是坏的。

死信队列作为前置指标。 DLQ 是坏消息悄悄堆积的地方。如果你的 DLQ 在增长,你有一个消费者 bug。大多数团队在几周后的故障复盘中才发现这一点。

多队列、多 broker 的单一视图。 故障期间,你没有时间逐个翻看十五个队列。

基于前置指标的告警,而不仅仅是滞后指标。 当队列达到 500,000 条消息时触发的告警,主要用于确认你已经处于故障中。当队列增长速度超过消耗速度时触发的告警——当你还有五分钟余量时——才是真正有用的。

无需 Prometheus。 不是因为 Prometheus 不好——对于通用基础设施监控它非常出色。但为了监控单个 RabbitMQ 集群而搭建一套完整的 Prometheus + Grafana + Alertmanager,对于还没有这套方案的团队来说门槛太高。

为什么我们选择构建而非修补现有工具

我认真研究过现有选项。有 RabbitMQ 的 Grafana 仪表盘模板,有带 RabbitMQ 集成的 SaaS APM 平台,有商业的 RabbitMQ 监控产品。

但没有一个是从”告诉我哪里出问题了,而不仅仅是发生了什么”这个前提出发构建的。

于是我们构建了 Qarote。

核心采用 MIT 许可,可自托管。你只需将它指向 RabbitMQ 管理 API——不需要 Prometheus 插件,不需要 YAML,不需要部署 agent——它就会给你一个多队列仪表盘,包含变化率指标、消费者健康信号、DLQ 监控和可配置告警。这正是在那次故障的前五分钟就能告诉我:消费者已连接但没有在确认消息,DLQ 没有增长(排除静默崩溃后重新入队),以及积压加速的时间节点与应用连接错误激增的时间完全一致。

历史记录保留超过 RabbitMQ 默认的 24 小时窗口。基于变化率的告警,而不仅仅是绝对阈值。除运行中的 broker 外无其他基础设施前提。

这就是 Qarote。因为我们亲历了它所设计要预防的故障,所以我们构建了它。


如果你在生产环境中运行 RabbitMQ,并且曾经有过在故障期间盯着管理插件、不知道究竟哪里出了问题的经历,来试试吧。免费套餐涵盖你入门所需的一切,配置大约需要两分钟。

如果你想自己托管,核心部分是在 GitHub 上开源的

Tired of debugging RabbitMQ blind?

Qarote gives you a real-time view of queues, consumers, and alarms — free.

Get started free