來自一個隊列的消息能夠被當作‘死信’,即被從新發布到另一個「exchange」去,這樣的狀況有:
- 消息被拒絕 (basic.reject or basic.nack) 且帶 requeue=false 參數
- 消息的TTL-存活時間已通過期
- 隊列長度限制被超越(隊列滿)
Dead letter exchanges (DLXs) are normal exchanges.
For any given queue, a DLX can be defined by clients using the queue's arguments, or in the server using policies.
Dead Letter Pattern
「死信」模式指的是,當消費者不能處理接收到的消息時,將這個消息從新發布到另一個隊列中,等待重試或者人工干預。
這個過程當中的exchange和queue就是所謂的"Dead Letter Exchange 和 Queue"。
關鍵是如何區分「消費失敗」和「處理失敗」?消費失敗須要送到死信隊列,而處理失敗不須要。大部分狀況都屬於「處理失敗」。
Dead-Letter-Exchange, routing-key, queue 均可以從 rabbitmq 的管理後臺配置。
若是用 Spring-rabbitmq 來使用 Dead-Letter-Exchange 和 Queue 須要對。
從 3.9 Exception Handling 能夠知道,設置 defaultRequeueRejected = false 會丟棄消息或者從新發布到死信隊列中。
若是是 Convert 出現異常,那麼會直接 "reject-dont-requeue".
<
rabbit:listener-container
defaultRequeueRejected="false"
connection-factory
=
"connectionFactory"
>
<
rabbit:listener
ref
=
"listener"
method
=
"listen"
queue-names
=
"async_request_queue"
/>
</rabbit:
listener-container>
|
也能夠在 handler 中拋出 "AmqpRejectAndDontRequeueException" 來告訴spring容器,不要從新requeue這條消息。
而後配置 Dead Letter Exchange 並綁定 Dead Letter Queue.
<rabbit:queue name="q.with.dlx">
<rabbit:queue-arguments>
<entry key="x-dead-letter-exchange" value="dlx"/>
<entry key="x-message-ttl" value="10000" value-type="java.lang.Long"/>
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:queue name="dlq"/>
<rabbit:direct-exchange name="dlx">
<rabbit:bindings>
<rabbit:binding key="q.with.dlx" queue="dlq"/>
</rabbit:bindings>
</rabbit:direct-exchange>
若是 exchange 或者 queue 是 鏡像/持久的,那麼須要先刪除再啓動 spring-amqp 程序,這樣 xml 中的 exchange 和 queue 配置才能生效,
不然服務器端配置不會修改,啓動生成者時拋異常,啓動失敗。
對於部署,能夠考慮使用新隊列來避免須要先刪除已有隊列的問題。
常見問題:
緣由:queue已經存在,可是啓動 consumer 時試圖設定一個 x-dead-letter-exchange 參數,這和服務器上的定義不同,server 不容許因此報錯。若是刪除 queue 從新 declare 則不會有問題。或者經過 policy 來設置這個參數也能夠不用刪除隊列。
參考: