40

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

我已阅读 RabbitMQ 文档。但我对拒绝、nack 和取消方法之间的区别感到困惑。

4

1 回答 1

69

简短的回答:

要重新排队特定消息,您可以选择两者basic.rejectbasic.nackmultiple标志设置为 false。

basic.consume如果您使用消息确认并且在特定时间消费者有未确认的消息并且消费者在没有确认它们的情况下退出,调用也可能导致消息重新传递。

basic.recover将在特定通道上重新传递所有未确认的消息。

长答案:

basic.reject并且basic.nack两者都用于相同的目的 - 丢弃或重新排队特定消费者无法处理的消息(在给定时刻,在某些条件下或根本不处理)。它们之间的主要区别在于basic.nack支持批量消息处理,basic.reject而不支持。

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

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

为了解决这个问题,RabbitMQ 支持basic.nack提供所有功能basic.reject同时还允许批量处理消息的方法。

要批量拒绝消息,客户端将方法的multiple标志设置为. 然后,代理将拒绝所有未确认的、已传递的消息,直到并包括在方法字段中指定的消息。在这方面,补充了.basic.nacktruedelivery_tagbasic.nackbasic.nackbasic.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 同步性

除了勘误表,根据 RabbitMQ 规范 basic.recover有部分支持(不支持使用 requeue=false 进行恢复。)

注意事项basic.consume

basic.consume没有自动确认(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)

其中star( *) 表示该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,它们被死信到死信队列的尾部(当然,通过死信交换)。

PS:

消费消息又名监听新消息在某种程度上不同于直接队列访问(在不关心其他消息的情况下获取一条或多条消息)。有关更多信息,请参阅basic.get方法说明。

于 2014-06-08T17:28:02.203 回答