RabbitMQ死信邮箱(DLX)

DLX,Dead-Letter-Exchange(死信邮箱)

利用DLX,当消息在一个队列中变成死信后,它能被重新publish到另一个Exchange,这个Exchange就是DLX。消息变成死信一向有以下几种情况:

消息被拒绝(basic.reject or basic.nack)并且requeue=false

消息TTL过期

队列达到最大长度

DLX也是一下正常的Exchange同一般的Exchange没有区别,它能在任何的队列上被指定,实际上就是设置某个队列的属性,当这个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的Exchange中去,进而被路由到另一个队列,publish可以监听这个队列中消息做相应的处理,这个特性可以弥补RabbitMQ 3.0.0以前支持的immediate参数中的向publish确认的功能。

Map args =newHashMap();

args.put("x-dead-letter-exchange","some.exchange.name");

channel.queueDeclare("myqueue",false,false,false, args);

你也可以为这个DLX指定routing key,如果没有特殊指定,则使用原队列的routing key

args.put("x-dead-letter-routing-key","some-routing-key");

死信”被republish时,会在消息的header中增加一个叫做“x-death"的数组内容,包含了以下字段内容:

在使用immediate参数时,如果消费者拒收消息这个应答是没有办法通知到publish的,但是利用DLX,拒收的消息会变成“死信”,这个死信会被republish到DLX路由的队列中去,分析这个新的信息的header中的x-death内容,可以判断出消息变成死信的原因,这样publish端可以做更灵活的处理。


TTL和DLX结合使用的一种场景

假如我需要一个这样的应用场景,consumer可以无条件退出,退出后我希望它监听的队列也一并删除掉,但是如果队列如果有消息,要求消息能被转发到DLX队列。

如果用queue的AUTO_DELETE功能,则consumer退出后,不管队列中是否有消息,队列都会被删除,这个方法不行。

我们可以这样的变通实现:

1、将队列的"x-expires"参数为300S,即队列在没有消费者空闲300S后将被自动删除 )

2、将队列的"x-message-ttl"参数为30S,即消息只存活30S

3、在生产者publish消息时,设置 immediate属性,即要求一publish时一定有一个消费者存在

这样子生产者不停的将消息成功放进了队列,由于publish时判断了immediate属性,也就是说publish消息时,消费者是一定存在的,假如由于消费者处理的不及时导致消息有所堆积,在30S内还没有处理的话,这些消息将会被republish到DLX路由的队列中保存,即使在这时消费者异常退出了,也没关系,因为队列至少也将在300S后才自动删除,有足够长的时间让所有消费都republish至DLX队列

你可能感兴趣的:(RabbitMQ死信邮箱(DLX))