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

Mor*_*ich 6 architecture rabbitmq dead-letter

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

描述我预期的消息流的流程图。 说明如下。

外部产生的传入消息被路由到交换器,交换器将它们放入工作队列中。在处理消息期间,消费者可能会由于一些临时错误而失败(想象一下爬虫从网站收到错误 500)。
我们不是拒绝消息并将其再次放置在队列的头部(导致无限循环),而是将拒绝的消息(带有requeue=0)路由到交换器,添加死信队列作为路由键。在这里,每条消息都会收到 X 秒的 TTL,之后该消息将被拒绝,并因此使用路由键 se 路由回原始工作队列的交换器。

然而,查看网上的文献和示例,每个人似乎都建议路由到单独的死信交换:

描述常用消息流的流程图。 说明如下。

外部产生的传入消息被路由到工作交换,工作交换将它们放入工作队列中。如果消费者失败,消息将被拒绝(带有requeue=0),并将被路由到死信交换。死信交换器将消息路由到死信队列,消息 TTL 将在死信队列中过期,再次被拒绝的消息将被路由回工作交换器。


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

IMS*_*SoP 1

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

  • 新消息,可能会路由到多个队列,或者根本没有路由
  • 失败的消息,应仅路由到延迟队列
  • 延迟的消息,应仅路由到失败的单个队列

此模式的实现中,我使用了两个额外的交换(均按需动态声明),以便它尽可能独立于原始路由配置:

  • 原始消息由消费者确认,并手动重新发布到“开始”交换。这允许一些额外的灵活性,例如在消息上设置自定义标头,以及将具有不同 TTL 的多个延迟队列附加到同一工作队列。
  • “开始”交换是一个扇出交换,绑定到特定的“等待”队列,如第二个图中所示。
  • 当“等待”队列中的消息 TTL 到期时,它会被路由到一个单独的“完成”交换,设置为死信交换。
  • 该交换器也是扇出交换器,仅绑定到原始工作队列。这可确保不会为第一次成功处理该消息的其他队列创建额外的消息副本。
  • 因此,消息及其原始路由密钥返回原始队列。