RabbitMQ 的工作队列(Work Queues)模式是一种消息处理模型,主要用于解决耗时任务的异步执行和负载均衡问题。在该模式下,生产者(Producer)将任务以消息的形式发送到一个特定的工作队列中,而多个消费者(Consumer)则并发地从队列中获取并处理这些任务。
工作流程:
-
创建队列:
- 首先需要在 RabbitMQ 服务器上声明一个队列,队列中的消息代表待处理的任务。
-
发布任务:
- 生产者(如 web 应用、服务或后台任务调度器等)将任务封装成消息,并通过 AMQP 协议将消息发布到指定的工作队列。
-
消费任务:
- 多个消费者可以同时监听这个队列,每个消费者都可以尝试从队列中取出一条未被其他消费者获取过的消息进行处理。
-
公平分发:
- 默认情况下,RabbitMQ 会尽力按照“轮询”方式公平地分配消息给所有在线的消费者,确保每个消费者都有机会获得消息进行处理。
-
确认机制:
- 消费者接收到消息后开始处理任务,在完成任务后必须向 RabbitMQ 发送一个确认信号(acknowledgement),只有收到确认,RabbitMQ 才会将消息从队列中移除。如果消费者在处理过程中失败或断开连接而没有确认消息,RabbitMQ 会在消费者重新连接后重新投递该消息,保证了任务至少会被执行一次。
-
消息持久化:
- 在工作队列模式下,为了防止消息在 RabbitMQ 服务器重启时丢失,可以设置消息的持久化属性,确保即使在服务器宕机的情况下,重要的任务消息仍能保存下来并在服务器恢复后继续投递给消费者。
-
预取计数(Prefetch Count):
- 可以通过设置消费者端的预取计数来限制单个消费者一次性从队列中获取的消息数量,这样可以在高并发场景下控制每个消费者的负载,避免某个消费者一次性获取过多消息导致其它消费者空闲的情况。
示例代码片段(Python 示例):
# 创建连接与通道
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# 声明队列,假设队列名为 'task_queue'
channel.queue_declare(queue='task_queue', durable=True)
# 生产者发布消息到队列
def publish_task(message):
channel.basic_publish(exchange='',
routing_key='task_queue',
body=message,
properties=pika.BasicProperties(delivery_mode=2)) # 设置消息持久化
# 消费者接收消息并处理
def consume_tasks():
channel.basic_qos(prefetch_count=1) # 设置预取计数为1,逐条处理消息
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
# 这里模拟耗时任务处理...
time.sleep(10)
print(" [x] Done")
ch.basic_ack(delivery_tag=method.delivery_tag) # 完成处理后发送确认
channel.basic_consume(queue='task_queue',
on_message_callback=callback,
auto_ack=False) # 不自动确认,手动确认
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming() # 开始监听并消费消息
# 启动生产者与消费者
publish_task('Hello World!')
consume_tasks()
以上示例中,我们首先创建了一个持久化的任务队列,并演示了如何发送持久化消息到队列以及如何设置消费者以公平且有序的方式处理这些消息。实际应用中,通常会启动多个消费者进程/线程分别监听同一个队列,从而实现任务的分布式处理和负载均衡。