該文已加入開源項目:JavaGuide(一份涵蓋大部分Java程序員所須要掌握的核心知識的文檔類項目,Star 數接近 16k)。地址:github.com/Snailclimb/….java
本文內容思惟導圖: git
「RabbitMQ?」「Kafka?」「RocketMQ?」...在平常學習與開發過程當中,咱們經常聽到消息隊列這個關鍵詞。我也在個人多篇文章中提到了這個概念。可能你是熟練使用消息隊列的老手,又或者你是不懂消息隊列的新手,不論你了不瞭解消息隊列,本文都將帶你搞懂消息隊列的一些基本理論。若是你是老手,你可能從本文學到你以前未曾注意的一些關於消息隊列的重要概念,若是你是新手,相信本文將是你打開消息隊列大門的一板磚。程序員
咱們能夠把消息隊列比做是一個存放消息的容器,當咱們須要使用消息的時候能夠取出消息供本身使用。消息隊列是分佈式系統中重要的組件,使用消息隊列主要是爲了經過異步處理提升系統性能和削峯、下降系統耦合性。目前使用較多的消息隊列有ActiveMQ,RabbitMQ,Kafka,RocketMQ,咱們後面會一一對比這些消息隊列。github
另外,咱們知道隊列 Queue 是一種先進先出的數據結構,因此消費消息時也是按照順序來消費的。好比生產者發送消息1,2,3...對於消費者就會按照1,2,3...的順序來消費。可是偶爾也會出現消息被消費的順序不對的狀況,好比某個消息消費失敗又或者一個 queue 多個consumer 也會致使消息被消費的順序不對,咱們必定要保證消息被消費的順序正確。面試
除了上面說的消息消費順序的問題,使用消息隊列,咱們還要考慮如何保證消息不被重複消費?如何保證消息的可靠性傳輸(如何處理消息丟失的問題)?......等等問題。因此說使用消息隊列也不是十全十美的,使用它也會讓系統可用性下降、複雜度提升,另外須要咱們保障一致性等問題。算法
我以爲使用消息隊列主要有兩點好處:1.經過異步處理提升系統性能(削峯、減小響應所需時間);2.下降系統耦合性。若是在面試的時候你被面試官問到這個問題的話,通常狀況是你在你的簡歷上涉及到消息隊列這方面的內容,這個時候推薦你結合你本身的項目來回答。數據庫
《大型網站技術架構》第四章和第七章均有提到消息隊列對應用性能及擴展性的提高。服務器
經過以上分析咱們能夠得出消息隊列具備很好的削峯做用的功能——即經過異步處理,將短期高併發產生的事務消息存儲在消息隊列中,從而削平高峯期的併發事務。 舉例:在電子商務一些秒殺、促銷活動中,合理使用消息隊列能夠有效抵禦促銷活動剛開始大量訂單涌入對系統的衝擊。以下圖所示: 數據結構
由於用戶請求數據寫入消息隊列以後就當即返回給用戶了,可是請求數據在後續的業務校驗、寫數據庫等操做中可能失敗。所以使用消息隊列進行異步處理以後,須要適當修改業務流程進行配合,好比用戶在提交訂單以後,訂單數據寫入消息隊列,不能當即返回用戶訂單提交成功,須要在消息隊列的訂單消費者進程真正處理完該訂單以後,甚至出庫後,再經過電子郵件或短信通知用戶訂單成功,以避免交易糾紛。這就相似咱們平時手機訂火車票和電影票。架構
咱們知道若是模塊之間不存在直接調用,那麼新增模塊或者修改模塊就對其餘模塊影響較小,這樣系統的可擴展性無疑更好一些。
咱們最多見的事件驅動架構相似生產者消費者模式,在大型網站中一般用利用消息隊列實現事件驅動結構。以下圖所示:
消息隊列使利用發佈-訂閱模式工做,消息發送者(生產者)發佈消息,一個或多個消息接受者(消費者)訂閱消息。 從上圖能夠看到消息發送者(生產者)和消息接受者(消費者)之間沒有直接耦合,消息發送者將消息發送至分佈式消息隊列即結束對消息的處理,消息接受者從分佈式消息隊列獲取該消息後進行後續處理,並不須要知道該消息從何而來。對新增業務,只要對該類消息感興趣,便可訂閱該消息,對原有系統和業務沒有任何影響,從而實現網站業務的可擴展性設計。
消息接受者對消息進行過濾、處理、包裝後,構形成一個新的消息類型,將消息繼續發送出去,等待其餘消息接受者訂閱該消息。所以基於事件(消息對象)驅動的業務架構能夠是一系列流程。
另外爲了不消息隊列服務器宕機形成消息丟失,會將成功發送到消息隊列的消息存儲在消息生產者服務器上,等消息真正被消費者服務器處理後才刪除消息。在消息隊列服務器宕機後,生產者服務器會選擇分佈式消息隊列服務器集羣中的其餘服務器發佈消息。
備註: 不要認爲消息隊列只能利用發佈-訂閱模式工做,只不過在解耦這個特定業務環境下是使用發佈-訂閱模式的。除了發佈-訂閱模式,還有點對點訂閱模式(一個消息只有一個消費者),咱們比較經常使用的是發佈-訂閱模式。 另外,這兩種消息模型是 JMS 提供的,AMQP 協議還提供了 5 種消息模型。
JMS(JAVA Message Service,java消息服務)是java的消息服務,JMS的客戶端之間能夠經過JMS服務進行異步的消息傳輸。JMS(JAVA Message Service,Java消息服務)API是一個消息服務的標準或者說是規範,容許應用程序組件基於JavaEE平臺建立、發送、接收和讀取消息。它使分佈式通訊耦合度更低,消息服務更加可靠以及異步性。
ActiveMQ 就是基於 JMS 規範實現的。
①點到點(P2P)模型
使用 隊列(Queue)做爲消息通訊載體;知足生產者與消費者模式,一條消息只能被一個消費者使用,未被消費的消息在隊列中保留直到被消費或超時。好比:咱們生產者發送100條消息的話,兩個消費者來消費通常狀況下兩個消費者會按照消息發送的順序各自消費一半(也就是你一個我一個的消費。)② 發佈/訂閱(Pub/Sub)模型
發佈訂閱模型(Pub/Sub) 使用 主題(Topic)做爲消息通訊載體,相似於廣播模式;發佈者發佈一條消息,該消息經過主題傳遞給全部的訂閱者, 在一條消息廣播以後才訂閱的用戶則是收不到該條消息的。JMS定義了五種不一樣的消息正文格式,以及調用的消息類型,容許你發送並接收以一些不一樣形式的數據,提供現有消息格式的一些級別的兼容性。
AMQP,即Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標準 高級消息隊列協議(二進制應用層協議),是應用層協議的一個開放標準,爲面向消息的中間件設計,兼容 JMS。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件同產品,不一樣的開發語言等條件的限制。
RabbitMQ 就是基於 AMQP 協議實現的。
對比方向 | JMS | AMQP |
---|---|---|
定義 | Java API | 協議 |
跨語言 | 否 | 是 |
跨平臺 | 否 | 是 |
支持消息類型 | 提供兩種消息模型:①Peer-2-Peer;②Pub/sub | 提供了五種消息模型:①direct exchange;②fanout exchange;③topic change;④headers exchange;⑤system exchange。本質來說,後四種和JMS的pub/sub模型沒有太大差異,僅是在路由機制上作了更詳細的劃分; |
支持消息類型 | 支持多種消息類型 ,咱們在上面提到過 | byte[](二進制) |
總結:
對比方向 | 概要 |
---|---|
吞吐量 | 萬級的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十萬級甚至是百萬級的 RocketMQ 和 Kafka 低一個數量級。 |
可用性 | 均可以實現高可用。ActiveMQ 和 RabbitMQ 都是基於主從架構實現高可用性。RocketMQ 基於分佈式架構。 kafka 也是分佈式的,一個數據多個副本,少數機器宕機,不會丟失數據,不會致使不可用 |
時效性 | RabbitMQ 基於erlang開發,因此併發能力很強,性能極其好,延時很低,達到微秒級。其餘三個都是 ms 級。 |
功能支持 | 除了 Kafka,其餘三個功能都較爲完備。 Kafka 功能較爲簡單,主要支持簡單的MQ功能,在大數據領域的實時計算以及日誌採集被大規模使用,是事實上的標準 |
消息丟失 | ActiveMQ 和 RabbitMQ 丟失的可能性很是低, RocketMQ 和 Kafka 理論上不會丟失。 |
總結:
參考:《Java工程師面試突擊第1季-中華石杉老師》
ThoughtWorks准入職Java工程師。專一Java知識分享!開源 Java 學習指南——JavaGuide(15k+ Star)的做者。公衆號多篇文章被各大技術社區轉載。公衆號後臺回覆關鍵字「1」能夠領取一份我精選的Java資源哦!