消息(Message)是指在應用間傳送的數據。消息能夠很是簡單,好比只包含文本字符串,也能夠更復雜,可能包含嵌入對象。
消息隊列(Message Queue)是一種應用間的通訊方式,消息發送後能夠當即返回,由消息系統來確保消息的可靠傳遞。消息發佈者只管把消息發佈到 MQ 中而不用管誰來取,消息使用者只管從 MQ 中取消息而不論是誰發佈的。這樣發佈者和使用者都不用知道對方的存在。
從上面的描述中能夠看出消息隊列是一種應用間的異步協做機制,那何時須要使用 MQ 呢? 以常見的訂單系統爲例,用戶點擊【下單】按鈕以後的業務邏輯可能包括:扣減庫存、生成相應單據、發紅包、發短信通知。在業務發展初期這些邏輯可能放在一塊兒同步執行,隨着業務的發展訂單量增加,須要提高系統服務的性能,這時能夠將一些不須要當即生效的操做拆分出來異步執行,好比發放紅包、
發短信通知等。這種場景下就能夠用 MQ ,在下單的主流程(好比扣減庫存、生成相應單據)完成以後發送一條消息到 MQ 讓主流程快速完結,而由另外的單獨線程拉取MQ的消息(或者由 MQ 推送消息),當發現 MQ 中有發紅包或發短信之類的消息時,執行相應的業務邏輯。 以上是用於業務解耦的狀況,其它常見場景包括最終一致性、廣播、錯峯流控等等。
RabbitMQ 是一個由 Erlang 語言開發的 AMQP 的開源實現。
AMQP :Advanced Message Queue,高級消息隊列協議。它是應用層協議的一個開放標準,爲面向消息的中間件設計,基於此協議的客戶端與消息中間件可傳遞消息,並不受產品、開發語言等條件的限制。
RabbitMQ 最初起源於金融系統,用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。具體特色包括: 可靠性(Reliability) RabbitMQ 使用一些機制來保證可靠性,如持久化、傳輸確認、發佈確認。
靈活的路由(Flexible Routing) 在消息進入隊列以前,經過 Exchange 來路由消息的。對於典型的路由功能,RabbitMQ 已經提供了一些內置的 Exchange 來實現。針對更復雜的路由功能,能夠將多個 Exchange 綁定在一塊兒,也經過插件機制實現本身的 Exchange 。
消息集羣(Clustering) 多個 RabbitMQ 服務器能夠組成一個集羣,造成一個邏輯 Broker 。 高可用(Highly Available Queues) 隊列能夠在集羣中的機器上進行鏡像,使得在部分節點出問題的狀況下隊列仍然可用。 多種協議(Multi-protocol) RabbitMQ 支持多種消息隊列協議,好比 STOMP、MQTT 等等。 多語言客戶端(Many Clients) RabbitMQ 幾乎支持全部經常使用語言,好比 Java、.NET、Ruby 等等。 管理界面(Management UI) RabbitMQ 提供了一個易用的用戶界面,使得用戶能夠監控和管理消息 Broker 的許多方面。 跟蹤機制(Tracing) 若是消息異常,RabbitMQ 提供了消息跟蹤機制,使用者能夠找出發生了什麼。
插件機制(Plugin System) RabbitMQ 提供了許多插件,來從多方面進行擴展,也能夠編寫本身的插件。
RabbitMQ是爲了應用程序與應用程序之間的通訊 RabbitMQ是消息投遞服務,RabbitMQ在應用程序之間扮演路由器的角色 應用程序能夠發送信息,發送消息給RabbitMQ(代理服務器) 應用程序能夠接收信息,從RabbitMQ(代理服務器)接收信息 當一個應用程序鏈接到RabbitMQ時,它只有一個身份,要麼是生產者,或者消費者。 生產者建立消息,而後發佈到代理服務器RabbitMQ,消息包含兩部分:有效載荷與標籤。 消費者鏈接到代理服務器,並訂閱到隊列上,咱們能夠把消息隊列想象成一個具體郵箱,每當消息到達特定的郵箱時,RabbitMQ會將其發送給其中一個訂閱/監聽的消費者。 注意:消費者接收消息裏面只有有效載荷,沒有消息的標籤,RabbitMQ不會告訴你是誰是消息的生產者,就好像你拿着一封信,上面並無署名。 整個消息傳遞的過程:生產者建立消息,消費者接收消息,二者是能夠切換的。
· Message 消息,消息是不具名的,它由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對於其餘消息的優先權)、delivery-mode(指出該消息可能須要持久性存儲)等。 · Publisher 消息的生產者,也是一個向交換器發佈消息的客戶端應用程序。 · Exchange 交換器,用來接收生產者發送的消息並將這些消息路由給服務器中的隊列。 · Binding 綁定,用於消息隊列和交換器之間的關聯。一個綁定就是基於路由鍵將交換器和消息隊列鏈接起來的路由規則,因此能夠將交換器理解成一個由綁定構成的路由表。 · Queue 消息隊列,用來保存消息直到發送給消費者。它是消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列裏面,等待消費者鏈接到這個隊列將其取走。 · Connection 網絡鏈接,好比一個TCP鏈接。 · Channel 信道,多路複用鏈接中的一條獨立的雙向數據流通道。信道是創建在真實的TCP鏈接內地虛擬鏈接,AMQP 命令都是經過信道發出去的,不論是發佈消息、訂閱隊列仍是接收消息,這些動做都是經過信道完成。由於對於操做系統來講創建和銷燬 TCP 都是很是昂貴的開銷,因此引入了信道的概念,以複用一條 TCP 鏈接。 · Consumer 消息的消費者,表示一個從消息隊列中取得消息的客戶端應用程序。 · Virtual Host 虛擬主機,表示一批交換器、消息隊列和相關對象。虛擬主機是共享相同的身份認證和加密環境的獨立服務器域。每一個 vhost 本質上就是一個 mini 版的 RabbitMQ 服務器,擁有本身的隊列、交換器、綁定和權限機制。vhost 是 AMQP 概念的基礎,必須在鏈接時指定,RabbitMQ 默認的 vhost 是 / 。 · Broker 表示消息隊列服務器實體。
AMQP: AMQP,高級消息隊列協議,以解決衆多的消息隊列需求和拓撲結構問題 而RabbitMQ是惟一實現了AMQP標準的代理服務器 信道: 生產者和消費者都須要鏈接到RabbitMQ,才能消費或者發佈消息。 應用程序與RabbitMQ之間創建一條TCP鏈接,在TCP鏈接上就能夠建立一條AMOP信道,信道是創建在TCP鏈接內的虛擬鏈接。 每一條信道都由一個惟一標識的ID(AMQP庫會幫你記住ID),發佈消息,訂閱隊列、接收消息都是在信道里完成的。 信道存在的意義: 咱們知道創建和銷燬TCP會話是很昂貴的開銷,好比如今發送者大量的發送消息給RabbitMQ,若是如今每條信息發送都是一個線程來發送信息,難道每一個線程發送信息都須要與RabbitMQ創建一條TCP鏈接嗎? 這裏面就有了一種辦法:在現成的TCP鏈接上創建信道,信道與信道之間相互獨立,不會給操做系統的TCP棧形成額外負擔,在一條TCP鏈接上建立信道是沒有限制的,因此這裏使用信道能夠建立並行的傳輸層,不會受到TCP層的鏈接限制。
AMQP 中增長了 Exchange 和 Binding 的角色。生產者把消息發佈到 Exchange 上,消息最終到達隊列並被消費者接收,而 Binding 決定交換器的消息應該發送到那個隊列。
隊列:消息最終到達隊列中並等待消費。 消費者經過兩種方式從隊列中接收消息: (1) AMQP的basic.consume命令訂閱。 將信道置爲接收模式,直到取消隊列的訂閱爲止,訂閱了隊列,消費者(或者拒絕)最近接收的消息後,就能從隊列中自動接收下一條消息。若是消費者處理隊列消息,而且須要消息一到達隊列就自動接收的話,使用basic.consume,說白了就是持續接收信息。 (2) AMQP的basic.get命令訂閱 只想從隊列中得到單條消息而不是持續的訂閱。總結:basic.get命令會訂閱隊列,得到單條消息,而後取消訂閱,因此消費者應該使用basic.consume來實現高吞吐量 若是隻有一個消費者訂閱了隊列,消息會當即發送給這個訂閱者。 若是沒有消費者訂閱隊列,消息會在隊列裏等待,一旦有消費者訂閱了對了,那麼隊列上的消息就會發送給消費者 若是有多個消費者訂閱到同一個隊列上,消息是如何分發的?循環依次發送給消費者,一次只發送給一個消費者。
消息實際上投遞到的是交換機,而後根據肯定的規則,RabbitMQ將會決定消息該投遞到哪一個隊列,這些規則被稱爲路由鍵,隊列經過路由鍵綁定到交換器。 當你發消息到代理服務器時,即使路由鍵是空的,RabbitMQ也會將其和使用的路由鍵進行匹配。若是路由的消息不匹配任何綁定模式,消息將會進入黑洞。 交換機在隊列與消息中間起到了中間層的做用,有了交換機咱們能夠實現更靈活的功能,RabbitMQ中有三種經常使用的交換機類型: direct: 若是路由鍵匹配,消息就投遞到對應的隊列 fanout:投遞消息給全部綁定在當前交換機上面的隊列 topic:容許實現有趣的消息通訊場景,使得5不一樣源頭的消息可以達到同一個隊列。topic隊列名稱有兩個特殊的關鍵字。 o* 能夠替換一個單詞 o# 能夠替換全部的單詞 能夠理解,direct爲1v1, fanout爲1v全部,topic比較靈活,能夠1v任意。
Exchange分發消息時根據類型的不一樣分發策略有區別,目前共四種類型:direct、fanout、topic、headers 。headers 匹配 AMQP 消息的 header 而不是路由鍵,此外 headers 交換器和 direct 交換器徹底一致,但性能差不少,目前幾乎用不到了,因此直接看另外三種類型:
消息中的路由鍵(routing key)若是和 Binding 中的 binding key 一致, 交換器就將消息發到對應的隊列中。路由鍵與隊列名徹底匹配,若是一個隊列綁定到交換機要求路由鍵爲「dog」,則只轉發 routing key 標記爲「dog」的消息,不會轉發「dog.puppy」,也不會轉發「dog.guard」等等。它是徹底匹配、單播的模式。
每一個發到 fanout 類型交換器的消息都會分到全部綁定的隊列上去。fanout 交換器不處理路由鍵,只是簡單的將隊列綁定到交換器上,每一個發送到交換器的消息都會被轉發到與該交換器綁定的全部隊列上。很像子網廣播,每臺子網內的主機都得到了一份複製的消息。fanout 類型轉發消息是最快的。
topic 交換器經過模式匹配分配消息的路由鍵屬性,將路由鍵和某個模式進行匹配,此時隊列須要綁定到一個模式上。它將路由鍵和綁定鍵的字符串切分紅單詞,這些單詞之間用點隔開。它一樣也會識別兩個通配符:符號「#」和符號「」。#匹配0個或多個單詞,匹配很少很多一個單詞。
每個vhost本質都是一個mini版的Rabbitmq服務器,擁有本身的隊列、交換器和綁定,還擁有本身的權限機制。安全
Vhost與Rabbit就像虛擬機與物理服務器同樣。bash
它們經過在各自實例間提供邏輯分離,容許你爲不一樣的應用程序安全保密運行數據。服務器
這頗有用,它能將同一個Rabbit的衆多客戶區分開來,又能夠避免隊列和交換器的命名衝突。不然你可能不得不運行多個Rabbit,這將帶來更多管理問題,相反,你能夠只運行一個Rabbit,而後按需啓動或關閉vhost。網絡
當你在Rabbit裏建立一個用戶,用戶一般會被指派給至少一個vhost,而且只能訪問被指派vhost內的隊列、交換器和綁定。Vhost之間是相互隔離的。架構
你將沒法將vhost banana_tree上的交換器綁定到vhostoak_tree中的隊列去。這確保了安全性與可移植性。異步
注意:當你在RabbitMQ集羣上建立vhost,整個集羣上都會建立該vhost,vhost不只消除了基礎架構中每一層運行一個RabbitMQ服務器的須要,一樣避免了爲每一層建立不一樣的集羣。分佈式
建立vhost:rabbitmqctl add_vhost [vhost_name] 刪除vhost:rabbitmqctl delete_vhost [vhost_name] 查看服務器運行的vhost:rabbitmqctl list_vhost