RabbitMQ是一個消息代理,核心原理:發送消息,接收消息。html
RabbitMQ主要用於組件之間的解耦,消息發送者無需知道消息使用者的存在,反之亦然。python
單向解耦 雙向解耦(如:RPC)服務器
例如一個日誌系統,很容易使用RabbitMQ簡化工做量,一個Consumer進行消息的正常處理,另外一個Consumer複製對消息進行日誌記錄,只要在程序中指定兩個Consumer所監聽的queue以相同的方式綁定到同一個exchange便可,剩下的消息分發工做由RabbitMQ完成。網絡
安裝rabbitmq,請參考官網。函數
首先經過一個很是簡單的」hello world「例子介紹如何使用RabbitMQ,而後再介紹其涉及的基本概念並對交換機和隊列多作點介紹。this
本例很是簡單——發送一個消息」hello world「,而後獲取它並輸出到屏幕。spa
總共須要兩個程序,一個發送消息叫send.py,一個接受消息並打印消息內容叫receive.py。代理
該圖爲helloworld例子的原理圖:生產者send.py(Productor)把消息(」hello world「)發送到一個名爲」queue「的隊列中,消費者receive.py從這個隊列中獲取消息。接下來看代碼:日誌
send.py(發送消息)server
#!/usr/bin/env python import pika #第一步,鏈接RabbitMq服務器 rabbit_username='xxx' rabbit_password='xxx' credentials = pika.PlainCredentials(rabbit_username, rabbit_password) connection = pika.BlockingConnection(pika.ConnectionParameters( host='x.x.x.x',credentials=credentials)) #channel是進行消息讀寫的通道 channel = connection.channel() #第二步,建立一個名爲queue的隊列,而後把消息發送到這個隊列 channel.queue_declare(queue='queue') #第三步,如今能夠發送消息,可是RabbitMQ不能把消息直接發送到隊列,要發送到交換器,這個稍後介紹,這裏使用默認交換器(exchange),它使用一個空字符串標 #識,routing_key參數必須指定爲隊列名稱,這裏爲queue channel.basic_publish(exchange='', routing_key='queue', body='hello world') print "send.py:send message 'hello world',wait for receive.py deal with this message" #退出程序前,經過關閉鏈接保證消息已經投遞到RabbitMq connection.close()
receive.py(獲取數據)
print ' [*] Waiting for messages. To exit press CTRL+C' #!/usr/bin/env python import pika #第一步,一樣鏈接RabbitMq服務器 rabbit_username='xxx' rabbit_password='xxx' credentials = pika.PlainCredentials(rabbit_username, rabbit_password) connection = pika.BlockingConnection(pika.ConnectionParameters( host='x.x.x.x',credentials=credentials)) channel = connection.channel() #爲確保隊列存在,再次執行queue_declare建立一個隊列,咱們能夠屢次運行該命令,可是隻要一個隊列會建立 #由於不能保證send.py先執行仍是receive.py先執行,因此重複聲明隊列來確保其存在 channel.queue_declare(queue='hellolxy') #第三步,定義一個回調函數,當得到消息時,Pika庫調用這個回調函數來處理消息,該回調函數將消息內容打印到屏幕 def callback(ch, method, properties, body): print "receive.py: Received message %r" % (body,) #第四步,告訴rabbbitMq回調函數將從queue隊列接收消息 channel.basic_consume(callback, queue='queue', no_ack=True) #第五步,輸入一個無限循環來等待消息數據並運行回調函數 print ' [*] Waiting for messages. To exit press CTRL+C' channel.start_consuming()
如今在終端運行程序。首先,用send.py發送一條消息:
$ python send.py send.py:send message 'hello world',wait for receive.py deal with this message
生產者(producer)程序send.py每次運行後就會中止。如今運行receive.py來接收消息:
$ python receive.py receive.py: Received message 'hello world' [*] Waiting for messages. To exit press CTRL+C
成功了!如今已經經過RabbitMQ發送了第一條消息。可是receive.py程序並無退出,它一直在準備獲取消息,能夠經過ctrl-c來中斷它。
總結一下發送接收消息的過程:
經過上面例子對RabbitMQ有一個感性認識後,如今來介紹RabbitMQ中的基本概念。
Broker:消息隊列服務器實體
消息:每一個消息都有一個路由鍵(routing key)的屬性。就是一個簡單的字符串。
connection:應用程序與broker的網絡鏈接。
channel:幾乎全部的操做都在channel中進行,channel是進行消息讀寫的通道。客戶端可創建多個channel,每一個channel表明一個會話任務。
交換機:接收消息,根據路由鍵轉發消息到綁定的隊列。
綁定:一個綁定就是基於路由鍵將交換機和隊列鏈接起來的路由規則,因此交換機不過就是一個由綁定構成的路由表。
舉例:一個具備路由鍵「key1」的消息要發送到兩個隊列,queueA和queueB。要作到這點就要創建兩個綁定,每一個綁定鏈接一個交換機和一個隊列。二者都是由路由鍵「key1」觸發,這種狀況,交換機會複製一份消息並把它們分別發送到兩個隊列中。
隊列:消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列裏面,等待消費者鏈接到這個隊列將其取走。
交換機用來接收消息,轉發消息到綁定的隊列,是rabbitMq中的核心。
交換機共有4種類型:direct,topic,headers和fanout。
爲何不建立一種交換機來處理全部類型的路由規則?由於每種規則匹配時的CPU開銷是不一樣的,因此根據不一樣需求選擇合適交換機。
舉例:一個"topic"類型的交換機會將消息的路由鍵與相似「dog.*」的模式進行匹配。一個「direct」類型的交換機會將路由鍵與 「dogs」進行比較。匹配末端通配符比直接比較消耗更多的cpu,因此若是用不到「topic」類型交換機帶來的靈活性,就經過「direct」類型交 換機得到更高的處理效率。
routingKey與隊列名徹底匹配,若是一個隊列綁定到交換機要求路由鍵爲「dog」,則只轉發routingkey標記爲dog的消息,不會轉發dog.puppy,也不會轉發dog.guard等。
Topic類型交換機經過模式匹配分配消息的routing-key屬性。將路由鍵和某個模式進行匹配,此時隊列須要綁定到一個模式上。
它將routing-key和binding-key的字符串切分紅單詞。這些單詞之間用點隔開。它一樣也會識別兩個通配符:符號「#」和符號「*」。#匹配0個或多個單詞,*匹配很少很多一個單詞。
例如,binding key:*.stock.#匹配routing key: usd.stock和eur.stock.db,可是不匹配stock.nana。
例如,「audit.#」可以匹配到「audit.irs.corporate」,可是「audit.*」只會匹配到「audit.irs」。
fanout交換機不處理路由鍵,簡單的將隊列綁定到交換機上,每一個發送到交換機的消息都會被轉發到與該交換機綁定的全部隊列上。
很像子網廣播,每臺子網內的主機都得到了一份複製的消息。Fanout交換機轉發消息是最快的。
深刻了解可參考: