DLX 徐鹤,全稱為 Dead-Letter-Exchange 阎抒,可以稱之為死信交換器沦辙,也有人稱之為死信郵箱灾炭。當(dāng) 消息在一個(gè)隊(duì)列中變成死信 (dead message) 之后茎芋,它能被重新被發(fā)送到另一個(gè)交換器中,這個(gè)交換器就是 DLX 蜈出,綁定 DLX 的隊(duì)列就稱之為死信隊(duì)列田弥。
消息變成死信 ,一般是由于以下幾種情況:
~消息被拒絕 (Basic.Reject/Basic .Nack) 铡原,井且設(shè)置 requeue 參數(shù)為 false;
~消息過期;
~隊(duì)列達(dá)到最大長度偷厦。
DLX 也是一個(gè)正常的交換器,和一般的交換器沒有區(qū)別燕刻,它能在任何的隊(duì)列上被指定 只泼,實(shí)際上就是設(shè)置某個(gè)隊(duì)列的屬性。當(dāng)這個(gè)隊(duì)列中存在死信時(shí)酌儒,RabbitMQ 就會(huì)自動(dòng)地將這個(gè)消息 新發(fā)布到設(shè)置的 DLX上去 辜妓,進(jìn)而被路由到另一個(gè)隊(duì)列,即死信隊(duì)列忌怎〖危可以監(jiān)聽這個(gè)隊(duì)列中的消 息、以進(jìn)行相應(yīng)的處理榴啸,這個(gè)特性與將消息的 TTL 設(shè)置為0 配合使用可以彌補(bǔ) imrnediate 參數(shù) 的功能孽惰。
通過在 channel.queueDeclare 方法中設(shè)置 x-dead-letter-exchange 參數(shù)來為這 個(gè)隊(duì)列添加 DLX
channel.exchangeDeclare("dlx_exchange " , "direct "); // 創(chuàng)建 DLX: dlx_exchange
Map<String,String> args = new HashMap<String,String>();
args.put("x-dead-letter-exchange" , " dlx_exchange "); // 值為交換機(jī)的名字
//為隊(duì)列 myqueue 添加 DLX
channel.queueDeclare("myqueue" , false , false , false , args);
//也可以為這個(gè) DLX 指定路由鍵,如果沒有特殊指定鸥印,則使用原隊(duì)列的路由鍵:
args.put("x-dead-letter-routing-key" , "dlx-routing-key");//
示例:
channel.exchangeDeclare("exchange.dlx" , "direct " , true);
channel.exchangeDeclare( "exchange.normal " , " fanout " , true);
Map<String,String> args = new HashMap<String,String>();
args.put("x-message-ttl " , 10000);
args.put( "x-dead-letter-exchange " , " exchange.dlx");
args.put( "x-dead-letter-routing-key" , " routingkey");
channel.queueDeclare( "queue.normal" , true , false , false , args);
channel.queueBind( "queue.normal " , "exchange .normal" , "");
channel.queueDeclare( "queue.dlx" , true , false , false , null) ;
channel.queueBind( "queue.dlx" , "exchange.dlx " , routingkey");
channel.basicPublish("exchange.normal","rk",MessageProperties.PERSISTENT_TEXT_PLAIN,"dlx".getBytes());
這里創(chuàng)建了兩個(gè)交換器 exchange.normal 和 exchange.dlx 分別綁定兩個(gè)隊(duì)列 queue.normal 和 queue.dlx勋功。
生產(chǎn)者首先發(fā)送一條攜帶路由鍵為 rk 的消息,然后經(jīng)過交換器 exchange.normal 順利地存儲(chǔ)到隊(duì)列 queue.normal 中库说。由于隊(duì)列 queue.normal 設(shè)置了過期時(shí)間為 10s 在這 10s 內(nèi)沒有消費(fèi)者消費(fèi)這條消息狂鞋,那么判定這條消息為過期。由于設(shè)置了 DLX 過期 之時(shí) 消息被丟給交換器 exchange.dlx 中潜的,這時(shí)找到 與exchange.dlx 匹配的隊(duì)列 queue.dlx 最后消息被存儲(chǔ)在 queue.dlx 這個(gè)死信隊(duì)列中骚揍。
對(duì)于 RabbitMQ 來說, DLX 是一個(gè)非常有用的特性 它可以處理異常情況下啰挪,消息不能夠 被消費(fèi)者正確消費(fèi)(消費(fèi)者調(diào)用了 Basic.Nack 或者 Basic.Reject) 而被置入死信隊(duì)列中 的情況信不,后續(xù)分析程序可以通過消費(fèi)這個(gè)死信隊(duì)列中的內(nèi)容來分析當(dāng)時(shí)所遇到的異常情況,進(jìn) 而可以改善和優(yōu)化系統(tǒng)亡呵。 DLX 配合 TTL 使用還可以實(shí)現(xiàn)延遲隊(duì)列的功能抽活。