RabbitMQ NACK 消息

RabbitMQ NACK messages

我的经验:在publish/subscribe场景中,如果订阅者nack了一条消息,nacked消息会立即重新排队到队列的前面,这将是订阅者收到的下一条消息。

有没有办法避免这种情况?是否有可能以下一条消息肯定不是刚刚 nacked 的方式 nack 一条消息?

我正在使用 Node.js 和 amqp.node 与 RabbitMQ 通信

问题:我的经验:在publish/subscribe场景中,如果订阅者nack了一条消息,那么nacked的消息会立即重新排队到队列的前面,这将是订阅者收到的下一条消息.

Yes that is correct. When a message is requeued with channel.basicNack, it will be placed to its original position in its queue, if possible. If not (due to concurrent deliveries and acknowledgements from other consumers when multiple consumers share a queue), the message will be requeued to a position closer to queue head. Source: https://www.rabbitmq.com/nack.html

问:有没有办法避免这种情况?是否有可能以下一条消息肯定不是刚刚 nacked 的方式 nack 一条消息?

nack 无法实现此目的。实现此目的的一种方法是将消息重新发布回需要 nack 的队列。

  • 收到消息并立即发回ack。
  • 处理消息,如果成功什么也不做。
  • 如果失败不发送 nack 而是重新发布消息返回给 排队。

Nack 是对 AMQP 协议的特定于 RabbitMQ 的增强。它允许消息的消费者在消息 成功处理时通知服务器。我想你已经走到这一步了。

这里有趣的是,AMQP 最初并不认为 Nack 是必要的。为什么?因为消费者无法处理消息时的 AMQP 行为是消费者 关闭连接而不 ack 发送消息 。在这种情况下,消息会按照它原来的顺序自动重新排队,并传递给设置了 redelivered 标志的下一个可用消费者。

为什么会这样?

因为 Nack 表示消费者有问题,而不是消息。如果消息本身是错误的,AMQP 假定消费者足够聪明,可以识别这一点,ack 消息,然后采取程序员设计的任何其他步骤来处理错误消息。

RabbitMQ 添加了带有 requeue 参数的 Nack 函数。默认情况下,requeue 为 true - 意味着在 nack 时,代理将重新排队消息。这符合 AMQP 设计的初衷。但是,如果您将 requeue 传递为 false,则代理会将消息设为死信。这是通常由智能应用程序架构师使用 AMQP 设计的行为的快捷方式,因此您可以将其视为对程序员的便利。

两者的区别

在第一种情况下,Nack 表示消息使用者有问题。消费者在解决问题时应该让自己离线。在第二种情况下,Nack 表示消息有问题。第一种情况是暂时性问题,而第二种情况是永久性故障。

如果我现在但可能稍后无法处理特定消息怎么办?

如果您的消息传递结构设计得当,这将永远不会发生。如果一条特定消息需要与另一条消息不同的处理路径或资源,则该消息类型应该有自己的队列。当处理这些消息的依赖项离线或不可用时,该队列的消费者可以停止消费。

作为一般规则,您可以考虑如果您的消费者正常运行,您应该始终确认消息,无论处理消息的结果如何(无论是错误还是成功)。

您可以 reject/nack 带有 requeue = false 的格式错误的消息将其路由到死信交换并对其执行操作(绑定队列并使用例如 post 验尸分析),或者选择确认它并做任何必要的事情(例如发送其他消息,如 BadRequest 消息,...)。

(几乎)永远不会出现问题的最佳方法是将确认作为处理消息的最后一个操作,并准备好处理重新传递(幂等性可能会有所帮助)。您可以在交付时立即确认,但如果消费者崩溃,消息就会丢失(您需要自己处理这种情况 - 有很多模式)。

希望对您有所帮助。