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