在一个使用 RabbitMQ 和 Pika 的 Python 环境中,存在一个队列,其中包含了 100 条消息。当两个消费者应用程序一个接一个地启动时,所有预先存在的消息都会被第一个消费者处理,并且不会在两个正在运行并等待消息的消费者之间进行分配。然而,从那时起放入队列中的任何新消息都会在两个消费者之间进行分配。问题在于,如果消费者花费大量时间来处理,那么在消耗队列中的初始预先存在的消息之前,负载都会落在一个消费者身上。但是,如果 Consumer1 被终止,则消息会传递给 Consumer2(这是预期的)。
已尝试使用 SelectionConnect、prefetch_count=(0 和 1)、prefetch_size = 0 以及 no_ack = False。
请注意,prefetch_count 决定了RabbitMQ 可以发送给每个消费者的未确认消息的最大数量,而 prefetch_size 决定了RabbitMQ 可以发送给每个消费者的未确认消息的最大字节大小。
2、解决方案
为了配置系统以便在队列中共享预先存在的消息,即使消费者在不同的时间启动(例如,随着负载的增加而添加更多消费者),可以采取以下步骤:
-
将队列声明为 “durable”。这将确保即使 RabbitMQ 重新启动,消息也会保留在队列中。
-
将消费者声明为 “durable”。这将确保即使消费者重新启动,它也会继续接收消息。
-
使用公平分发(fair dispatch)策略。这将确保每个消费者平均收到相同数量的消息。
-
将 prefetch_count 设置为 1。这将确保每个消费者一次只处理一条消息,从而减少处理延迟。
-
将 no_ack 设置为 False。这将确保在消息被成功处理之前,不会从队列中删除该消息。
如果正确配置了这些参数,则预先存在于队列中的消息将平均分配给所有正在运行的消费者,即使这些消费者在不同的时间启动。
以下代码示例展示了如何使用 Pika 和 RabbitMQ 将预先存在的消息分发到多个消费者应用程序:
import pika
# Declare the queue as durable
queue_name = 'my-queue'
queue_args = {'x-queue-mode': 'durable'}
# Declare the consumers as durable
consumer_tag1 = 'consumer1'
consumer_tag2 = 'consumer2'
# Connect to RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
# Create a channel
channel = connection.channel()
# Declare the queue
channel.queue_declare(queue=queue_name, durable=True, arguments=queue_args)
# Declare the consumers
channel.basic_consume(queue=queue_name, on_message_callback=on_message_callback, consumer_tag=consumer_tag1)
channel.basic_consume(queue=queue_name, on_message_callback=on_message_callback, consumer_tag=consumer_tag2)
# Start consuming messages
channel.start_consuming()
# Define the on_message_callback function
def on_message_callback(ch, method, properties, body):
# Process the message
print(f"Received message: {body}")
# Acknowledge the message
ch.basic_ack(delivery_tag=method.delivery_tag)
这个示例展示了如何声明一个持久的队列和两个持久的消费者,并使用公平分发策略将消息分配给消费者。它还展示了如何使用 on_message_callback
函数来处理消息和确认消息。