Python+Pika+RabbitMQ環境部署及實現工作隊列

來源:互聯網
上載者:User
rabbitmq中文翻譯的話,主要還是mq字母上:Message Queue,即訊息佇列的意思。前面還有個rabbit單詞,就是兔子的意思,和python語言叫python一樣,老外還是蠻幽默的。rabbitmq服務類似於mysql、apache服務,只是提供的功能不一樣。rabbimq是用來提供發送訊息的服務,可以用在不同的應用程式之間進行通訊。

安裝rabbitmq
先來安裝下rabbitmq,在ubuntu 12.04下可以直接通過apt-get安裝:

sudo apt-get install rabbitmq-server

安裝好後,rabbitmq服務就已經啟動好了。接下來看下python編寫Hello World!的執行個體。執行個體的內容就是從send.py發送“Hello World!”到rabbitmq,receive.py從rabbitmq接收send.py發送的資訊。

其中P表示produce,生產者的意思,也可以稱為寄件者,執行個體中表現為send.py;C表示consumer,消費者的意思,也可以稱為接收者,執行個體中表現為receive.py;中間紅色的表示隊列的意思,執行個體中表現為hello隊列。

python使用rabbitmq服務,可以使用現成的類庫pika、txAMQP或者py-amqplib,這裡選擇了pika。

安裝pika

安裝pika可以使用pip來進行安裝,pip是python的軟體管理組件,如果沒有安裝,可以通過apt-get安裝

sudo apt-get install python-pip

通過pip安裝pika:

sudo pip install pika

send.py代碼

串連到rabbitmq伺服器,因為是在本地測試,所以就用localhost就可以了。

connection = pika.BlockingConnection(pika.ConnectionParameters(        'localhost'))channel = connection.channel()

聲明訊息佇列,訊息將在這個隊列中進行傳遞。如果將訊息發送到不存在的隊列,rabbitmq將會自動清除這些訊息。

channel.queue_declare(queue='hello')

發送訊息到上面聲明的hello隊列,其中exchange表示交換器,能精確指定訊息應該發送到哪個隊列,routing_key設定為隊列的名稱,body就是發送的內容,具體發送細節暫時先不關注。

channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')

關閉串連

connection.close()

完整代碼

#!/usr/bin/env python#coding=utf8import pika connection = pika.BlockingConnection(pika.ConnectionParameters(        'localhost'))channel = connection.channel() channel.queue_declare(queue='hello') channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')print " [x] Sent 'Hello World!'"connection.close()

先來執行下這個程式,執行成功的話,rabbitmqctl應該成功增加了hello隊列,並且隊列裡應該有一條資訊,用rabbitmqctl命令來查看下

rabbitmqctl list_queues

在筆者的電腦上輸出如下資訊:


確實有一個hello隊列,並且隊列裡有一條資訊。接下來用receive.py來擷取隊列裡的資訊。

receive.py代碼

和send.py的前面兩個步驟一樣,都是要先串連伺服器,然後聲明訊息的隊列,這裡就不再貼同樣代碼了。

接收訊息更為複雜一些,需要定義一個回呼函數來處理,這邊的回呼函數就是將資訊列印出來。

def callback(ch, method, properties, body):  print "Received %r" % (body,)

告訴rabbitmq使用callback來接收資訊

channel.basic_consume(callback, queue='hello', no_ack=True)

開始接收資訊,並進入阻塞狀態,隊列裡有資訊才會調用callback進行處理。按ctrl+c退出。

channel.start_consuming()

完整代碼

#!/usr/bin/env python#coding=utf8import pika connection = pika.BlockingConnection(pika.ConnectionParameters(        'localhost'))channel = connection.channel() channel.queue_declare(queue='hello') def callback(ch, method, properties, body):  print " [x] Received %r" % (body,) channel.basic_consume(callback, queue='hello', no_ack=True) print ' [*] Waiting for messages. To exit press CTRL+C'channel.start_consuming()

執行程式,就能夠接收到隊列hello裡的訊息Hello World!,然後列印在螢幕上。換一個終端,再次執行send.py,可以看到receive.py這邊會再次接收到資訊。

工作隊列樣本

1.準備工作(Preparation)

在執行個體程式中,用new_task.py來類比任務分配者, worker.py來類比工作者。

