Skip to content

RabbitMQ 中无法路由的消息会去到哪里? ​

  • 标签:RabbitMQ、消息队列、后端

🏛 业务架构师 ​

无法路由的消息(exchange 没有匹配的 queue)有三种归宿,对应三档防护投入:

  • 默认:直接丢弃。这是最危险的默认值——消息静默消失,没有任何痕迹;
  • 设置 mandatory=true:消息不可路由时通过 ReturnCallback 回调给生产者,由业务决定重发、落库或告警;
  • 配置备份交换机(Alternate Exchange):交换机上指定一个"兜底交换机",无法路由的消息全部进它,统一落库或监控。

业务上的真实教训很多:积分服务上线时队列名改了、绑定关系漏配,生产端一直正常投递,用户的积分却悄悄丢了两周,最后靠对账才追回来。所以我的落地标准是:

  1. 核心业务消息一律 mandatory + ReturnCallback + 备份交换机双保险,回调里落"投递失败表"并接告警;
  2. 生产端开启 Confirm 机制,区分"到没到 broker"(confirm)和"能不能路由到队列"(return)两层确认;
  3. 丢失兜底靠对账系统:业务表和消息消费结果定时比对,任何机制都有失效窗口,对账才是最后防线。

一句话:RabbitMQ 默认行为对业务不友好,消息可靠性是生产者、broker、消费者三方都要显式建设的,没有免费的安全。

🏗 系统架构师 ​

分两种情况:

  • mandatory 标志未设置(默认):消息不可路由时直接丢弃。交换机按 binding 找不到队列,或路由键不匹配,消息无声消失,连消费端都不知道存在过这条消息——这是排查"消息丢了"的高频原因;
  • 设置 mandatory = true:RabbitMQ 会通过 basic.return 把消息退回给生产者,配合 ReturnCallback 可以捕获并落库告警。

相关兜底:交换机不存在时 immediate 失败走 confirm 机制;备份交换机(alternate exchange,AE)可以把不可路由消息自动转到备用队列,我生产上会给核心交换机配 AE,等于给路由失败加了自动停车场,再配监控消费,避免静默丢失。

我的标准动作:生产端开启 publisher confirm + mandatory + ReturnCallback,三件套齐了,"发出去但没进队列"这类问题才有迹可循;消费侧再靠手动 ack + 死信队列闭环,整条链路每一段都有显式的失败处理路径。

💻 全栈开发专家 ​

取决于 mandatory 标志和有没有配置备份交换机(Alternate Exchange):

  • mandatory = false(默认):消息无法路由时直接丢弃,神不知鬼不觉,这是我见过最经典的"消息丢了但不知道"事故来源。
  • mandatory = true:回退给生产者,触发 ReturnCallback。
java
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnCallback((msg, replyCode, replyText, exchange, routingKey) ->
    log.warn("消息路由失败: routingKey={}, reason={}", routingKey, replyText));
  • 备份交换机(推荐兜底):声明交换机时指定 alternate-exchange,路由不到的消息进备份队列,接监控告警 + 人工处理。

我的生产配置:mandatory=true(打日志告警)+ 备份交换机(兜底存储)双保险,再用 rabbitmq_management 的 unroutable 统计做巡检。

另外一个相邻的坑:发布成功 ≠ 路由成功。confirm 回调只代表消息到了 exchange,所以 publisher confirm 和 return 回调要成对开启才能覆盖"到达交换机但路由失败"这个缝隙。