消息中間件的介紹和對比

原文鏈接:https://blog.csdn.net/java_zyq/article/details/80022391, https://www.cnblogs.com/FlowRainFlySnow/p/4628673.html

1. 參考原文鏈接:版權聲明:本文爲CSDN博主「Mr_baci」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。 https://blog.csdn.net/java_zyq/article/details/80022391

2. 參考原文鏈接: 流雨飛雪   https://www.cnblogs.com/FlowRainFlySnow/p/4628673.html

3. 本文是好幾篇博文的綜合梳理,轉載請說明出處&附帶原文連接。

一、概述   

       (開源消息中間件介紹)目前業界上關於消息中間件的實現多達好幾十種,可謂百花齊放,所用的實現語言同樣也五花八門。下面挑選了一部分,在網上開源社區相對容易搜索出來的十多種MQ來作簡單介紹。

開源MQ

概述

1.Qpid

Apach的一個開源AMQP實現,broker架構,有C++和Java兩個版本

2.RabbitMQ

LShift 用Erlang實現,支持多協議,broker架構,重量級

3.ZeroMQ

AMQP最初設計者iMatix公司實現,輕量消息內核,無broker設計。C++實現

4.Jafka/Kafka

LinkedIn用Scala語言實現,支持hadoop數據並行加載

5.ActiveMQ

Apach的一種JMS具體實現,支持代理和p2p部署。支持多協議。Java實現

6.Apollo

ActiveMQ的下一代產品,支持多協議,Scala實現

7.Redis

Key-value  NoSQL數據庫,有MQ的功能

8.MemcacheQ

國人利用memcache緩衝隊列協議開發的消息隊列,C/C++實現

9.Open-MQ

C++和QT實現,支持JMS

10.ActiveMQ-CPP

ActiveMQ的C++純客戶端庫,用於跟ActiveMQ通信

11.MQ4CPP

一個C++實現的MQ,信息甚少

12.MetaQ

Alibaba對Kafka的改造,增加事務支持等新特性,用純Java實現

13.Beanstalkd

一個類memcached協議設計的消息隊列,C/C++實現

14.OpenAMQ

iMatix公司AMQP1.0的實現,類似rabbitMQ。C++實現。2010年項目放棄

15.Spread Toolkit

高性能的分佈式分組消息系統,C++實現

16.SAFMQ

C++實現的儲存轉發消息隊列中間件

17. Mosquitto

一個輕量級的IBM物聯網連接協議的消息中間件實現,C/C++實現

18.MUSCLE

提供一個多路消息服務器和消息對象傳遞功能,支持C/C++

19.JORAM

一個類似OpenJMS(Sun OpenMQ)的JMS消息中間件,JAVA實現

       什麼是消息中間件?

消息隊列中間件(簡稱消息中間件)是指利用高效可靠的消息傳遞機制進行與平臺無關的數據交流,並基於數據通信來進行分佈式系統的集成。通過提供消息傳遞和消息排隊模型,它可以在分佈式環境下提供應用解耦、彈性伸縮、冗餘存儲、流量削峯、異步通信、數據同步等等功能,其作爲分佈式系統架構中的一個重要組件,有着舉足輕重的地位。個人感覺比價場景應用核心的有三個:解耦、異步、削峯。

二、消息隊列的使用場景  

       爲什麼使用消息隊列?

其實這個話題也是面試官經常問詢的問題,問問你消息隊列都有哪些使用場景,然後你項目裏具體是什麼場景,說說你在這個場景裏用消息隊列是什麼

期望的一個回答是說,你們公司有個什麼業務場景,這個業務場景有個什麼技術挑戰,如果不用MQ可能會很麻煩,但是你現在用了MQ之後帶給了你很多的好處

現在你可以下想想你如何回答上述問題,想不起來?  好吧我這裏先介紹幾個常見使用場景,提醒下。。。

解耦:現場畫個圖來說明一下,

