天天看點

RabbitMQ之mandatory和immediate

mandatory和immediate是AMQP協定中basic.publish方法中的兩個辨別位,它們都有當消息傳遞過程中不可達目的地時将消息傳回給生産者的功能。對于剛開始接觸RabbitMQ的朋友特别容易被這兩個參數搞混,這裡部落客整理了寫資料,簡單講解下這兩個辨別位。

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都沒有消費者,直接把消息返還給生産者,不用将消息入隊列等待消費者了。

在生産者通過channle的basicPublish方法釋出消息時,通常有幾個參數需要設定,為此我們有必要了解清楚這些參數代表的具體含義及其作用,檢視channel接口,會發現存在3個重載的basicPublish方法:

mandatory和immediate上面已經解釋過了,其餘的參數分别是:

exchange:交換機名稱

routingkey:路由鍵

props:消息屬性字段,比如消息頭部資訊等等

body:消息主體部分

本節主要講述mandatory, 下面我們寫一個demo,在RabbitMQ broker中有:

exchange : exchange.mandatory.test

queue: queue.mandatory.test

exchange路由到queue的routingkey是mandatory

這裡先不講目前的exchange綁定到queue中,即:

詳細代碼如下:

運作,之後通過wireshark抓包工具可以看到如下圖所示:

RabbitMQ之mandatory和immediate

這裡可以看到最後執行了basic.return方法,将釋出者發出的消息傳回給了釋出者,檢視協定的arguments參數部分可以看到:reply-text字段值為NO_ROUTE,表示消息并沒有路由到合适的隊列中;

那麼我們該怎麼擷取到沒有被正确路由到合适隊列的消息呢?這時候可以通過為channel信道設定ReturnListener監聽器來實作,具體代碼(main函數部分):

運作結果:

下面我們來看一下,設定mandatory标志且exchange路由到queue中,代碼部分隻需要将:

改為

即可。

通過wireshark抓包如下:

RabbitMQ之mandatory和immediate

可以看到并不會有basic.return方法被調用。檢視RabbitMQ管理界面發現消息已經到達了隊列。

在RabbitMQ3.0以後的版本裡,去掉了immediate參數的支援,發送帶immediate标記的publish會傳回如下錯誤:

“{amqp_error,not_implemented,”immediate=true”,’basic.publish’}”

為什麼移除immediate标記,參見如下版本變化描述:

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.

這段解釋的大概意思是:immediate标記會影響鏡像隊列性能,增加代碼複雜性,并建議采用“TTL”和“DLX”等方式替代。

<a href="http://www.mamicode.com/info-detail-1673003.html">深入學習RabbitMQ(一):mandatory标志的作用</a>

<a href="http://blog.csdn.net/jiao_fuyou/article/details/21594947">RabbitMQ(二)AMQP協定mandatory和immediate标志位差別</a>