來自一個隊列的消息可以被當做‘死信’,即被重新發布到另外一個“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: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 來設置這個參數也可以不用刪除隊列。
參考
blog
參考: