【发布时间】:2011-09-14 12:27:18
【问题描述】:
我们有一个持久的 RabbitMQ 队列。当消费者从队列中获取项目时,它会处理它然后确认它。如果消费者未能处理该项目,它会打印一个错误,期望有人解决问题并停止。没有发送确认。当消费者重新启动它接收到的项目时,它是队列中的下一个项目,而不是没有 ack 的项目。 Basic.Recover() 没有帮助(使用 .NET 客户端)。 任何如何使它作为队列工作的想法 - 如果它没有被确认,总是得到第一个项目。
【问题讨论】:
我们有一个持久的 RabbitMQ 队列。当消费者从队列中获取项目时,它会处理它然后确认它。如果消费者未能处理该项目,它会打印一个错误,期望有人解决问题并停止。没有发送确认。当消费者重新启动它接收到的项目时,它是队列中的下一个项目,而不是没有 ack 的项目。 Basic.Recover() 没有帮助(使用 .NET 客户端)。 任何如何使它作为队列工作的想法 - 如果它没有被确认,总是得到第一个项目。
【问题讨论】:
消息可以通过两种方式使用 noAck=false 或 noAck=true
noAck 是 Model.BasicConsume 和 Model.BasicGet 的参数
当 noAck 设置为 true 时,消息在传递后会自动从队列中删除。如果 noAsk 设置为 false,则仅当您调用 basicAck 时才会删除消息。
如果 noAck=false 并且您不调用 basicAck 消息将保留,但在您重新启动应用程序(或关闭首先使用它的连接)之前,您不会收到其他消费者的消息。如果您调用 BasicReject,则消息将重新发送给订阅者。
我希望这会有所帮助。
【讨论】:
见this entry in the RabbitMQ FAQ。虽然您可能希望 RabbitMQ 将未确认的消息重新排队回到队列的头部(在您的消费者将它们拉下之前它们所在的位置),但正如您所经历的那样,现实可能会有所不同。
所以并不是Basic.Recover() 不起作用(消息被放回队列中以供将来重新处理)只是它没有按您预期的方式工作。
我脑海中的某件事告诉我,您也许能够通过将预取计数设置为 1 并且在任何时候最多只有一个消费者连接到队列来获得您想要的行为时间,但我不能保证是这样。值得一试。然而,即使它有效,也不能永远依赖于这种情况,并且由于预取计数如此之低,您的消费者的消息/秒性能可能会受到影响。
【讨论】:
RabbitMQ 似乎已修复此问题的一部分since 2.7.0,因为现在消息将按发布顺序重新排队。虽然如果您的队列有多个订阅者,您可能仍然会收到不符合原始顺序的消息。
【讨论】:
您可以通过拥有一对队列、一个高优先级和一个普通优先级来获得这种行为。将预取计数设置为 1,然后使用 basic.get 在队列之间交替。大多数情况下,优先级队列是空的,但是当您想重新排队时,请再次将消息发布到高优先级队列中。
这适用于您有多个进程使用消息流的情况,并且一个进程决定退出消息。该消息将几乎立即被另一个进程拾取。
【讨论】: