bigywater.tech
RabbitMQ · 6

mandatory 与 return:消息不可路由时去哪了

消息发出去没人要,默认是悄悄丢掉。mandatory 标志让 broker 把它退回来,但退回来的是什么、什么时候到、什么情形才算“不可路由”?有备用交换机时又怎样?这篇用 TCP 代理看线上帧,并逐种情形验证。

312
路由不到的 mandatory 消息收到的 reply-code(NO_ROUTE)
1000 / 1000
无 confirm 时连发 1000 条不可路由消息,最终收到的 Return 数,顺序不变
0 条
设了备用交换机且它能接住时,被退回的消息数

Basic.Return

实测 · 本机执行输出
  线上帧: [(1, 'Basic.Publish'), (1, 'ContentHeader'), (1, 'ContentBody'), (1, 'Basic.Return'), (1, 'ContentHeader'), (1, 'ContentBody')]
  Basic.Return: reply-code=312 reply-text='NO_ROUTE' exchange='x.d' routing-key='nomatch'
  退回的属性: message_id=id-42 content_type=text/plain headers={'trace': 'abc'} delivery_mode=2;body=b'hello-return'

发布时 mandatory=True 且消息无法路由到任何队列,broker 会发回 Basic.Return(后面跟内容头和内容体),带 reply-code 312 NO_ROUTE,以及原来的 exchange、routing key、属性和消息体。

异步

实测 · 本机执行输出
  1000 条发布调用本身花了 120 ms,这时已处理的 Return 回调 0 个;再处理 1 秒的网络事件之后共收到 1000 个,顺序是否与发布一致: True

Return 不是发布调用的返回值,而是 broker 之后推回来的一个帧。发布方要注册回调并保持事件循环运行;如果同时开了 confirm,Return 一定先于该条的 Ack。

不可路由的定义

实测 · 本机执行输出
  direct 有绑定 key 匹配     → 已路由
  direct key 不匹配        → 退回 312
  fanout 没有任何绑定         → 退回 312
  topic 匹配 a.*          → 已路由
  topic 不匹配             → 退回 312
  headers 匹配            → 已路由
  headers 不匹配           → 退回 312
  exchange 不存在          → channel 被关

direct/topic/headers 不匹配、没有任何绑定的 fanout 都算不可路由;exchange 不存在不是 Return,而是 channel 错误(channel 被关闭)。

备用交换机

实测 · 本机执行输出
  发了 5 条 mandatory(2 条能路由、3 条路由不到):q.main = 2 条,q.ae = 3 条,被退回 0 条
  q.ae 里的消息: ['stray1', 'stray2', 'stray3']
  如果备用交换机本身也路由不到,才会退回:
    x.main2 → x.ae2(没有绑定): 被退回 1 条,reply-code=312

给 exchange 设置 alternate-exchange 参数后,路由不到的消息转给它;转成功就算路由成功。只有备用交换机也路由不到才会退回。

开销

实测 · 本机执行输出
  mandatory=False 中位数 526 ms(最小 512);mandatory=True 中位数 523 ms(最小 517)

可路由时 mandatory 没有可测的额外开销(526 ms 对 523 ms)。

分步演示

mandatory 与 return
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / RabbitMQ 4.3.6 / Erlang/OTP 28.5 / pika 1.4.4(Homebrew 与临时虚拟环境);所有节点都是本机自己起的 RabbitMQ 进程(127.0.0.1,端口 9500 以上,每个实验独立的数据目录与节点名,不连任何外部服务);命令输出来自真实的 rabbitmqctl 与管理 API,发布与消费用 pika 的真实连接;计时用 time.perf_counter,数字每次运行会有小幅抖动。第一、二、三、四节经过自己写的 TCP 代理(第一节看线上帧);第五节直连 broker,不经过代理,mandatory 交替 7 轮取中位数,不开 confirm
    • 没有验证:与 publisher confirm 同时开启时 Return / Ack 的顺序在高并发下的表现(第 5 篇只在单条上看到先 Return 后 Ack);quorum / stream 队列;immediate 标志(3.0 起已去掉);集群中跨节点路由失败;备用交换机链很长时的行为
    京ICP备2026067502号-1京公网安备11010502063487号