RabbitMQ(四)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确认的功能。


JAVA的SDK设置

channel.exchangeDeclare("some.exchange.name", "direct");

Map<String, Object> args = new HashMap<String, Object>();
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");

还可以使用policy来配置:

rabbitmqctl set_policy DLX ".*" '{"dead-letter-exchange":"my-dlx"}' --apply-to queues

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

  • queue - the name of the queue the message was in before it was dead-lettered,
  • reason - see below,
  • time - the date and time the message was dead lettered as a 64-bit AMQP format timestamp,
  • exchange - the exchange the message was published to (note that this will be a dead letter exchange if the message is dead lettered multiple times), and
  • routing-keys - the routing keys (including CC keys but excluding BCC ones) the message was published with.
  • original-expiration (if the message was dead-letterered due to per-message TTL) - the originalexpiration property of the message. The expiration property is removed from the message on dead-lettering in order to prevent it from expiring again in any queues it is routed to.

The reason is a name describing why the message was dead-lettered and is one of the following:

  • rejected - the message was rejected with requeue=false,
  • expired - the TTL of the message expired; or
  • maxlen - the maximum allowed queue length was exceeded.

在使用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而想的,实际应用中可以有其它代替方案来实现,就当学习了。


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RabbitMQ 中,可以使用死信功能(DLX)来处理过期的消息。当消息过期时,你可以将其发送到另一个队列进行处理。以下是使用 Python 和 pika 库设置死信功能的示例代码: 首先,我们需要创建两个队列:一个用于发送消息,另一个用于处理过期的消息。 ```python import pika # 连接 RabbitMQ 服务器 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 声明发送消息的队列,并设置消息的过期时间和死信交换机 channel.queue_declare(queue='my_queue', arguments={ 'x-message-ttl': 10000, # 消息过期时间为 10 秒 'x-dead-letter-exchange': 'my_dlx' # 死信交换机的名称 }) # 声明处理过期消息的队列和交换机 channel.exchange_declare(exchange='my_dlx', exchange_type='direct') channel.queue_declare(queue='my_dlx_queue') channel.queue_bind(queue='my_dlx_queue', exchange='my_dlx', routing_key='') # 关闭连接 connection.close() ``` 在上述示例中,我们通过 `channel.queue_declare()` 方法声明了一个名为 'my_queue' 的队列,并在 `arguments` 参数中设置了 `x-message-ttl` 属性为 10000 毫秒,即 10 秒。同时,我们还设置了 `x-dead-letter-exchange` 属性为 'my_dlx',指定了死信交换机的名称。 接下来,我们声明了处理过期消息的队列 'my_dlx_queue' 和交换机 'my_dlx',并使用 `channel.queue_bind()` 方法将队列和交换机进行绑定。 当消息在 'my_queue' 队列中过期时,它将被发送到 'my_dlx_queue' 队列进行处理。 注意:以上示例仅涵盖了如何设置死信功能。实际上,你还需要编写代码来消费 'my_dlx_queue' 队列中的消息,并进行相应的处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值