A系統發送個數據到BCD三個系統,接口調用發送,那如果E系統也要這個數據呢?那如果C系統現在不需要了呢?現在A系統又要發送第二種數據了呢?A系統負責人瀕臨崩潰中。。。再來點更加崩潰的事兒,A系統要時時刻刻考慮BCDE四個系統如果掛了咋辦?我要不要重發?我要不要把消息存起來?頭髮都白了啊。。。

這是你需要去考慮一下你負責的系統中是否有類似的場景,就是一個系統或者一個模塊,調用了多個系統或者模塊,互相之間的調用很複雜,維護起來很麻煩。但是其實這個調用是不需要直接同步調用接口的,如果用MQ給他異步化解耦,也是可以的,你就需要去考慮在你的項目裏(做過微服務項目的同學這裏是不是考慮下  消息總線 搭配Rabbitmq 做解耦 用於廣播配置文件的更改或者服務間的通訊?),是不是可以運用這個MQ去進行系統的解耦。在簡歷中體現出來這塊東西,用MQ作解耦。

異步:現場畫個圖來說明一下,

 


A系統接收一個請求,需要在自己本地寫庫,還需要在BCD三個系統寫庫,自己本地寫庫要3ms,BCD三個系統分別寫庫要300ms、450ms、200ms。最終請求總延時是3 + 300 + 450 + 200 = 953ms,接近1s,用戶感覺搞個什麼東西,慢死了慢死了。

更改爲 異步後當消息發送到消息隊列  自行讓對應系統進行消費即可  所以給用戶的體驗爲20 + 5 = 25ms  ,快 好快!

削峯:每天0點到11點,A系統風平浪靜,每秒併發請求數量就100個。結果每次一到11點~1點,每秒併發請求數量突然會暴增到1萬條。但是系統最大的處理能力就只能是每秒鐘處理1000個請求啊。。。尷尬了,系統會死。。。

 

 消息隊列有什麼優缺點?

優點上面已經說了,就是在特殊場景下有其對應的好處,解耦、異步、削峯?

選擇消息系統根據業務需要需要考慮以下幾個方面:

l  是否持久化

l  吞吐能力

l  高可用,避免單點故障

l  分佈式擴展能力

l  兼容現有協議

l  易於維護

l  其他,如消息丟失和重複的處理

l  負載均衡

 

缺點呢?顯而易見的

系統可用性降低:系統引入的外部依賴越多,越容易掛掉,本來你就是A系統調用BCD三個系統的接口就好了,人ABCD四個系統好好的,沒啥問題,你偏加個MQ進來,萬一MQ掛了咋整?MQ掛了,整套系統崩潰了,你不就完了麼。

系統複雜性提高:硬生生加個MQ進來,你怎麼保證消息沒有重複消費?怎麼處理消息丟失的情況?怎麼保證消息傳遞的順序性?頭大頭大,問題一大堆,痛苦不已

一致性問題:A系統處理完了直接返回成功了,人都以爲你這個請求就成功了;但是問題是,要是BCD三個系統那裏,BD兩個系統寫庫成功了,結果C系統寫庫失敗了,咋整?你這數據就不一致了。

所以消息隊列實際是一種非常複雜的架構,你引入它有很多好處,但是也得針對它帶來的壞處做各種額外的技術方案和架構來規避掉,最好之後,你會發現,媽呀,系統複雜度提升了一個數量級,也許是複雜了10倍。但是關鍵時刻,用,還是得用的。。。

目前流行的消息隊列都有什麼優點和缺點呢?

kafka

