鉴于在 RabbitMQ 的使用过程中，很多同学搞不清楚 basic.publish 接口中 mandatory 和 immediate 的背后含义，特搜集整理网上相关文章，以便彻底理解该问题。
===== 我是三体分隔线 =====
在 RabbitMQ 3.0.0 版本的 README 中如是说：
另外一篇 文章 中也对该变更进行了说明
... feature removal 23896 remove support for AMQP's "immediate" publish mode ...
RabbitMQ 官网上针对 AMQP-0-9-1 协议中 basic.publish 方法的说明。
Removal of "immediate" flag What changed? We removed support for the rarely-used "immediate" flag on AMQP's basic.publish. Why on earth did you do that? Support for "immediate" made many parts of the codebase more complex, particularly around mirrored queues. It also stood in the way of our being able to deliver substantial performance improvements in mirrored queues. What do I need to do? If you just want to be able to publish messages that will be dropped if they are not consumed immediately, you can publish to a queue with a TTL of 0. If you also need your publisher to be able to determine that this has happened, you can also use the DLX feature to route such messages to another queue, from which the publisher can consume them.
...publish(short reserved-1, exchange-name exchange, shortstr routing-key, bit mandatory, bit immediate) ... bit mandatory This flag tells the server how to react if the message cannot be routed to a queue. If this flag is set, the server will return an unroutable message with a Return method. If this flag is zero, the server silently drops the message. The server SHOULD implement the mandatory flag. bit immediate This flag tells the server how to react if the message cannot be routed to a queue consumer immediately. If this flag is set, the server will return an undeliverable message with a Return method. If this flag is zero, the server will queue the message, but with no guarantee that it will ever be consumed. The server SHOULD implement the immediate flag. ...
下面是网上找到的 关于 mandatory 和 immediate 两个属性的讨论 。
AMQP's basic.publish method has two flags - mandatory and immediate - that trigger checks at the server and result in messages getting returned to clients with basic.return when the necessary conditions aren't met. See http://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.publish for the details. I can just about see why 'mandatory' may be useful, but 'immediate' has always struck me as a bizarre and I fear that anybody using it may well do so w/o fully understanding the semantics - can't blame them, it *is* bizarre. Because of that, and since it complicates the code in many places, we are considering dropping support for 'immediate'. So is anybody actually using the 'immediate' flag?
I'd support this move. Have never used "immediate".
Just curious, are there any benefits for removing it -- is it preventing / complicating support for other features?
Yes. It accounts for a fair bit logic scattered across the code base and we've just found another case where in order to significantly improve performance of mirrored queues we'd have to make yet more code aware of the 'immediate' flag.
Well, the specific thing that we've bumped into in this case is that support for immediate is greatly slowing down HA queues. We could be smarter about this, at the cost of tangling the code further. So if we want to make HA queues faster (and we do!) we can either keep immediate and add a bunch of code at the same time, or remove immediate and delete a bunch of code. There are quite a number of places where we have notably greater complexity just to support this weird feature that (we suspect) no-one uses. It just feels very disproportionate.
Matthias / Simon, thanks for the background. I'm not using the immediate flag, but I've considered using it. Admittedly, I'm not fully aware of exactly how it works. It would be helpful to have a better understanding of the semantics. Can you explain what the publisher is notified of (if anything?) when there are 10 queues bound to an exchange named HighPriority, a message with immediate flag true is published to HighPriority, and 7 out of the 10 queues have the message consumed immediately.
No notification is sent to the publisher in that case. A basic.return is only sent if *no* queues were able to send the message to a consumer immediately.
Here are a few more warts about 'immediate':
- while a message might get sent out to a consumer straight away, there is of course no guarantee that such a message will reach the consumer, get processed and ack'ed. If any of these steps go wrong the message will end up in the queue (unless the consuming happened with no-ack, in which case it is simply lost), even though supposedly it was delivered immediately.
- a queue can have a consumer and yet 'immediate' delivery may fail (and a basic.return issued) because: a) the consumer isn't quick enough and a backlog of messages has built up, b) the consumer has configured a 'basic.qos' prefetch count and that the limit has been reached
- the interaction with transactions is not at all obvious. This does apply to 'mandatory' too though. See http://www.rabbitmq.com/semantics.html#tx
Matthias, thanks for the explanation. Considering your points below, I now have a better understanding on your thought that the actual use-cases and practicality to publish messages with the immediate flag are minimal. In light of the details, I won't be using it -- faster mirrored queues sounds better to me. :o)
Couldn't it be possible emulate immediate by delivering to a TTL'ed queue, then having a dead-letter queue that the publisher consumes from to be notified that a message has not been consumed?
Yes. It's not an exact emulation, but arguably more flexible, e.g. it gives greater control over how the 'returned' messages are dealt with.
Plus 1 for faster HA queues and less complexity in the code base.
下面是 stackoverflow 上关于上述两个属性的讨论。
The immediate and mandatory fields are part of the AMQP specification, and are also covered in the RabbitMQ FAQ to clarify how its implementers interpreted their meaning: Mandatory This flag tells the server how to react if a message cannot be routed to a queue. Specifically, if mandatory is set and after running the bindings the message was placed on zero queues then the message is returned to the sender (with a basic.return). If mandatory had not been set under the same circumstances the server would silently drop the message. Or in my words, "Put this message on at least one queue. If you can't, send it back to me." Immediate For a message published with immediate set, if a matching queue has ready consumers then one of them will have the message routed to it. If the lucky consumer crashes before ack'ing receipt the message will be requeued and/or delivered to other consumers on that queue (if there's no crash the messaged is ack'ed and it's all done as per normal). If, however, a matching queue has zero ready consumers the message will not be enqueued for subsequent redelivery on from that queue. Only if all of the matching queues have no ready consumers that the message is returned to the sender (via basic.return). Or in my words, "If there is at least one consumer connected to my queue that can take delivery of a message right this moment, deliver this message to them immediately. If there are no consumers connected then there's no point in having my message consumed later and they'll never see it. They snooze, they lose."