介紹
RabbitMQ是一個消息代理。它的核心原理非常簡單:接收和發送消息。你可以把它想像成一個郵局:你把信件放入郵箱,郵遞員就會把信件投遞到你的收件人處。在這個比喻中,RabbitMQ就扮演着郵箱、郵局以及郵遞員的角色。
RabbitMQ和郵局的主要區別是,它不是用來處理紙張的,它是用來接收、存儲和發送消息(message)這種二進制數據的。
一般提到RabbitMQ和消息,都會用到一些專有名詞。
-
生產(Producing)意思就是發送。發送消息的程序就是一個生產者(producer)。我們一般用"P"來表示:
-
隊列(queue)就是郵箱的名稱。消息通過你的應用程序和RabbitMQ進行傳輸,它們能夠只存儲在一個隊列(queue)中。 隊列(queue)沒有任何限制,你要存儲多少消息都可以——基本上是一個無限的緩衝。多個生產者(producers)能夠把消息發送給同一個隊列,同樣,多個消費者(consumers)也能夠從同一個隊列(queue)中獲取數據。隊列可以繪製成這樣(圖上是隊列的名稱):
-
消費(Consuming)和獲取消息是一樣的意思。一個消費者(consumer)就是一個等待獲取消息的程序。我們把它繪製爲"C":
需要指出的是生產者、消費者、代理需不要待在同一個設備上;事實上大多數應用也確實不在會將他們放在一臺機器上。
Hello World!
(使用pika 0.9.5 Python客戶端)
我們的“Hello world”不會很複雜——僅僅發送一個消息,然後獲取它並輸出到屏幕。這樣以來我們需要兩個程序,一個用作發送消息,另一個接受消息並打印消息內容
我們的大致的設計是這樣的:
生產者(producer)把消息發送到一個名爲“hello”的隊列中。消費者(consumer)從這個隊列中獲取消息。
RabbitMQ庫
RabbitMQ使用的是AMQP協議。要使用她你就必須需要一個使用同樣協議的庫。幾乎所有的編程語言都有可選擇的庫。python也是一樣,可以從以下幾個庫中選擇:
在這一系列教程中,我們打算使用pika。要安裝pika,你可以使用pip這個包管理工具:
$ sudo pip install pika==0.9.5
安裝過程依賴於pip和git-core兩個包,你需要先安裝它們。
Ubuntu平臺
$ sudo apt-get install python-pip git-coreDebian平臺
$ sudo apt-get install python-setuptools git-core$ sudo easy_install pip
Windows平臺 運行easy_install的安裝程序setuptools即可,安裝後運行以下命令
> easy_install pip
> pip install pika==0.9.5
發送消息
我們第一個程序send.py會發送一個消息到隊列中。首先要做的事情就是建立一個到RabbitMQ服務器的連接。
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
'localhost'))
channel = connection.channel()
現在我們已經連接上服務器了,那麼,在發送消息之前我們需要確認隊列是存在的。如果我們把消息發送到一個不存在的隊列,RabbitMQ會丟棄這條消息。我門先創建一個名爲hello的隊列,然後把消息發送到這個隊列中。
channel.queue_declare(queue='hello')
這時候我們就可以發送消息了,我們第一條消息只包含了 Hello World!字符串,我們打算把它發送到我們的hello隊列。
在RabbitMQ中,消息是不能直接發送到隊列,它需要發送到交換機(exchange)中。我們不打算在這裏深入討論它——你可以通過教程的第三部分了解更多。現在我們所需要了解的是如何使用默認的交換機(exchange),它使用一個空字符串來標識。交換機允許我們指定某條消息需要投遞到哪個隊列,routing_key參數必須指定爲隊列的名稱:
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print " [x] Sent 'Hello World!'"
在退出程序之前,我們需要確認網絡緩衝已經被刷寫、消息已經投遞到RabbitMQ。完成這些事情(正確的關閉連接)是很簡單的。
connection.close()
發送不成功!
如果這是你第一次使用RabbitMQ,並且沒有看到“Sent”消息出現在屏幕上,你可能會抓耳撓腮不知所以。這也許是因爲沒有足夠的磁盤空間給代理使用所造成的(代理默認需要1Gb的空閒空間),所以它纔會拒絕接收消息。查看一下代理的日誌確定並且減少必要的限制。配置文件文檔會告訴你如何更改磁盤空間限制(disk_free_limit)。
獲取數據
我們的第二個程序receive.py,將會從隊列中獲取消息並打印消息。
這次我們還是先要連接到RabbitMQ服務器。連接服務器的代碼和之前是一樣的。
下一步也和之前一樣,我們需要確認隊列是存在的。使用queue_declare創建一個隊列——我們可以運行這個命令很多次,但是隻有一個隊列會被創建。
channel.queue_declare(queue='hello')
你也許要問: 爲什麼要重複聲明隊列呢 —— 我們已經在前面的代碼中聲明過它了。如果我們確定了隊列是已經存在的,那麼我們可以不這麼做,比如此前預先運行了send.py程序。可是我們並不確定哪個程序會首先運行。這種情況下,在程序中重複將隊列重複聲明一下是種值得推薦的做法。
列出所有隊列
你也許希望查看RabbitMQ中有哪些隊列、有多少消息在隊列中。此時你可以使用rabbitmqctl工具(使用有權限的用戶):
bash $ sudo rabbitmqctl list_queues Listing queues ... hello 0 ...done.
(在Windows中不需要sudo命令)
從隊列中獲取消息相對來說稍顯複雜。需要爲隊列定義一個回調(callback)函數。當我們獲取到消息的時候,Pika庫就會調用此回調函數。這個回調函數會將接收到的消息內容輸出到屏幕上。
def callback(ch, method, properties, body):
print " [x] Received %r" % (body,)
下一步,我們需要告訴RabbitMQ這個回調函數將會從名爲"hello"的隊列中接收消息:
channel.basic_consume(callback,
queue='hello',
no_ack=True)
要成功運行這些命令,我們必須保證隊列是存在的,我們的確可以確保它的存在——因爲我們之前已經使用queue_declare
將其聲明過了。
no_ack
參數稍後會進行介紹。
最後,我們輸入一個用來等待消息數據並且在需要的時候運行回調函數的無限循環。
print ' [*] Waiting for messages. To exit press CTRL+C'
channel.start_consuming()
整合
send.py的全部代碼:
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='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()
receive.py的全部代碼:
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
print ' [*] Waiting for messages. To exit press CTRL+C'
def callback(ch, method, properties, body):
print " [x] Received %r" % (body,)
channel.basic_consume(callback,
queue='hello',
no_ack=True)
channel.start_consuming()
現在就可以在終端中運行我們的程序了。首先,用send.py重續發送一條消息:
$ python send.py
[x] Sent 'Hello World!'
生產者(producer)程序send.py每次運行之後就會停止。現在我們就來接收消息:
$ python receive.py
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'Hello World!'
成功了!我們已經通過RabbitMQ發送第一條消息。你也許已經注意到了,receive.py程序並沒有退出。它一直在準備獲取消息,你可以通過Ctrl-C來中止它。
試下在新的終端中再次運行send.py。
我們已經學會如何發送消息到一個已知隊列中並接收消息。是時候移步到第二部分了,我們將會建立一個簡單的工作隊列(work queue)。