LinkedIn開源的分佈式發佈-訂閱消息系統,目前屬於Apache。Kafka主要特點是基於Pull的模式來處理消息消費,追求高吞吐量,一開始的目的就是用於日誌收集和傳輸。0.8版本開始支持複製,不支持事務,對消息的重複、丟失、錯誤沒有嚴格要求,適合產生大量數據的互聯網服務的數據收集業務,Apache Kafka相對於ActiveMQ是一個非常輕量級的消息系統,除了性能非常好之外,還是一個工作良好的分佈式系統。

        在架構模型方面 kafka遵從一般的MQ結構,producer,broker,consumer,以consumer爲中心,消息的消費信息保存的客戶端consumer上,consumer根據消費的點,從broker上批量pull數據;無消息確認機制。

        在吞吐量kafka具有高的吞吐量,內部採用消息的批量處理,zero-copy機制,數據的存儲和獲取是本地磁盤順序批量操作,具有O(1)的複雜度,消息處理的效率很高。

       在集羣負載均衡方面,採用zookeeper對集羣中的broker、consumer進行管理,可以註冊topic到zookeeper上;通過zookeeper的協調機制,producer保存對應topic的broker信息,可以隨機或者輪詢發送到broker上;並且producer可以基於語義指定分片,消息發送到broker的某分片上。
       在可用性方面,kafka的broker支持主備模式。

       機制上來講,kafka中,只有topic,但是每個topic可以有很多partition分區。若是kafka集羣由兩臺機器組成。topic被分成四個分區,server1維護p0,p3。 在kafka中,每個消費者都要指出自己屬於哪個consumerGroup,每個consumer可以讀取多個partition。但是一個partition在同一個consumerGroup中,只會被一個consumer消費。以此保證不會重複消費。而且在一個partition中,消息被消費的順序是可保障的。上圖中,consumer group A 由兩個consumer組成,因此一個consumer可以消費兩個partition。如果要保證嚴格的順序性,那麼就要像consumer group B一樣,每個consumer只消費一個partition。kafka和rabbitmq及activemq機制上略有區別。rabbitmq和activemq都是消費後就刪除消息,沒有重複消費的功能,而kafka 隊列中的內容按策略存儲一定時間,消費者通過指定偏移量來讀取數據。如果使用基礎api可以從任意位置讀取。kafka同時提供高級api,即kafka來維護每個消費者當前讀到什麼位置了,下次再來,可以接着讀。

    kafka中partition是冗餘存儲的。如果一個partition不幸掛了,通過選主,馬上可以切換到另外一臺機器上繼續使用。這一點上,是當之無愧的分佈式隊列。相比之下,rabbitmq需要配置鏡像隊列,操作太麻煩。kafka搭建集羣也是非常簡單。

    kafka的優勢在於: 傳統的消息隊列只有兩種模式,要麼是queue,要麼是publish-subscribe發佈訂閱。在queue模式中,一組消費者消費一個隊列,每條消息被髮給其中一個消費者。在publish-subscribe模式中,消費被廣播給所有消費者。queue模式的好處在於,他可以把消費分發給一組消費者,從而實現消費者的規模化(scale);問題在於,這樣一個消息只能被一組消費者消費,一旦消費,消息就沒有了。publish-subscribe的好處在於,一個消息可以被多組消費者消費;問題在於,你的消費者沒法規模化,即不可能出現多個消費者訂閱同一個topic,但每個消費者只處理一部分消息(雖然這個可以通過設計topic來解決)。

    kafka的設計意義在於,大家都publish-subscribe,因爲我的隊列數據是不刪除的,多個subscriber可以訂閱同一個topic,但是各自想從哪讀,從哪讀,互不干擾。同時提出了consumer group的概念。每個subscriber可以是多個consumer組成的,在consumer group內部,你們自己分配,不要兩個人消費同一條數據。爲了達到這種目的,一個topic裏的消息,被分成多個partition,既實現了上面的想法,同時又冗餘(一個partition可以冗餘存儲在多臺機器上),達到分佈式系統的高可用效果。

    kafka也支持mqtt,需要寫一個connecter。kafka還提供流式計算的功能,做數據的初步清理還是很方便的。

    總體而言。我感覺kafka安裝使用最簡單,同時,如果有集羣要求,那麼kafka是當仁不讓的首選。尤其在海量數據,以及數據有傾斜問題的場景裏,因爲partition的緣故,數據傾斜問題自動解決。比如個別Topic的消息量非常大,在kafka裏,調整partition數就好了。反而在rabbitmq或者activemq裏,這個不好解決。

    rabbitmq是功能最豐富,最完善的企業級隊列。基本沒有做不了的,就算是做類似kafka的高可用集羣,也是沒問題的,不過安裝部署麻煩了點。

      在kafka中,創建一個topic是一個比較重的操作,因爲是分佈式的,topic要同步到其他的broker,中間還要經過zookeeper。所以kafka僅僅做mqtt的輸入是ok的,但是你需要給每個硬件推送消息,實際上不太好。這方面反倒是rabbitmq比較好,因爲在rabbitmq中創建幾萬的topic是很容易的,所以是可以做到每個硬件訂閱不同的topic。

 