修改send.py,從命令列參數裡接收資訊,並發送

import sys message = ' '.join(sys.argv[1:]) or "Hello World!"channel.basic_publish(exchange='',           routing_key='hello',           body=message)print " [x] Sent %r" % (message,)

修改receive.py的回呼函數。

import time def callback(ch, method, properties, body):  print " [x] Received %r" % (body,)  time.sleep( body.count('.') )  print " [x] Done"

這邊先開啟兩個終端,都運行worker.py,處於監聽狀態,這邊就相當於兩個工作者。開啟第三個終端,運行new_task.py

$ python new_task.py First message.$ python new_task.py Second message..$ python new_task.py Third message...$ python new_task.py Fourth message....$ python new_task.py Fifth message.....

觀察worker.py接收到任務,其中一個工作者接收到3個任務 :

$ python worker.py [*] Waiting for messages. To exit press CTRL+C [x] Received 'First message.' [x] Received 'Third message...' [x] Received 'Fifth message.....'

另外一個工作者接收到2個任務 :

$ python worker.py [*] Waiting for messages. To exit press CTRL+C [x] Received 'Second message..' [x] Received 'Fourth message....'

從上面來看,每個工作者,都會依次分配到任務。那麼如果一個工作者,在處理任務的時候掛掉,這個任務就沒有完成,應當交由其他工作者處理。所以應當有一種機制,當一個工作者完成任務時,會反饋訊息。

2.訊息確認(Message acknowledgment)

訊息確認就是當工作者完成任務後,會反饋給rabbitmq。修改worker.py中的回呼函數:

def callback(ch, method, properties, body):  print " [x] Received %r" % (body,)  time.sleep(5)  print " [x] Done"  ch.basic_ack(delivery_tag = method.delivery_tag)

這邊停頓5秒,可以方便ctrl+c退出。

去除no_ack=True參數或者設定為False也可以。

channel.basic_consume(callback, queue='hello', no_ack=False)

用這個代碼運行,即使其中一個工作者ctrl+c退出後,正在執行的任務也不會丟失,rabbitmq會將任務重新分配給其他工作者。

3.訊息持久化儲存(Message durability)

雖然有了訊息反饋機制,但是如果rabbitmq自身掛掉的話,那麼任務還是會丟失。所以需要將任務持久化儲存起來。聲明持久化儲存:

channel.queue_declare(queue='hello', durable=True)

但是這個程式會執行錯誤,因為hello這個隊列已經存在,並且是非持久化的,rabbitmq不允許使用不同的參數來重新定義存在的隊列。重新定義一個隊列:

channel.queue_declare(queue='task_queue', durable=True)

在發送任務的時候,用delivery_mode=2來標記任務為持久化儲存:

channel.basic_publish(exchange='',           routing_key="task_queue",           body=message,           properties=pika.BasicProperties(             delivery_mode = 2, # make message persistent           ))

4.公平調度(Fair dispatch)

上面執行個體中,雖然每個工作者是依次分配到任務,但是每個任務不一定一樣。可能有的任務比較重,執行時間比較久;有的任務比較輕,執行時間比較短。如果能公平調度就最好了,使用basic_qos設定prefetch_count=1,使得rabbitmq不會在同一時間給工作者分配多個任務,即只有工作者完成任務之後,才會再次接收到任務。

channel.basic_qos(prefetch_count=1)

new_task.py完整代碼

#!/usr/bin/env pythonimport pikaimport sys connection = pika.BlockingConnection(pika.ConnectionParameters(    host='localhost'))channel = connection.channel() channel.queue_declare(queue='task_queue', durable=True) message = ' '.join(sys.argv[1:]) or "Hello World!"channel.basic_publish(exchange='',           routing_key='task_queue',           body=message,           properties=pika.BasicProperties(             delivery_mode = 2, # make message persistent           ))print " [x] Sent %r" % (message,)connection.close()worker.py完整代碼#!/usr/bin/env pythonimport pikaimport time connection = pika.BlockingConnection(pika.ConnectionParameters(    host='localhost'))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,)  time.sleep( body.count('.') )  print " [x] Done"  ch.basic_ack(delivery_tag = method.delivery_tag) channel.basic_qos(prefetch_count=1)channel.basic_consume(callback,           queue='task_queue') channel.start_consuming()


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.