RBMQ案例二:工作队列模式
工作队列模式
工作队列(又名:任务队列)背后的主要思想是避免立即执行资源密集型任务而不得不等待它完成。相反,我们安排任务稍后完成。我们将任务封装 为消息并将其发送到队列。在后台运行的工作进程将弹出任务并最终执行作业。当您运行许多工人时,任务将在他们之间共享。
循环调度
使用任务队列的优势之一是能够轻松并行化工作。如果我们正在积压工作,我们只需添加更多的工作人员,这样就可以轻松扩展。
首先,让我们尝试同时运行两个worker.py脚本。他们都将从队列中获取消息,但究竟如何呢?让我们来看看。
您需要打开三个控制台。两个将运行worker2.py 脚本。这些控制台将是我们的两个消费者 - C1 和 C2。
公平派遣
您可能已经注意到,调度仍然不能完全按照我们的意愿进行。比如有两个worker的情况,当奇数消息都重,偶数消息都轻时,一个worker会一直很忙,另一个worker几乎不做任何工作。好吧,RabbitMQ 对此一无所知,仍然会均匀地分发消息。
发生这种情况是因为 RabbitMQ 只是在消息进入队列时分派消息。它不会查看消费者未确认消息的数量。它只是盲目地将每条第 n 条消息发送给第 n 个消费者。
为了打败它,我们可以使用带有prefetch_count=1设置的Channel#basic_qos通道方法 。这使用basic.qos协议方法来告诉 RabbitMQ 一次不要给一个 worker 一个以上的消息。或者,换句话说,在 worker 处理并确认前一条消息之前,不要向它发送新消息。相反,它将把它分派给下一个还不忙的工人。
一、代码--消息生产者 new_task.py
#!/usr/bin/env python import time import pika import json import datetime # 产生消息的入口,生产queue消息 def producer(): connection = pika.BlockingConnection( pika.ConnectionParameters(virtual_host='/melon_demo', host='82.156.19.94', port=5672, credentials=pika.PlainCredentials('guest', 'guest'))) channel = connection.channel() channel.queue_declare(queue='task_queue', durable=True) ## 循环生成100条消息 for i in range(200): message = json.dumps({'id': "80000%s" % i, "amount": 100 * i, "name": "melon", "createtime": str(datetime.datetime.now())}) channel.basic_publish(exchange='', routing_key='task_queue', body=message, properties=pika.BasicProperties(delivery_mode=pika.spec.PERSISTENT_DELIVERY_MODE)) time.sleep(1) print(" [x] Sent %r" % message) connection.close() producer()
二、代码 消息的消费者: worker.py
#!/usr/bin/env python import pika import time connection = pika.BlockingConnection( pika.ConnectionParameters(virtual_host='/melon_demo', host='82.156.19.94', port=5672, credentials=pika.PlainCredentials('guest', 'guest'))) channel = connection.channel() channel.queue_declare(queue='task_queue', durable=True) print(' [*] Waiting for messages. To exit press CTRL+C') def callback(ch, method, properties, body): print("[x] Received %r" % body.decode()) time.sleep(1) time.sleep(body.count(b'.')) print("[x] Done") ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=1) channel.basic_consume(queue='task_queue', on_message_callback=callback) channel.start_consuming()
三、消息的消费
心有猛虎,细嗅蔷薇