根据Consumer Acknowledgements上的RabbitMQ文档:
将消息重新排队后,如果可能的话,它将被放置到其队列中的原始位置。否则(由于多个消费者共享一个队列时,由于并发传递和来自其他消费者的确认),邮件将重新排队到更靠近队列头的位置。
因此对于单个客户端使用者,如果服务器队列最初是
尾巴[c b a]头
并且客户消费者使用了头消息(“ a”),则服务器队列应变为:
尾巴[c b]头
然后,如果客户消费者对已处理的消息进行处理,则该消息应在服务器队列的开头重新排队(根据文档,其“原始位置”),并且服务器队列应变为:
尾巴[c b a]头
最后,客户消费者应再次消费相同的头消息(“ a”)。
但这不是我使用Python库Pika观察到的。我观察到的是,被拒绝的消息在服务器队列的末尾而不是在头部(“原始位置”)被重新排队。 RabbitMQ文档是正确的还是库Pika是正确的?
示例代码:
import logging
import pika
logging.basicConfig(level=logging.INFO)
logging.getLogger("pika").propagate = False
parameters = pika.ConnectionParameters()
# Produce messages
with pika.BlockingConnection(parameters) as connection:
queue = "foobar"
routing_key = queue
channel = connection.channel()
channel.queue_declare(queue=queue)
for body in ["a", "b", "c"]:
channel.publish(exchange="", routing_key=routing_key, body=body)
logging.info("Produced message %r with routing key %r", body, routing_key)
# Consume messages
def handle(channel, method, properties, body):
logging.info("Consumed message %r from queue %r", body.decode(), queue)
channel.basic_nack(method.delivery_tag)
with pika.BlockingConnection(parameters) as connection:
queue = "foobar"
channel = connection.channel()
channel.queue_declare(queue=queue)
channel.basic_consume(queue=queue, on_message_callback=handle)
channel.start_consuming()
输出:
INFO:root:生成的消息'a',带有路由键'foobar'
INFO:root:使用路由键'foobar'产生的消息'b'
INFO:root:使用路由键'foobar'产生的消息'c'
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ b”
INFO:root:来自队列'foobar'的已消耗消息'c'
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ b”
INFO:root:来自队列'foobar'的已消耗消息'c'
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ b”
INFO:root:来自队列“ foobar”的已消耗消息“ c”
答案 0 :(得分:1)
您遇到的行为很可能是由于预取行为造成的。
由于您尚未指定所需的服务质量,因此我相信(希望获得更多知识的来源来确认这一点吗?)预取是由服务器决定的,并且可能会很高。
这个想法是,对于性能而言,客户可以获取多条消息,这在大多数情况下是有利的:
如果您查看下面的文档链接,它们将说明如何控制行为。
有关这些点的其他信息,请访问:
答案 1 :(得分:0)
谢谢@Olivier。使用channel.basic_qos(prefetch_count=1)
,我得到了记录的行为:
INFO:root:生成的消息'a',带有路由键'foobar'
INFO:root:使用路由键'foobar'产生的消息'b'
INFO:root:使用路由键'foobar'产生的消息'c'
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”
INFO:root:来自队列“ foobar”的已消耗消息“ a”