如何在RabbitMQ中重新排队消息

时间:2014-06-08 15:50:25

标签: rabbitmq amqp node-amqp

在消费者收到消息后,消费者/工作人员会进行一些验证,然后调用Web服务。在此阶段,如果发生任何错误或验证失败,我们希望将消息放回最初使用的队列。

我已阅读RabbitMQ文档。但我对reject,nack和cancel方法之间的区别感到困惑。

1 个答案:

答案 0 :(得分:51)

简答:

要重新排列特定消息,您可以同时选择basic.rejectbasic.nack并将multiple标记设置为false。

如果您正在使用消息确认,那么

basic.consume调用也可能导致重新传递的消息,并且消费者在特定时间和消费者退出时都会收到未确认消息,而不会对其进行处理。

basic.recover将在特定频道重新发送所有未启用的消息。

答案很长:

basic.rejectbasic.nack都用于同一目的 - 删除或重新排列特定消费者无法处理的消息(在特定时刻,某些条件下或根本不会)。它们之间的主要区别在于basic.nack支持批量邮件处理,而basic.reject则不支持。

官方RabbitMQ网站上的Negative Acknowledgements文章中描述了这种差异:

  

AMQP规范定义了basic.reject方法,该方法允许客户拒绝单个传递的消息,指示代理丢弃它们或重新排队。不幸的是,basic.reject不支持批量负面确认消息。

     

要解决此问题,RabbitMQ支持basic.nack方法,该方法提供basic.reject的所有功能,而也允许批量处理消息

     

要批量拒绝邮件,客户端会将multiple方法的basic.nack标记设置为true。然后,代理将拒绝所有未确认的,已发送的消息,包括delivery_tag方法的basic.nack字段中指定的消息。在这方面,basic.nack补充了basic.ack的批量确认语义。

注意,basic.nack方法是RabbitMQ特定的扩展,而basic.reject方法是AMQP 0.9.1规范的一部分。

对于basic.cancel方法,它用于通知服务器客户端停止消息消费。请注意,客户端可能会在发送接收basic.cancel回复的cancel-ok方法之间收到任意消息编号。如果客户端使用了消息确认,并且它有任何未确认的消息,则它们将被移回到最初消耗的队列中。

basic.recover在RabbitMQ中有一些限制:它   - basic.recover with requeue=false   - basic.recover synchronicity

除了勘误表,according to RabbitMQ specs basic.recover有部分支持(不支持使用requeue = false恢复。)

关于basic.consume的注意事项:

basic.consume在没有auto-ack(no­ack=false)的情况下启动并且有一些待处理的消息没有被激活的消息时,那么当消费者被取消(死亡,致命错误,异常等)时,该等待处理消息将被重新传递。从技术上讲,在消费者释放它们(ack / nack / reject / recover)之前,不会处理这些待处理的消息(甚至是死信函)。只有在那之后它们才会被处理(例如,无法复制)。

例如,假设我们连续发布了5条消息:

Queue(main) (tail) { [4] [3] [2] [1] [0] } (head)

然后消耗其中的3个,但不要它们,然后取消消费者。我们将遇到这种情况:

Queue(main) (tail) { [4] [3] [2*] [1*] [0*] } (head)

星号(*)注意到redelivered标志设置为true

假设我们有死信交换集的情况和死信函的队列

Exchange(e-main)                                   Exchange(e-dead) 
  Queue(main){x-dead-letter-exchange: "e-dead"}       Queue(dead) 

并假设我们发布了5条消息,expire属性设置为5000(5秒):

Queue(main) (tail) { [4] [3] [2] [1] [0] } (head)
Queue(dead) (tail) { }(head)

然后我们从main队列中消耗3条消息并保持10秒钟:

Queue(main) (tail) { [2!] [1!] [0!] } (head)
Queue(dead) (tail) { [4*] [3*] } (head)

其中感叹号(!)代表未包装的消息。此类消息无法传递给任何消费者,并且通常无法在管理面板中查看。但是,让我们取消消费者,请记住,它仍然保留了3条未发送的消息:

Queue(main) (tail) { } (head)
Queue(dead) (tail) { [2*] [1*] [0*] [4*] [3*] } (head)

所以现在头部的3条消息被放回到原始队列,但由于它们有每个消息的TTL设置,它们已经死信到死信队列的尾部(当然,通过死信交换)。

<强> P.S:

使用消息即侦听新消息与直接队列访问有某种不同(获取一个或多个消息而不关心其他消息)。有关详情,请参阅basic.get方法说明。