RabbitMQ
使用Erlang語言開發的開源消息隊列系統,基於AMQP協議來實現。AMQP的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。AMQP協議更多用在企業系統內,對數據一致性、穩定性和可靠性要求很高的場景,對性能和吞吐量的要求還在其次。
        在架構模型方面RabbitMQ遵循AMQP協議,RabbitMQ的broker由Exchange,Binding,queue組成,其中exchange和binding組成了消息的路由鍵;客戶端Producer通過連接channel和server進行通信,Consumer從queue獲取消息進行消費(長連接,queue有消息會推送到consumer端,consumer循環從輸入流讀取數據)。rabbitMQ以broker爲中心;有消息的確認機制。
        在吞吐量rabbitMQ在吞吐量方面稍遜於kafka,他們的出發點不一樣,rabbitMQ支持對消息的可靠的傳遞,支持事務,不支持批量的操作;基於存儲的可靠性的要求存儲可以採用內存或者硬盤。

        在集羣負載均衡方面,rabbitMQ的負載均衡需要單獨的loadbalancer進行支持。

        在可用性方面,rabbitMQ支持miror的queue,主queue失效,miror queue接管。

        機制上來講,rabbitmq也有queue和topic的概念,發消息的時候還要指定消息的key,這個key之後會做路由鍵用。但是,多了一個概念叫做交換器exchange。exchange有四種,direct、fanout、topic、header。也就是說,發消息給rabbitmq時,消息要有一個key,並告訴他發給哪個exchange。exchange收到之後,根據key分發或者廣播給queue。消費者是從queue裏拿消息的,並接觸不到交換機。

    在rabbitmq裏,有各種默認行爲,如果我們不指定exchange,會有個默認的direct類型的exchange,如果不指定隊列和交換器的綁定關係,默認就按消息的key綁定對應的queue。此時發一個消息,消息的key是什麼,就會被默認交換器送給對應的queue。

此時,其實等同於activemq的queue模式。

在rabbitmq裏,一個queue可以有多個消費者

通過設置prefetch的值爲1,可以讓多個消費者每次都取到一條記錄,消費完再取下一條。這兩種都是使用direct交換器,即消息的key是多少,就把消息放到key對應的queue中。

    fanout交換器。實際上就是廣播,發送到fanout交換器的消息,會被轉發給所有和這個交換器綁定的隊列。通常我們把隊列搞成臨時的,這樣就解耦了。例如用戶登錄,發送一個登陸消息到fanout交換器,同時有一個smsQueue和交換器綁定,一個消費者從這個smsQueue裏取出誰登陸了,併發送一條短信。過了幾天,我們希望用戶登陸可以獲得積分。那麼我再聲明一個scoreQueue綁定到這個fanout交換器,實現積分更改邏輯。下圖是fanout(X爲交換器)

    總體說來fanout其實就是direct交換器實現的。把兩個隊列都綁定到direct,綁定的時候指定同一個key,就變成fanout交換器了,如下圖

    queue和exchange綁定的時候,也可以指定多個綁定key,這時候就實現了簡單版的訂閱。如下圖

