RabbitMQ 中需要单独的死信交换吗?

Separate dead letter exchange necessary in RabbitMQ?

我已经为我的队列设置了一个死信路由,以延迟几秒钟重新排队被拒绝的消息,防止临时消费者错误阻塞队列。我已经设置好了,所以工作队列和死信队列都绑定到同一个交换:

Externally produced, incoming messages are routed to the exchange, which places them in the work queue. During processing the message, a consumer might fail due to some temporary errors (think a crawler receiving an error 500 from a website).
Instead of rejecting the message and having it placed at the head of the queue again (leading to an infinite loop), we route rejected messages (with requeue=0) to the exchange, adding the dead letter queue as the routing key. Here, every message receives a TTL of X seconds, after which it will be rejected, and therefore routed back to the exchange with the routing key se to the original work queue.

不过网上看文献和例子,好像大家都推荐路由到单独的死信交换:

Externally produced, incoming messages are routed to the work exchange, which places them in the work queue. If a consumer fails, messages are rejected (with requeue=0) and will be routed to the dead letter exchange. The dead letter exchange routes the messages to the dead letter queue, where the message TTL will expire, and the again-rejected messages will be routed back to the work exchange.


与第一个设计相比,第二个设计有一些重要的优势吗?我无法识别任何东西,但话又说回来,我对 RabbitMQ 不太有信心。

这取决于您使用的交换类型,以及您需要执行的其他路由操作。如果您对原始消息和 re-queued 消息使用相同的交换,则需要区分:

  • 新消息,可能会被路由到多个 queue,或者根本 none
  • 失败的消息,应该只路由到延迟 queue
  • 延迟的消息,应该只路由到失败的单个 queue

my implementation of this pattern中我使用了两个额外的交换(都是动态声明的on-demand)以便它尽可能独立于原始路由配置:

  • 原始消息由消费者确认,并手动re-published“开始”交换。这允许一些额外的灵活性,例如在消息上设置自定义 headers,并在同一作品 queue.
  • 上附加不同 TTL 的多个延迟 queue
  • “开始”交换是一个扇出交换,绑定到特定的“等待”queue,如您的第二张图表所示。
  • 当消息 TTL 在“等待”queue 中过期时,它被路由到一个单独的“完成”交换,设置为死信交换。
  • 该交换也是一个扇出交换,仅绑定到原始作品 queue。这确保不会为第一次成功处理它的其他 queue 创建消息的额外副本。
  • 因此,消息以原始 queue 的形式返回,并带有其原始路由密钥。