什么叫消息隊列
消息(Message)是指在應(yīng)用間傳送的數(shù)據(jù)卖毁。消息可以非常簡單,比如只包含文本字符串奶稠,也可以更復(fù)雜,可能包含嵌入對象汗捡。
消息隊列(Message Queue)是一種應(yīng)用間的通信方式蛾默,消息發(fā)送后可以立即返回段标,由消息系統(tǒng)來確保消息的可靠傳遞翔脱。消息發(fā)布者只管把消息發(fā)布到 MQ 中而不用管誰來取琢歇,消息使用者只管從 MQ 中取消息而不管是誰發(fā)布的。這樣發(fā)布者和使用者都不用知道對方的存在畦攘。
為何用消息隊列
從上面的描述中可以看出消息隊列是一種應(yīng)用間的異步協(xié)作機制霸妹,那什么時候需要使用 MQ 呢?
以常見的訂單系統(tǒng)為例念搬,用戶點擊【下單】按鈕之后的業(yè)務(wù)邏輯可能包括:扣減庫存抑堡、生成相應(yīng)單據(jù)、發(fā)紅包朗徊、發(fā)短信通知首妖。在業(yè)務(wù)發(fā)展初期這些邏輯可能放在一起同步執(zhí)行,隨著業(yè)務(wù)的發(fā)展訂單量增長爷恳,需要提升系統(tǒng)服務(wù)的性能有缆,這時可以將一些不需要立即生效的操作拆分出來異步執(zhí)行,比如發(fā)放紅包温亲、發(fā)短信通知等棚壁。這種場景下就可以用 MQ ,在下單的主流程(比如扣減庫存栈虚、生成相應(yīng)單據(jù))完成之后發(fā)送一條消息到 MQ 讓主流程快速完結(jié)袖外,而由另外的單獨線程拉取MQ的消息(或者由 MQ 推送消息),當(dāng)發(fā)現(xiàn) MQ 中有發(fā)紅包或發(fā)短信之類的消息時魂务,執(zhí)行相應(yīng)的業(yè)務(wù)邏輯曼验。
以上是用于業(yè)務(wù)解耦的情況,其它常見場景包括最終一致性粘姜、廣播鬓照、錯峰流控等等。
RabbitMQ 特點
RabbitMQ 是一個由 Erlang 語言開發(fā)的 AMQP 的開源實現(xiàn)孤紧。
AMQP :Advanced Message Queue豺裆,高級消息隊列協(xié)議。它是應(yīng)用層協(xié)議的一個開放標(biāo)準(zhǔn)号显,為面向消息的中間件設(shè)計臭猜,基于此協(xié)議的客戶端與消息中間件可傳遞消息,并不受產(chǎn)品押蚤、開發(fā)語言等條件的限制获讳。
RabbitMQ 最初起源于金融系統(tǒng),用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息活喊,在易用性丐膝、擴展性、高可用性等方面表現(xiàn)不俗钾菊。具體特點包括:
可靠性(Reliability)
RabbitMQ 使用一些機制來保證可靠性帅矗,如持久化、傳輸確認(rèn)煞烫、發(fā)布確認(rèn)浑此。靈活的路由(Flexible Routing)
在消息進入隊列之前,通過 Exchange 來路由消息的滞详。對于典型的路由功能凛俱,RabbitMQ 已經(jīng)提供了一些內(nèi)置的 Exchange 來實現(xiàn)紊馏。針對更復(fù)雜的路由功能,可以將多個 Exchange 綁定在一起蒲犬,也通過插件機制實現(xiàn)自己的 Exchange 朱监。消息集群(Clustering)
多個 RabbitMQ 服務(wù)器可以組成一個集群,形成一個邏輯 Broker 原叮。高可用(Highly Available Queues)
隊列可以在集群中的機器上進行鏡像赫编,使得在部分節(jié)點出問題的情況下隊列仍然可用。多種協(xié)議(Multi-protocol)
RabbitMQ 支持多種消息隊列協(xié)議奋隶,比如 STOMP擂送、MQTT 等等。多語言客戶端(Many Clients)
RabbitMQ 幾乎支持所有常用語言唯欣,比如 Java嘹吨、.NET、Ruby 等等境氢。管理界面(Management UI)
RabbitMQ 提供了一個易用的用戶界面躺苦,使得用戶可以監(jiān)控和管理消息 Broker 的許多方面。跟蹤機制(Tracing)
如果消息異常产还,RabbitMQ 提供了消息跟蹤機制匹厘,使用者可以找出發(fā)生了什么。插件機制(Plugin System)
RabbitMQ 提供了許多插件脐区,來從多方面進行擴展愈诚,也可以編寫自己的插件。
RabbitMQ 中的概念模型
消息模型
所有 MQ 產(chǎn)品從模型抽象上來說都是一樣的過程:
消費者(consumer)訂閱某個隊列牛隅。生產(chǎn)者(producer)創(chuàng)建消息炕柔,然后發(fā)布到隊列(queue)中,最后將消息發(fā)送到監(jiān)聽的消費者媒佣。
RabbitMQ 基本概念
上面只是最簡單抽象的描述匕累,具體到 RabbitMQ 則有更詳細的概念需要解釋。上面介紹過 RabbitMQ 是 AMQP 協(xié)議的一個開源實現(xiàn)默伍,所以其內(nèi)部實際上也是 AMQP 中的基本概念:
- Message
消息欢嘿,消息是不具名的,它由消息頭和消息體組成也糊。消息體是不透明的炼蹦,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)狸剃、priority(相對于其他消息的優(yōu)先權(quán))掐隐、delivery-mode(指出該消息可能需要持久性存儲)等。 - Publisher
消息的生產(chǎn)者钞馁,也是一個向交換器發(fā)布消息的客戶端應(yīng)用程序虑省。 - Exchange
交換器匿刮,用來接收生產(chǎn)者發(fā)送的消息并將這些消息路由給服務(wù)器中的隊列。 - Binding
綁定探颈,用于消息隊列和交換器之間的關(guān)聯(lián)熟丸。一個綁定就是基于路由鍵將交換器和消息隊列連接起來的路由規(guī)則,所以可以將交換器理解成一個由綁定構(gòu)成的路由表膝擂。 - Queue
消息隊列虑啤,用來保存消息直到發(fā)送給消費者隙弛。它是消息的容器架馋,也是消息的終點。一個消息可投入一個或多個隊列全闷。消息一直在隊列里面叉寂,等待消費者連接到這個隊列將其取走。 - Connection
網(wǎng)絡(luò)連接总珠,比如一個TCP連接屏鳍。 - Channel
信道,多路復(fù)用連接中的一條獨立的雙向數(shù)據(jù)流通道局服。信道是建立在真實的TCP連接內(nèi)地虛擬連接钓瞭,AMQP 命令都是通過信道發(fā)出去的,不管是發(fā)布消息淫奔、訂閱隊列還是接收消息山涡,這些動作都是通過信道完成。因為對于操作系統(tǒng)來說建立和銷毀 TCP 都是非常昂貴的開銷唆迁,所以引入了信道的概念鸭丛,以復(fù)用一條 TCP 連接。 - Consumer
消息的消費者唐责,表示一個從消息隊列中取得消息的客戶端應(yīng)用程序鳞溉。 - Virtual Host
虛擬主機,表示一批交換器鼠哥、消息隊列和相關(guān)對象熟菲。虛擬主機是共享相同的身份認(rèn)證和加密環(huán)境的獨立服務(wù)器域。每個 vhost 本質(zhì)上就是一個 mini 版的 RabbitMQ 服務(wù)器朴恳,擁有自己的隊列科盛、交換器、綁定和權(quán)限機制菜皂。vhost 是 AMQP 概念的基礎(chǔ)贞绵,必須在連接時指定,RabbitMQ 默認(rèn)的 vhost 是 / 恍飘。 - Broker
表示消息隊列服務(wù)器實體榨崩。
AMQP 中的消息路由
AMQP 中消息的路由過程和 Java 開發(fā)者熟悉的 JMS 存在一些差別谴垫,AMQP 中增加了 Exchange 和 Binding 的角色。生產(chǎn)者把消息發(fā)布到 Exchange 上母蛛,消息最終到達隊列并被消費者接收翩剪,而 Binding 決定交換器的消息應(yīng)該發(fā)送到那個隊列。
Exchange 類型
Exchange分發(fā)消息時根據(jù)類型的不同分發(fā)策略有區(qū)別彩郊,目前共四種類型:direct前弯、fanout、topic秫逝、headers 恕出。headers 匹配 AMQP 消息的 header 而不是路由鍵,此外 headers 交換器和 direct 交換器完全一致违帆,但性能差很多浙巫,目前幾乎用不到了,所以直接看另外三種類型:
-
direct
消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致刷后, 交換器就將消息發(fā)到對應(yīng)的隊列中的畴。路由鍵與隊列名完全匹配,如果一個隊列綁定到交換機要求路由鍵為“dog”尝胆,則只轉(zhuǎn)發(fā) routing key 標(biāo)記為“dog”的消息丧裁,不會轉(zhuǎn)發(fā)“dog.puppy”,也不會轉(zhuǎn)發(fā)“dog.guard”等等含衔。它是完全匹配煎娇、單播的模式。
-
fanout
每個發(fā)到 fanout 類型交換器的消息都會分到所有綁定的隊列上去抱慌。fanout 交換器不處理路由鍵逊桦,只是簡單的將隊列綁定到交換器上,每個發(fā)送到交換器的消息都會被轉(zhuǎn)發(fā)到與該交換器綁定的所有隊列上抑进。很像子網(wǎng)廣播强经,每臺子網(wǎng)內(nèi)的主機都獲得了一份復(fù)制的消息。fanout 類型轉(zhuǎn)發(fā)消息是最快的寺渗。
-
topic
topic 交換器通過模式匹配分配消息的路由鍵屬性匿情,將路由鍵和某個模式進行匹配,此時隊列需要綁定到一個模式上信殊。它將路由鍵和綁定鍵的字符串切分成單詞炬称,這些單詞之間用點隔開。它同樣也會識別兩個通配符:符號“#”和符號“”涡拘。#匹配0個或多個單詞玲躯,匹配不多不少一個單詞。