在RabbitMQ中死信队列的处理方式

8
这里有以下内容:
  • 主题交换机DLE,旨在成为死信交换机
  • 主题交换机E,是“主”交换机
  • 绑定到E的多个队列(EQ1,...,EQn)(并使用x-dead-letter-exchange = DLE初始化),每个队列都有自己的路由键。这些队列是被消费的队列。
  • 对于每个EQn,都有一个DLEQn(使用x-dead-letter-exchange = Ex-message-ttl = 5000初始化),与DLE绑定,并具有与EQn相同的路由键。这些队列不被消费

我想要的是:如果消费者无法处理来自EQn的消息,则使用requeue: false Nacks该消息,并将其发送到DLEQn - 即发送到适当的死信交换机队列。现在,我希望此消息在DLEQn上停留一段时间,然后再次路由回原始队列EQn以进行处理。

尽管我尝试了很多次,但我无法使“重新发送到原始队列”正常工作。我看到消息在DLEQn中停留,并具有所有正确的标头和路由键,但是TTL过期后它们就消失了。

我在这里做错了什么?

3个回答

9
是的,您可以这样做。我们目前正在生产环境中执行此操作,并且效果非常好。代码太长了,无法在此处包含,但我将向您展示我创建的代表该过程的图表。基本思路是第一个 DLX 具有 TTL,一旦 TTL 过期,消息就会进入第二个队列,以便再次发送回原始队列。

它是如何重新发送到原始队列的?是RabbitMQ执行重新发送还是在重试队列上有一个单独的消费者? - Anton Gogolev
3
一个单独的消费者会从“重试重定向队列”中获取消息并查看兔子头。有用的头是“x-death”,里面包含消息来自的交换机和队列。我们使用这个来向许多不同的队列发送消息,这样我们只需要一个“重试重定向队列”。明白吗? - jhilden
非常好用!非常感谢。 - Anton Gogolev
@jhilden 您能告诉我如何维护失败消息的计数吗?您是否使用某些内置功能或者需要维护自定义变量以便在每次重试时递增计数? - Naresh
自定义变量,以下是检查计数的代码:https://gist.github.com/jayhilden/2078872a53c7df0fe45d661861ed2d45 - jhilden
显示剩余4条评论

5
RabbitMQ会检测消息流循环(E->DLE->E->DLE...),并悄无声息地丢弃消息:
来自DLX手册(路由死信消息部分)

死信队列可以形成一个循环。例如,当队列将消息死信到默认交换机而没有指定死信路由键时,就会发生这种情况。如果整个循环是由于消息过期而导致的,则会丢弃这些循环中的消息(即到达同一队列两次的消息)。


我想知道RabbitMQ 3.1(http://www.rabbitmq.com/release-notes/README-3.1.0.txt)中的“25107 permit dead-letter cycles”是否真的允许它们。 - Anton Gogolev
我猜在RabbitMQ用户组(https://groups.google.com/forum/#!forum/rabbitmq-users)中寻求澄清会对这个问题有所帮助。我认为当您使用消息过期时,25107不是您的情况,根据文档,这是丢弃消息的情况(我加粗了那部分)。 - pinepain
好的,我的周期明显不完全是由于到期。将原始消息移动从 E 到 DLE,然后才会使用 TTL。尽管如此,感谢您抽出时间! - Anton Gogolev

3

这篇文章虽然有些旧,但类似问题让我花了几天才找到解决方案,所以我想在这里分享我的解决方案。

我们正在接收TargetQueue中的消息(没有TTL!!!,绑定到TargetExchange),消费者可能会否定。 TargetQueue定义了DLX(RetryExchange),它又绑定了一个相应的队列(RetryQueue,TTL为60秒,TargetExchange定义为DLX)。

因此,如果消费者从TargetQueue否定了一条消息,则该消息排队在RetryQueue中,并且由于TTL,该消息再次被否定并重新排队在原始的TargetQueue中。关键在于,TargetQueue可能没有定义TTL,否则像这样的消息将出现在RabbitMQ日志中:

检测到死信队列循环:[<<"TargetQueue">>,<<"RetryQueue">>,<<"TargetQueue">>]

因此,最终的解决方案非常简单(只需要一个消费者)。 我从https://medium.com/@igkuz/ruby-retry-scheduled-tasks-with-dead-letter-exchange-in-rabbitmq-9e38aa39089b得到了最终的灵感。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接