目錄
概述
在進行大型的、複雜的項目建設中,往往會涉及模塊與模塊之前的消息通信的問題,消息通信可以通過硬件設施或者軟件設施來實現,通過硬件設施進行消息通信的就涉及比較高度安全和高度機密的政府及軍用的通信了(通信成本高、時間長等特點),一般大、中、小型企業系統模塊之前的通信都是通過消息中間件來實現的,如果再往高出走一點,就是企業自己根據業務需求,自己寫一套複合自生業務發展的消息通信中間見咯。
本文將從 Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ這幾個常見的消息中間件中進行選型對比。
項目中消息中間件的選型
一、消息中間件概述
Kafka
Kafka 是由 Apache軟件基金會開發的一個開源流處理平臺,由 Scala語言和 Java語言編寫。Kafka是一種高吞吐量的分佈式發佈訂閱消息系統,它可以處理消費者在網站中的所有動作流數據。 這種動作(網頁瀏覽,搜索和其他用戶的行動)是在現代網絡上的許多社會功能的一個關鍵因素。 這些數據通常是由於吞吐量的要求而通過處理日誌和日誌聚合來解決。 對於像Hadoop一樣的日誌數據和離線分析系統,但又要求實時處理的限制,這是一個可行的解決方案。Kafka的目的是通過Hadoop的並行加載機制來統一線上和離線的消息處理,也是爲了通過集羣來提供實時的消息。
RabbitMQ
RabbitMQ是實現了高級消息隊列協議(AMQP)的開源消息代理軟件(亦稱面向消息的中間件)。RabbitMQ服務器是用Erlang語言編寫的,而集羣和故障轉移是構建在開放電信平臺框架上的。所有主要的編程語言均有與代理接口通訊的客戶端庫。
ZeroMQ
ZeroMQ(簡稱ZMQ)是一個基於消息隊列的多線程網絡庫,是一個非常輕量級的消息中間件,其對套接字類型、連接處理、幀、甚至路由的底層細節進行抽象,提供跨越多種傳輸協議的套接字。
ZMQ是網絡通信中新的一層,介於應用層和傳輸層之間(按照TCP/IP劃分),ZMQ是一個可伸縮層,可並行運行,分散在分佈式系統間。
ZMQ不是單獨的服務,而是一個嵌入式庫,它封裝了網絡通信、消息隊列、線程調度等功能,向上層提供簡潔的API,應用程序通過加載庫文件,調用API函數來實現高性能網絡通信。
RocketMQ
RocketMQ是一款分佈式、隊列模型的消息中間件,是阿里巴巴集團自主研發的專業消息中間件,借鑑參考了 JMS規範的MQ實現,參考了優秀的開源消息中間件Kafka,實現了業務削峯,分佈式事務的優秀框架。
官網:http://rocketmq.apache.org/
ActiveMQ
ActiveMQ是 Apache軟件基金會研發的開源消息中間件;由於 ActiveMQ是一個純Java程序,因此只需要操作系統支持 Java虛擬機,ActiveMQ便可執行。
官網:http://activemq.apache.org/
二、消息中間件區別及定義速覽表
功能 | Kafka | RabbitMQ | ZeroMQ | RocketMQ | ActiveMQ |
---|---|---|---|---|---|
支持的協議 | 自己定義的一套(基於TCP的協議) | AMQP | TCP/UDP | 自己定義的一套 | OpenWire、STOMP、REST、XMPP、AMQP |
存儲方式 | 內存、磁盤、數據庫。支持大量堆積。 | 內存、磁盤。支持少量堆積。 | 消息發送端的內存或者磁盤中。不支持持久化。 | 磁盤。支持大量堆積。 | 內存、磁盤、數據庫。支持少量堆積。 |
事務支持 | 支持 | 支持,使用事務會使性能有所下降 | 不支持 | 支持 | 支持 |
負載均衡 | 支持負載均衡 | 對負載均衡的支持不好 | 去中心化,不支持負載均衡,本身只是一個多線程網絡庫 | 支持負載均衡 | 支持負載均衡,需要通過集成zookeeper來實現負載均衡 |
集羣 | 天然的 Leader-Slave 無狀態集羣,每臺服務器既是Master也是Slave。 | 支持簡單集羣,複製模式,對高級集羣模式支持不好。 | 去中心化,不支持集羣。 | 常用多對 Master-Slave 模式,開源版本需手動切換Slave變成Master。集羣的slave會從master拉取數據備份,master分佈在不同的broker上。 | 支持簡單集羣模式,比如'主-備',對高級集羣模式支持不好。 |
高可用 | 非常高(分佈式) | 高(主從) | 高 | 非常高(分佈式) | 高(主從) |
消息重複 | 支持at least once、at most once | 支持at least once、at most once | 既不支持at least once、也不支持at most once、更不支持exactly only once | 支持at least once | 支持at least once |
吞吐量 (TPS) |
灰常大,Kafka 按批次發送消息和消費消息 | 比較大 | 非常大 | 大,rocketMQ 接收端可以批量消費消息,可以配置每次消費的消息數,但是發送端不是批量發送。 | 比較大 |
消息訂閱與發佈 | 基於topic以及按照topic進行正則匹配的發佈訂閱模式 | 提供了4種:direct, topic ,Headers和fanout | 點對點(P2P) | 基於topic/messageTag以及按照消息類型、屬性進行正則匹配的發佈訂閱模式 | 點對點(P2P)、廣播(發佈-訂閱) |
消息順序支持 | 支持 | 不支持 | 不支持 | 支持 | 不支持 |
消息確認支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
消息回溯支持 | 支持指定分區offset位置的回溯 | 不支持 | 不支持 | 支持指定時間點的回溯 | 不支持 |
消息重試支持 | 不支持,但是可以實現 | 不支持,但是可以利用消息確認機制實現 | 不支持 | 支持 | 不支持 |
併發度 | 高 | 極高 | 高 | 高 | 高 |
管理界面 | 一般 | 好 | 無 | 無 | 一般 |
三、存儲方式概述
Kafka
內存、磁盤、數據庫。支持大量堆積。
Kafka 的最小存儲單元是分區,一個 topic 包含多個分區,Kafka 創建 topic時,這些分區會被分配在多個服務器上,通常一個broker 一臺服務器。 分區首領會均勻地分佈在不同的服務器上,分區副本也會均勻的分佈在不同的服務器上,確保負載均衡和高可用性,當新的 broker 加入集羣的時候,部分副本會被移動到新的broker上。 根據配置文件中的目錄清單,Kafka 會把新的分區分配給目錄清單裏分區數最少的目錄。 默認情況下,分區通過使用輪詢算法把消息均衡地分佈在同一個 topic的不同分區中,對於發送時指定了 key的情況,會根據key的 hashcode取模後的值存到對應的分區中。
RabbitMQ
內存、磁盤。支持少量堆積。
RabbitMQ 的消息分爲持久化的消息和非持久化消息,不管是持久化的消息還是非持久化的消息都可以寫入到磁盤。 持久化的消息在到達隊列時就寫入到磁盤,如果可以,持久化的消息也會在內存中保存一份備份,這樣可以提高一定的性能,當內存喫緊的時候會從內存中清除。非持久化的消息一般只存在於內存中,在內存喫緊的時候會被換入到磁盤中,以節省內存。
引入鏡像隊列機制,可將重要隊列“複製”到集羣中的其他 broker上,保證這些隊列的消息不會丟失。配置鏡像的隊列,都包含一個主節點 master和多個從節點 slave,如果 master失效,加入時間最長的 slave會被提升爲新的 master,除發送消息外的所有動作都向 master發送,然後由 master將命令執行結果廣播給各個 slave,RabbitMQ 會讓 master均勻地分佈在不同的服務器上,而同一個隊列的 slave也會均勻地分佈在不同的服務器上,保證負載均衡和高可用性。
ZeroMQ
消息發送端的內存或者磁盤中,不支持持久化。
RocketMQ
磁盤。支持大量堆積。
commitLog 文件存放實際的消息數據,每個 commitLog上限是1G,滿了之後會自動新建一個 commitLog文件保存數據。ConsumeQueue隊列只存放offset、size、tagcode,非常小,分佈在多個broker上。ConsumeQueue 相當於 CommitLog的索引文件,消費者消費時會從 consumeQueue中查找消息在 commitLog中的offset,再去 commitLog中查找元數據。
ConsumeQueue存儲格式的特性,保證了寫過程的順序寫盤(寫CommitLog文件),大量數據IO都在順序寫同一個commitLog,滿1G了再寫新的。加上 RocketMQ是累計4K才強制從 PageCache中刷到磁盤(緩存),所以高併發寫性能突出。
ActiveMQ
內存、磁盤、數據庫。支持少量堆積。
四、負載均衡概述
Kafka
支持負載均衡。
1、一個 broker通常就是一臺服務器節點。對於同一個 Topic的不同分區,Kafka會盡力將這些分區分佈到不同的 Broker服務器上,zookeeper 保存了broker、Topic和分區的元數據信息。分區 Leader會處理來自客戶端的生產請求,kafka分區 Leader會被分配到不同的 broker服務器上,讓不同的 broker服務器共同分擔任務。每一個 broker都緩存了元數據信息,客戶端可以從任意一個 broker獲取元數據信息並緩存起來,根據元數據信息知道要往哪裏發送請求。
2、kafka的消費者組訂閱同一個Topic,會盡可能地使得每一個消費者分配到相同數量的分區,分攤負載。
3、當消費者加入或者退出消費者組的時候,還會觸發再均衡,爲每一個消費者重新分配分區,分攤負載。kafka的負載均衡大部分是自動完成的,分區的創建也是自動完成的,隱藏了很多細節,避免了繁瑣的配置和人爲疏忽造成的負載問題。
4、發送端由 Topic和 Key來決定消息發往哪個分區,如果 Key爲null,那麼會使用輪詢算法將消息均衡地發送到同一個 Topic的不同分區中。如果 Key不爲null,那麼會根據 Key的hashcode取模計算出要發往的分區。
RabbitMQ
對負載均衡的支持不好。
1、消息被投遞到哪個隊列是由 exchang和 key決定的,exchang、key、queue都需要手動創建。
RabbitMQ客戶端發送消息要和 broker建立連接,需要事先知道 broker上有哪些 exchang,有哪些 queue。通常要聲明要發送的目標 queue,如果沒有目標 queue,會在 broker上創建一個 queue,如果有,就什麼都不處理,接着往這個 queue中發送消息。假設大部分繁重任務的 queue都創建在同一個broker上,那麼這個 broker的負載就會過大。(可以在上線前預先創建隊列,無需聲明要發送的隊列,但是發送時不會嘗試創建隊列,可能出現找不到隊列的問題,RabbitMQ 的備份 exchang會把找不到隊列的消息保存到一個專門的隊列中,以便以後查詢使用)
使用鏡像隊列機制建立 RabbitMQ集羣可以解決 broker的負載就會過大的問題,形成 master-slave的架構,master節點會均勻分佈在不同的服務器上,讓每一臺服務器分攤負載。slave節點只是負責轉發,在 master失效時會選擇加入時間最長的 slave成爲master。
當新節點加入鏡像隊列的時候,隊列中的消息不會同步到新的slave中,除非調用同步命令,但是調用命令後,隊列會阻塞,不能在生產環境中調用同步命令。
2、當 RabbitMQ隊列擁有多個消費者的時候,隊列收到的消息將以輪詢的分發方式發送給消費者。每條消息只會發送給訂閱列表裏的一個消費者,不會重複。這種方式非常適合擴展,而且是專門爲併發程序設計的。如果某些消費者的任務比較繁重,那麼可以設置 basicQos限制信道上消費者能保持的最大未確認消息的數量,在達到上限時,RabbitMQ不再向這個消費者發送任何消息。
3、對於 RabbitMQ而言,客戶端與集羣建立的 TCP連接不是與集羣中所有的節點建立連接,而是挑選其中一個節點建立連接。但是 RabbitMQ集羣可以藉助 HAProxy、LVS技術,或者在客戶端使用算法實現負載均衡,引入負載均衡之後,各個客戶端的連接可以分攤到集羣的各個節點之中。
RabbitMQ Client均衡算法:
- 輪詢法。按順序返回下一個服務器的連接地址;
- 加權輪詢法。給配置高、負載低的機器配置更高的權重,讓其處理更多的請求;而配置低、負載高的機器,給其分配較低的權重,降低其系統負載;
- 隨機法。隨機選取一個服務器的連接地址;
- 加權隨機法。按照概率隨機選取連接地址;
- 源地址哈希法。通過哈希函數計算得到的一個數值,用該數值對服務器列表的大小進行取模運算;
- 最小連接數法。動態選擇當前連接數最少的一臺服務器的連接地址;
ZeroMQ
去中心化,不支持負載均衡。本身只是一個多線程網絡庫。
RocketMQ
支持負載均衡。一個 broker通常是一個服務器節點,broker 分爲 master和 slave,master和 slave存儲的數據一樣,slave從master同步數據。
1、nameserver與每個集羣成員保持心跳,保存着 Topic-Broker路由信息,同一個 Topic的隊列會分佈在不同的服務器上。
2、發送消息通過輪詢隊列的方式發送,每個隊列接收平均的消息量。發送消息指定 Topic、Tags、Keys,無法指定投遞到哪個隊列(沒有意義,集羣消費和廣播消費跟消息存放在哪個隊列沒有關係)。
Tags 選填,類似於 Gmail 爲每封郵件設置的標籤,方便服務器過濾使用。目前只支持每個消息設置一個 tag,所以,也可以類比爲 Notify 的 MessageType 概念。
Keys 選填,代表這條消息的業務關鍵詞,服務器會根據 Keys 創建哈希索引,設置後, 可以在 Console 系統根據 Topic、Keys 來查詢消息,由於是哈希索引,所以儘可能保證 Key唯一。
3、RocketMQ的負載均衡策略規定:Consumer數量應該小於等於 Queue數量,如果 Consumer超過 Queue數量,那麼多餘的 Consumer 將不能消費消息。這一點和 Kafka是一致的,RocketMQ會盡可能地爲每一個 Consumer分配相同數量的隊列,分攤負載。
ActiveMQ
支持負載均衡。基於 zookeeper實現負載均衡。
五、集羣方式概述
Kafka
天然的 Leader-Slave 無狀態集羣,每臺服務器既是Master 也是Slave。
分區首領均勻地分佈在不同的kafka服務器上,分區副本也均勻地分佈在不同的kafka服務器上,所以每一臺kafka服務器既含有分區首領,同時又含有分區副本,每一臺kafka服務器是某一臺kafka服務器的Slave,同時也是某一臺kafka服務器的leader。
kafka的集羣依賴於zookeeper,zookeeper支持熱擴展,所有的broker、消費者、分區都可以動態加入移除,而無需關閉服務,與不依靠zookeeper集羣的mq相比,這是最大的優勢。但是現在最新的 kafka版本已經有了自己的一套zk,如果在項目中使用kafka時,如果沒有硬性的要求,可以使用kafka中的zk,功能和目的都是一樣的。
RabbitMQ
支持簡單集羣,複製模式,對高級集羣模式支持不好。
rabbitmq的每一個節點,不管是單一節點系統或者是集羣中的一部分,要麼是內存節點,要麼是磁盤節點,集羣中至少要有一個是磁盤節點。
在rabbitmq集羣中創建隊列,集羣只會在單個節點創建隊列進程和完整的隊列信息(元數據、狀態、內容),而不是在所有節點上創建。
引入鏡像隊列,可以避免單點故障,確保服務的可用性,但是需要人爲地爲某些重要的隊列配置鏡像。
ZeroMQ
去中心化,不支持集羣。
RocketMQ
常用多對 Master-Slave 模式,開源版本需手動切換Slave變成Master。集羣的slave會從master拉取數據備份,master分佈在不同的broker上。
Name Server是一個幾乎無狀態節點,可集羣部署,節點之間無任何信息同步。
Broker部署相對複雜,Broker分爲Master與Slave,一個Master可以對應多個Slave,但是一個Slave只能對應一個Master,Master與Slave的對應關係通過指定相同的BrokerName,不同的BrokerId來定義,BrokerId爲0表示Master,非0表示Slave。Master也可以部署多個。每個Broker與Name Server集羣中的所有節點建立長連接,定時註冊Topic信息到所有Name Server。
Producer與Name Server集羣中的其中一個節點(隨機選擇)建立長連接,定期從Name Server取Topic路由信息,並向提供Topic服務的Master建立長連接,且定時向Master發送心跳。Producer完全無狀態,可集羣部署。
Consumer與Name Server集羣中的其中一個節點(隨機選擇)建立長連接,定期從Name Server取Topic路由信息,並向提供Topic服務的Master、Slave建立長連接,且定時向Master、Slave發送心跳。Consumer既可以從Master訂閱消息,也可以從Slave訂閱消息,訂閱規則由Broker配置決定。
客戶端先找到NameServer, 然後通過NameServer再找到 Broker。
一個topic有多個隊列,這些隊列會均勻地分佈在不同的broker服務器上。rocketmq隊列的概念和kafka的分區概念是基本一致的,kafka同一個topic的分區儘可能地分佈在不同的broker上,分區副本也會分佈在不同的broker上。
ActiveMQ
支持簡單集羣模式,比如'主-備',對高級集羣模式支持不好。
六、消息的訂閱與發佈概述
Kafka
Kafka是基於 topic以及按照 topic進行正則匹配的發佈訂閱模式。
消息發送:
發送端由 topic和 key來決定消息發往哪個分區,如果 key爲null,那麼會使用輪詢算法將消息均衡地發送到同一個 topic的不同分區中。如果 key不爲null,那麼會根據 key的 hashcode取模計算出要發往的分區。
消息接收:
1、consumer向組協調器 broker發送心跳來維持和組的從屬關係以及對分區的所有權關係,所有權關係一旦被分配就不會改變,除非發生再均衡(比如有一個consumer加入或者離開consumer group),consumer只會從對應的分區讀取消息;
2、kafka限制 consumer個數要少於分區個數,每個消息只會被同一個 consumer group的一個consumer消費(非廣播);
3、kafka的 consumer group訂閱同一個topic,會盡可能地使得每一個 consumer分配到相同數量的分區,不同 consumer group訂閱同一個 topic相互獨立,同一個消息會被不同的 consumer group處理;
RabbitMQ
RabbitMQ提供了4種模式,即:direct、topic 、Headers和fanout。
消息發送:
首先,聲明一個隊列(新創建或已經存在的隊列),隊列是RabbitMQ基本存儲單元,由 exchange和 key決定消息存儲放在哪個隊列中。
- direct,發送到和 bindingKey完全匹配的隊列;
- topic,路由 key是含有"."的字符串,會發送到含有“*”、“#”進行模糊匹配的 bindingKey對應的隊列;
- headers,與 key無關,是消息內容的 headers屬性(一個鍵值對)和綁定鍵值對完全匹配時,纔會發送到此隊列。此方式性能極低一般不使用;
- fanout,與 key無關,消息會發送到所有和 exchange綁定的隊列中;
消息接收:
RabbitMQ 的隊列是基本存儲單元,不再被分區或者分片,對於已經創建了的隊列,消費端要指定從哪一個隊列接收消息。
當 RabbitMQ隊列擁有多個消費者的時候,隊列收到的消息將以輪詢的方式分發給消費者。每條消息只會發送給訂閱列表裏的一個消費者,不會重複發送,這種方式非常適合擴展,而且是專門爲併發程序設計的。
如果某些消費者的任務比較繁重,那麼可以設置 basicQos限制信道上消費者能保持的最大未確認消息的數量,在達到上限時,RabbitMQ不再向這個消費者發送任何消息。
ZeroMQ
ZeroMQ的消息發佈與訂閱是點對點(p2p)的方式。
RocketMQ
RocketMQ是基於topic、messageTag以及按照消息類型、屬性進行正則匹配的發佈訂閱模式。
消息發送:
發送消息通過輪詢隊列的方式發送,每個隊列接收平均的消息量。發送消息需要依賴於topic、tags、keys,無法指定投遞到哪個具體的隊列,指定了也沒有意義,集羣消費和廣播消費跟消息存放在哪個隊列沒有任何關係。
tags可以不指定,tag類似於 Gmail爲每封郵件設置的標籤,方便服務器過濾使用。目前只支持每個消息設置一個 tag,所以也可以類比爲 Notify 的 MessageType 概念。
keys可以不指定,key代表這條消息的業務關鍵詞,服務器會根據 keys創建哈希索引,設置後,可以在 Console系統根據 Topic、Keys 來查詢消息,由於是哈希索引,所以需要儘可能保證 key唯一性。
消息接收:
1、廣播消費,一條消息被多個 consumer消費,即使 consumer屬於同一個 consumer group,消息也會被 consumer group中的每個 consumer都消費一次。
2、集羣消費,一個 consumer group中的 consumer實例平均分攤消費消息。例如某個topic有 9 條消息,其中一個 consumer group有3個實例,那麼每個實例只消費其中的 3 條消息。即每一個隊列都把消息輪流分發給每個 consumer。
ActiveMQ
ActiveMQ是點對點(p2p)、廣播(發佈-訂閱)的發佈訂閱模式。點對點模式,即每個消息對應1個消費者;發佈/訂閱模式,每個消息對應多個消費者。
消息發送:
- 點對點模式,先要指定一個隊列,這個隊列已經存在或者新創建;
- 發佈/訂閱模式,先要指定一個 topic,這個topic已經存在或者新創建;
消息接收:
- 點對點模式:對於已經創建了的隊列,消費端要指定從哪一個隊列接收消息;
- 發佈/訂閱模式:對於已經創建了的topic,消費端要指定訂閱哪一個topic的消息;
七、消息確認機制概述
Kafka
Kafka支持消息確認,Kafka的消息確認分爲兩方面,一個是消息發送方確認,一個是消息接收方確認:
1、發送方確認機制
- ack=0,不管消息是否成功寫入分區;
- ack=1,消息成功寫入首領分區後,返回成功;
- ack=all,消息成功寫入所有分區後,返回成功;
2、接收方確認機制
通過自動或者手動提交分區偏移量來實現,早期版本的 Kafka偏移量是提交給 Zookeeper的,這樣使得 Zookeeper的壓力比較大,現在新版本的 Kafka的偏移量都是提交給 Kafka服務器端的,不再依賴於 Zookeeper,這樣以來 Kafka集羣的性能會更加穩定。
RabbitMQ
RabbitMQ支持消息確認,RabbitMQ的消息確認分爲兩方面,一個是消息發送方確認,一個是消息接收方確認:
1、發送方確認。消息被投遞到所有匹配的隊列後,返回成功。如果消息和隊列是可持久化的,那麼在寫入磁盤後,返回成功。支持批量確認和異步確認。
2、接收方確認機制,設置autoAck爲false,需要顯式確認,設置autoAck爲true,自動確認。
當autoAck爲false的時候,rabbitmq隊列會分成兩部分,一部分是等待投遞給consumer的消息,一部分是已經投遞但是沒收到確認的消息。如果一直沒有收到確認信號,並且consumer已經斷開連接,rabbitmq會安排這個消息重新進入隊列,投遞給原來的消費者或者下一個消費者。
未確認的消息不會有過期時間,如果一直沒有確認,並且沒有斷開連接,rabbitmq會一直等待,rabbitmq允許一條消息處理的時間可以很久很久。
ZeroMQ
ZeroMQ支持消息確認。
RocketMQ
RocketMQ支持消息確認。
ActiveMQ
ActiveMQ支持消息確認。
八、消息重試概述
Kafka:Kafka不支持消息重試,但是可以實現。kafka支持指定分區 offset位置的回溯,可以實現消息重試。
RabbitMQ:RabbitMQ不支持消息重試,但是可以利用消息確認機制實現。RabbitMQ接收方確認機制,設置 autoAck爲false來實現。當 autoAck設爲false的時候,RabbitMQ隊列會分成兩部分,一部分是等待投遞給 consumer的消息,一部分是已經投遞但是沒收到確認的消息。如果一直沒有收到確認信號,並且 consumer已經斷開連接,RabbitMQ會安排這個消息重新進入隊列,投遞給原來的消費者或者下一個消費者。
ZeroMQ:ZeroMQ不支持消息重試。
RocketMQ:RocketMQ支持消息重試。消息消費失敗的大部分場景下,立即重試99%都會失敗,所以RocketMQ的策略是在消費失敗時定時重試,每次時間間隔相同。
1、發送端的 send方法本身支持內部重試,重試邏輯如下:
- 最多重試3次;
- 如果發送失敗,則輪轉到下一個broker;
- send方法的總耗時不超過 sendMsgTimeout設置的值,默認 10s,超過時間不再重試;
2、接收端的 Consumer 消費消息失敗後,要提供一種重試機制,使消息再消費一次。Consumer 消費消息失敗通常可以分爲以下兩種情況:
- 消息本身的原因。例如反序列化失敗,消息數據本身無法處理等。定時重試機制,比如過 10s 秒後再重試。
- 依賴的下游應用服務不可用,例如 DB連接不可用,系統外部網絡不可達等。即使跳過當前失敗的消息,消費其他消息同樣也會失敗。這種情況可以 sleep 30s 再消費下一條消息,減輕 Broker重試消息的壓力。
ActiveMQ:ActiveMQ不支持消息重試。
九、消息中間件併發度概述
Kafka
高,一個線程一個消費者,kafka限制消費者的個數要小於等於分區數,如果要提高並行度,可以在消費者中再開啓多線程,或者增加consumer實例數量。
RabbitMQ
極高,RabbitMQ本身是用 Erlang語言寫的,併發性能高。
可在消費者中開啓多線程,最常見的做法是一個 channel對應一個消費者,每一個線程對應一個 channel,多個線程複用 connection的tcp連接,減少性能開銷。
當 RabbitMQ隊列擁有多個消費者的時候,隊列收到的消息將以輪詢的方式發送給消費者。每條消息只會發送給訂閱列表裏的一個消費者,不會重複發送。
如果某些消費者的任務比較繁重,那麼可以設置 basicQos限制信道上消費者能保持的最大未確認消息的數量,在達到上限時,RabbitMQ不再向這個消費者發送任何消息。
ZeroMQ
ZeroMQ的併發度高。
RocketMQ
RocketMQ的併發度高RocketMQ限制消費者的個數少於等於隊列數,但是可以在消費者中再開啓多線程,這一點和 kafka是一致的,提高並行度的方法相同。
同一個網絡連接時,客戶端多個線程可以同時發送請求,連接會被複用,減少系統性能開銷。
如何修改RocketMQ消費的併發度:
- 同一個 ConsumerGroup 下,通過增加 Consumer 實例數量來提高併發度,超過訂閱隊列數的 Consumer實例無效。
- 提高單個 Consumer 的消費並行線程,通過修改參數consumeThreadMin、consumeThreadMax
ActiveMQ
ActiveMQ併發度高。單個 ActiveMQ的接收和消費消息的速度在1萬/秒(持久化一般爲1-2萬,非持久化2萬以上),也就是說,如果部署 10個ActiveMQ就能達到10萬/秒以上的併發度,部署越多的 ActiveMQ broker 在 MQ上 latency也就越低,系統吞吐量也就越高。
十、管理界面友好程度
Kafka:一般
RabbitMQ:好
ZeroMQ:無
RocketMQ:無
ActiveMQ:一般
好了,關於 項目中如何選擇消息中間件?消息中間件的選型? 就寫到這兒了,如果還有什麼疑問或遇到什麼問題歡迎掃碼提問,也可以給我留言哦,我會一一詳細的解答的。
歇後語:“ 共同學習,共同進步 ”,也希望大家多多關注CSND的IT社區。
作 者: | 華 仔 |
聯繫作者: | [email protected] |
來 源: | CSDN (Chinese Software Developer Network) |
原 文: | https://blog.csdn.net/Hello_World_QWP/article/details/103628314 |
版權聲明: | 本文爲博主原創文章,請在轉載時務必註明博文出處! |