1. 概述
mandatory和immediate是AMQP协议中basic.publish方法中的两个标识位,它们都有当消息投递过程中不可达目的地时将消息返回给生产者的功能。
mandatory
当mandatory标志位设置为true时,如果exchange根据自身类型和消息routeKey无法找到一个符合条件的queue,那么会调用basic.return方法将消息返回给生产者(Basic.Return + Content-Header + Content-Body);当mandatory设置为false时,出现上述情形broker会直接将消息扔掉。
immediate
当immediate标志位设置为true时,如果exchange在将消息路由到queue(s)时发现对应的queue此时没有消费者,那么这条消息不会放入队列中。当与消息routeKey关联的所有queue(一个或者多个)都没有消费者时,该消息会通过basic.return方法返还给生产者。
概括来说,mandatory标志告诉服务器至少将该消息route到一个队列中,否则将消息返还给生产者;immediate标志告诉服务器如果该消息关联的queue上有消费者,则马上将消息投递给它,如果所有queue都没有消费者,直接把消息返还给生产者,不用将消息入队列等待消费者了。
2使用
众所周知,RabbitMQ在保证消息可靠投递的实现过程中有个参数mandatory
。该参数的作用是,当消息的mandatory
设置为true
时,消息投递到Exchange之后,如果Exchange无法将该消息路由到任何一个队列,那么该消息将返回给生产者。当设置为false,RabbitMQ将直接丢弃该消息。
- 在了解了这个背景之后,分为使用和不使用
spring-boot-starter-amqp
两种场景。- 在未使用
spring-boot-starter-amqp
的场景下,我们直接给channel设置监听器并且将消息的mandatory
设置为true
,即可实现消息无法路由之后通过该channel将消息return给生产者。即:- channel设置监听回调函数。
- 消息的
mandatory
设置为true
。
- 而在使用
spring-boot-starter-amqp
的场景下,除了设置mandatory,还需要设置spring.rabbitmq.publisher-returns
,这个参数的作用是什么呢。并且在SpringBoot下尽管设置了mandatory
为true
,但是同时spring.rabbitmq.publisher-returns
为false
,还是无法监听到路由失败return的消息。
- 在未使用
使用spring-boot-starter-amqp需要配置如下:
# 当exchange无法找到任何一个合适的queue时,将消息return给生产者
spring.rabbitmq.template.mandatory=true
# 必须设置为true,否则消息消息路由失败也无法触发Return回调
spring.rabbitmq.publisher-returns=true
原因:
用SpringBoot的代码,在回调函数出打断点查看调用链。
监听器是被ChannelIN.processAsync()
方法触发的。
ChannelIN.processAsync()
中遍历了所有的监听器。那么查看监听器是如何被加入returnListeners
集合的即可。
接下来分析为什么将spring.rabbitmq.publisher-returns
设置为flase
的场景下我们的监听器为什么没有被加入集合。
在添加回调监听器的地方打上断点
回到SpringBoot环境下Debug: 分析监听器是如何被加入到集合的。
发现这段代码会根据confirmsOrReturnsCapable
的值判断是否需要向Channel添加监听器,而confirmsOrReturnsCapable
的值来自于RabbitProperties
的isPublisherReturns
即:只有将spring.rabbitmq.publisher-returns
设置为true
,才会向Channel添加我们设置的监听回调函数。
3.消息的可靠性 publisher-confirms: true
生产者与broker之间的消息确认称为public confirms,public confirms机制用于解决生产者与Rabbitmq服务器之间消息可靠传输,它在消息服务器持久化消息后通知消息生产者发送成功