當然這樣不夠靈活,我想要靠通配符綁定如何呢,這時候就不用direct交換器了,用topic交換器

    “#”通配剩餘字符,"*"通配部分字符。 如果綁定的時候key爲“#”,那麼其實就是fanout交換器。如果一個通配符都沒有,其實就是direct交換器。

    head交換器貌似是通過消息附帶的頭信息來路由的,不過官方對這個介紹的少之又少,平時也應該沒什麼人用,死信隊列貌似依賴於這個。

    通過交換器的概念,rabbitmq在機制上要比activemq靈活不少。對於activemq來說,你要麼是個queue的消費者,要麼是個topic的訂閱者。你要同時訂閱多個topic,要自己在消費者端寫代碼來實現。在rabbitmq中,你只是queue的消費者,至於你這個queue的消息是從哪個topic來,或者從哪裏直接發過來,這個和消費者沒有關係,而且queue裏的消息從哪來可以在rabbitmq裏動態配置。所以靈活度得到了提升。

 

    rabbitmq同樣也支持主從複製和集羣。但是rabbitmq的集羣非常多樣化,而且需要至少一臺機器做爲磁盤節點,可以持久化queue和exchange的信息,其他的可以爲內存節點。普通集羣中,只有exchange,queue這些定義是分佈在所有機器上的,而queue中的數據不是冗餘的,比如有三臺rabbitmq組成了集羣,他們共享同樣的exchange,queue,但是一條消息數據落到了第一臺機器上,另外兩臺實際上沒有這條數據的。 對於整個集羣的使用,這樣其實沒有任何問題。  但出於高可用的角度來想,還是需要完完全全的分佈式集羣的,萬一中間有數據這臺機器掛了? rabbitmq對此也有支持,把隊列數據也冗餘存到三臺機器上,稱之爲鏡像隊列,但性能要比普通集羣低,畢竟一條消息被複制到其他機器上是耗時的事情。

    rabbitmq以plugin的形式支持mqtt,和spring整合也非常簡單。

 

 

Redis
一個Key-Value的NoSQL數據庫,開發維護很活躍,雖然它是一個Key-Value數據庫存儲系統,但它本身支持MQ功能,所以完全可以當做一個輕量級的隊列服務來使用。對於RabbitMQ和Redis的入隊和出隊操作,各執行100萬次,每10萬次記錄一次執行時間。測試數據分爲128Bytes、512Bytes、1K和10K四個不同大小的數據。實驗表明:入隊時,當數據比較小時Redis的性能要高於RabbitMQ,而如果數據大小超過了10K,Redis則慢的無法忍受;出隊時,無論數據大小,Redis都表現出非常好的性能,而RabbitMQ的出隊性能則遠低於Redis。
 

RocketMQ
阿里開源的消息中間件,它是純Java開發,具有高吞吐量、高可用性、適合大規模分佈式系統應用的特點。RocketMQ思路起源於Kafka,但並不是Kafka的一個Copy,它對消息的可靠傳輸及事務性做了優化,目前在阿里集團被廣泛應用於交易、充值、流計算、消息推送、日誌流式處理、binglog分發等場景。

ZeroMQ
號稱最快的消息隊列系統,尤其針對大吞吐量的需求場景。ZMQ能夠實現RabbitMQ不擅長的高級/複雜的隊列,但是開發人員需要自己組合多種技術框架,技術上的複雜度是對這MQ能夠應用成功的挑戰。ZeroMQ具有一個獨特的非中間件的模式,你不需要安裝和運行一個消息服務器或中間件,因爲你的應用程序將扮演了這個服務角色。你只需要簡單的引用ZeroMQ程序庫,可以使用NuGet安裝,然後你就可以愉快的在應用程序之間發送消息了。但是ZeroMQ僅提供非持久性的隊列,也就是說如果down機,數據將會丟失。其中,Twitter的Storm中使用ZeroMQ作爲數據流的傳輸。

ActiveMQ
Apache ActiveMQ 是最受歡迎且功能最強大的開源消息傳遞和Integration Patterns服務器。
Apache ActiveMQ速度快,支持許多跨語言客戶端和協議,帶有易於使用的企業集成模式和許多高級功能,同時完全支持JMS 1.1和J2EE 1.4。Apache ActiveMQ是在Apache 2.0許可下發布
特徵
支持Java消息服務(JMS) 1.1 版本
Spring Framework
集羣 (Clustering)
支持的編程語言包括:C、C++、C#、Delphi、Erlang、Adobe Flash、Haskell、Java、JavaScript、Perl、PHP、Pike、Python和Ruby,同時對jms、spring之類的支持很友好。
協議支持包括:OpenWire、REST、STOMP、WS-Notification、MQTT、XMPP以及AMQP [1]

       而且因爲是Java寫的,所以可以作爲一個jar包,放到java項目裏,用代碼啓動和配置,這個對於java開發者而言是不是相當爽?畢竟還是有些場景,需要我們把隊列放到自己項目內部,隨項目啓動而啓動的。而且,還可以類似拓展tomcat一樣,自己寫java的plugin來拓展activemq。比如說,我有10萬硬件連到mq上,這10萬設備每個都有用戶名密碼,這個時候我們可以用java寫個權限驗證,從數據庫裏查這10萬用戶名密碼。

    activemq支持主從複製、集羣。但是集羣功能看起來很弱,只有failover功能,即我連一個失敗了,可以切換到其他的broker上。這一點貌似不太科學。假設有三個broker,其中一個上面沒有consumer,但另外兩個掛了,消息會轉到這個上面來,堆積起來。看樣子activemq還在升級中。

    activemq工作模型比較簡單。只有兩種模式 queue,topics 。

    queue就多對一,producer往queue裏發送消息,消費者從queue裏取,消費一條,就從queue裏移除一條。如果一個消費者消費速度不夠快怎麼辦呢?在activemq裏,提供messageGroup的概念,一個queue可以有多個消費者,但是他們得標記自己是一個messageGroup裏的。這樣,消息會輪訓發送給每個消費者,也就是說消費者不會重複消費同一條消息。但是每條消息只被消費一次。

    topics就是廣播。producer往broker發消息,每個消息包含topic。消費者訂閱感興趣的topic,所有訂閱了topic的消費者都會收到消息。當然訂閱分持久不持久。持久訂閱,當消費者斷開一會,再連上來,仍然會把沒收到的消費發過來。不持久的訂閱,斷開這段時間的消息就收不到了。

    activemq支持mqtt、ssl。

 

 

綜上所述,各種對比之後,總結如下:

一般的業務系統要引入MQ,最早大家都用ActiveMQ,但是現在確實大家用的不多了,沒經過大規模吞吐量場景的驗證,社區也不是很活躍,所以大家還是算了吧,我個人不推薦用這個了;

後來大家開始用RabbitMQ,但是確實erlang語言阻止了大量的java工程師去深入研究和掌控他,對公司而言,幾乎處於不可控的狀態,但是確實人是開源的,比較穩定的支持,活躍度也高;

不過現在確實越來越多的公司,會去用RocketMQ,確實很不錯,但是我提醒一下自己想好社區萬一突然黃掉的風險,對自己公司技術實力有絕對自信的,我推薦用RocketMQ,否則回去老老實實用RabbitMQ吧,人是活躍開源社區,絕對不會黃

所以中小型公司,技術實力較爲一般,技術挑戰不是特別高,用RabbitMQ是不錯的選擇(我們項目也正在使用這個^_^);大型公司,基礎架構研發實力較強,用RocketMQ是很好的選擇

如果是大數據領域的實時計算、日誌採集等場景,用Kafka是業內標準的,絕對沒問題,社區活躍度很高,絕對不會黃,何況幾乎是全世界這個領域的事實性規範

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章