常見消息中間件大 PK

@[toc] 說到消息中間件,估計大夥多多少少都能講出來一些,ActiveMQ、RabbitMQ、RocketMQ、Kafka 等等各種以及 JMS、AMQP 等各種協議,然而這些消息中間件各自都有什麼特點,我們在開發中又該選擇哪種呢?今天松哥就來和小夥伴們梳理一下。

1. 幾種協議

先來說說消息中間件中常見的幾個協議。

1.1 JMS

1.1.1 JMS 介紹

先來說說 JMS。

JMS 全稱 Java Message Service,類似於 JDBC,不同於 JDBC,JMS 是 JavaEE 的消息服務接口,JMS 主要有兩個版本:

  • 1.1
  • 2.0。

兩者相比,後者主要是簡化了收發消息的代碼。

考慮到消息中間件是一個非常常用的工具,所以 JavaEE 爲此制定了專門的規範 JMS。

不過和 JDBC 一樣,JMS 作爲規範,他只是一套接口,並不包含具體的實現,如果我們要使用 JMS,那麼一般還需要對應的實現,這就像使用 JDBC 需要對應的驅動一樣。

1.1.2 JMS 模型

JMS 消息服務支持兩種消息模型:

  • 點對點或隊列模型
  • 發佈/訂閱模型

在點對點或隊列模型下,一個生產者向一個特定的隊列發佈消息,一個消費者從該隊列中讀取消息。這裏,生產者知道消費者的隊列,並直接將消息發送到對應的隊列。這是一種點對點的消息模型,這種模式被概括爲:

  1. 只有一個消費者將獲得消息。
  2. 生產者不需要在消費者消費該消息期間處於運行狀態,消費者也同樣不需要在消息發送時處於運行狀態,即消息的生產者和消費者是完全解耦的。
  3. 每一個成功處理的消息都由消息消費者簽收。

發佈者/訂閱者模型支持向一個特定的消息主題發佈消息,消費者則可以定義自己感興趣的主題,這是一種點對面的消息模型,這種模式可以被概括爲:

  • 多個消費者可以消費消息。
  • 在發佈者和訂閱者之間存在時間依賴性,發佈者需要創建一個訂閱(subscription),以便客戶能夠訂閱;訂閱者必須保持在線狀態以接收消息;當然,如果訂閱者創建了持久的訂閱,那麼在訂閱者未連接時,消息生產者發佈的消息將會在訂閱者重新連接時重新發布。

1.1.3 JMS 實現

開源的支持 JMS 的消息中間件有:

  • Kafka
  • Apache ActiveMQ
  • JBoss 社區的 HornetQ
  • Joram
  • Coridan 的 MantaRay
  • OpenJMS

一些商用的支持 JMS 的消息中間件有:

  • WebLogic Server JMS
  • EMS
  • GigaSpaces
  • iBus
  • IONA JMS
  • IQManager(2005 年 8 月被Sun Microsystems併購)
  • JMS+
  • Nirvana
  • SonicMQ
  • WebSphere MQ

這裏有不少是松哥考古挖掘出來的,其實對於我們日常開發接觸較多的,可能就是 Kafka 和 ActiveMQ。

1.2 AMQP

1.2.1 AMQP 簡介

另一個和消息中間件有關的協議就是 AMQP 了。

Message Queue 的需求由來已久,80 年代最早在金融交易中,高盛等公司採用 Teknekron 公司的產品,當時的 Message Queue 軟件叫做:the information bus(TIB)。 TIB 被電信和通訊公司採用,路透社收購了 Teknekron 公司。之後,IBM 開發了 MQSeries,微軟開發了 Microsoft Message Queue(MSMQ)。這些商業 MQ 供應商的問題是廠商鎖定,價格高昂。2001 年,Java Message Service 試圖解決鎖定和交互性的問題,但對應用來說反而更加麻煩了。

於是 2004 年,摩根大通和 iMatrix 開始着手 Advanced Message Queuing Protocol (AMQP)開放標準的開發。2006 年,AMQP 規範發佈。2007 年,Rabbit 技術公司基於 AMQP 標準開發的 RabbitMQ 1.0 發佈。

目前 RabbitMQ 的最新版本爲 3.5.7,基於 AMQP 0-9-1。

在 AMQP 協議中,消息收發涉及到如下一些概念:

  • Broker: 接收和分發消息的應用,我們日常所用的 RabbitMQ 就是一個 Message Broker。
  • Virtual host: 出於多租戶和安全因素設計的,把 AMQP 的基本組件劃分到一個虛擬的分組中,類似於網絡中的 namespace 概念。當多個不同的用戶使用同一個 RabbitMQ 提供的服務時,可以劃分出多個 vhost,每個用戶在自己的 vhost 中創建 exchange/queue 等,這個松哥之前寫過專門的文章,傳送門:RabbitMQ 中的 VirtualHost 該如何理解
  • Connection: publisher/consumer 和 broker 之間的 TCP 連接,斷開連接的操作只會在 client 端進行,Broker 不會斷開連接,除非出現網絡故障或 broker 服務出現問題。
  • Channel: 如果每一次訪問 RabbitMQ 都建立一個 Connection,在消息量大的時候建立 TCP Connection 的開銷將是巨大的,效率也較低。Channel 是在 Connection 內部建立的邏輯連接,如果應用程序支持多線程,通常每個 Thread 創建單獨的 Channel 進行通訊,AMQP method 包含了 Channel id 幫助客戶端和 Message Broker 識別 Channel,所以 Channel 之間是完全隔離的。Channel 作爲輕量級的 Connection 極大減少了操作系統建立 TCP Connection 的開銷,關於 Channel,松哥在RabbitMQ 管理頁面該如何使用一文中也做過詳細介紹。
  • Exchange: Message 到達 Broker 的第一站,根據分發規則,匹配查詢表中的 routing key,分發消息到 queue 中去。常用的類型有:direct (點對點), topic(發佈訂閱) 以及 fanout (廣播)。
  • Queue: 消息最終被送到這裏等待 Consumer 取走,一個 Message 可以被同時拷貝到多個 queue 中。
  • Binding: Exchange 和 Queue 之間的虛擬連接,binding 中可以包含 routing key,Binding 信息被保存到 Exchange 中的查詢表中,作爲 Message 的分發依據。

1.2.2 AMQP 實現

來看看實現了 AMQP 協議的一些具體的消息中間件產品都有哪些。

  • Apache Qpid
  • Apache ActiveMQ
  • RabbitMQ

可能有小夥伴奇怪咋還有 ActiveMQ?其實 ActiveMQ 不僅支持 JMS,也支持 AMQP,這個松哥後面細說。

另外還有大家熟知的阿里出品的 RocketMQ,這個是自定義了一套協議,社區也提供了 JMS,但是不太成熟,後面松哥細說。

1.3 MQTT

做物聯網開發的小夥伴應該會經常接觸這個協議,MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是 IBM 開發的一個即時通訊協議,目前看來算是物聯網開發中比較重要的協議之一了,該協議支持所有平臺,幾乎可以把所有聯網物品和外部連接起來,被用來當做傳感器和 Actuator(比如通過 Twitter 讓房屋聯網)的通信協議,它的優點是格式簡潔、佔用帶寬小、支持移動端通信、支持 PUSH、適用於嵌入式系統。

1.4 XMPP

XMPP(可擴展消息處理現場協議,Extensible Messaging and Presence Protocol)是一個基於 XML 的協議,多用於即時消息(IM)以及在線現場探測,適用於服務器之間的準即時操作。核心是基於 XML 流傳輸,這個協議可能最終允許因特網用戶向因特網上的其他任何人發送即時消息,即使其操作系統和瀏覽器不同。 它的優點是通用公開、兼容性強、可擴展、安全性高,缺點是 XML 編碼格式佔用帶寬大。

1.5 JMS Vs AMQP

對於我們 Java 工程師而言,大家日常接觸較多的應該是 JMS 和 AMQP 協議,既然 JMS 和 AMQP 都是協議,那麼兩者有什麼區別呢?來看下面一張圖:

這張圖說的很清楚了,我就不囉嗦了。

2. 重要產品

2.1 ActiveMQ

ActiveMQ 是 Apache 下的一個子項目,使用完全支持 JMS1.1 和 J2EE1.4 規範的 JMS Provider 實現,少量代碼就可以高效地實現高級應用場景,並且支持可插拔的傳輸協議,如:in-VM, TCP, SSL, NIO, UDP, multicast, JGroups and JXTA transports

ActiveMQ 支持常用的多種語言客戶端如 C++、Java、.Net,、Python、 Php、 Ruby 等。

現在的 ActiveMQ 分爲兩個版本:

  • ActiveMQ Classic
  • ActiveMQ Artemis

這裏的 ActiveMQ Classic 就是原來的 ActiveMQ,而 ActiveMQ Artemis 是在 RedHat 捐贈的 HornetQ 服務器代碼的基礎上開發的,兩者代碼完全不同,後者支持 JMS2.0,使用基於 Netty 的異步 IO,大大提升了性能,更爲神奇的是,後者不僅支持 JMS 協議,還支持 AMQP 協議、STOMP 以及 MQTT,可以說後者的玩法相當豐富。

因此大家在使用時,建議直接選擇 ActiveMQ Artemis。

2.2 RabbitMQ

RabbitMQ 算是 AMQP 體系下最爲重要的產品了,它基於 Erlang 語言開發實現,估計很多人被 RabbitMQ 的安裝摺磨過,松哥建議安裝 RabbitMQ 直接用 Docker,省心省力(公號後臺回覆 docker 有教程)。

RabbitMQ 支持 AMQP、XMPP、SMTP、STOMP 等多種協議,功能強大,適用於企業級開發。

來看一張 RabbitMQ 的結構圖:

關於 RabbitMQ,松哥最近發了十來篇教程了,這裏就不再囉嗦了。

2.3 RocketMQ

RocketMQ 是阿里開源的一款分佈式消息中間件,原名 Metaq,從 3.0 版本開始改名爲 RocketMQ,是阿里參照 Kafka 設計思想使用 Java 語言實現的一套 MQ。RocketMQ 將阿里內部多款 MQ 產品(Notify、Metaq)進行整合,只維護核心功能,去除了所有其他運行時依賴,保證核心功能最簡化,在此基礎上配合阿里上述其他開源產品實現不同場景下 MQ 的架構,目前主要用於訂單交易系統。

RocketMQ 具有以下特點:

  • 保證嚴格的消息順序。
  • 提供針對消息的過濾功能。
  • 提供豐富的消息拉取模式。
  • 高效的訂閱者水平擴展能力。
  • 實時的消息訂閱機制。
  • 億級消息堆積能力

對於 Java 工程師而言,這也是一種經常會用到的 MQ。

2.4 Kafka

Kafka 是 Apache 下的一個開源流處理平臺,由 Scala 和 Java 編寫。Kafka 是一種高吞吐量的分佈式發佈訂閱消息系統,它可以處理消費者在網站中的所有動作(網頁瀏覽,搜索和其他用戶的行動)流數據。Kafka 的目的是通過 Hadoop 的並行加載機制來統一線上和離線的消息處理,也是爲了通過集羣來提供實時的消息。

Kafka 具有以下特性:

  • 快速持久化:通過磁盤順序讀寫與零拷貝機制,可以在O(1)的系統開銷下進行消息持久化。
  • 高吞吐:在一臺普通的服務器上既可以達到 10W/s 的吞吐速率。
  • 高堆積:支持 topic 下消費者較長時間離線,消息堆積量大。
  • 完全的分佈式系統:Broker、Producer、Consumer 都原生自動支持分佈式,通過 Zookeeper 可以自動實現更加複雜的負載均衡。
  • 支持 Hadoop 數據並行加載。

大數據開發中大家可能會經常接觸 Kafka,Java 開發中也會接觸,但是相對來說可能接觸的少一些。

2.5 ZeroMQ

ZeroMQ 號稱最快的消息隊列系統,它專門爲高吞吐量/低延遲的場景開發,在金融界的應用中經常使用,偏重於實時數據通信場景。ZeroMQ 不是單獨的服務,而是一個嵌入式庫,它封裝了網絡通信、消息隊列、線程調度等功能,向上層提供簡潔的 API,應用程序通過加載庫文件,調用 API 函數來實現高性能網絡通信。

ZeroMQ 的特性:

  • 無鎖的隊列模型:對於跨線程間的交互(用戶端和 session)之間的數據交換通道 pipe,採用無鎖的隊列算法 CAS,在 pipe 的兩端註冊有異步事件,在讀或者寫消息到 pipe 時,會自動觸發讀寫事件。
  • 批量處理的算法:對於批量的消息,進行了適應性的優化,可以批量的接收和發送消息。
  • 多核下的線程綁定,無須 CPU 切換:區別於傳統的多線程併發模式,信號量或者臨界區,ZeroMQ 充分利用多核的優勢,每個核綁定運行一個工作者線程,避免多線程之間的 CPU 切換開銷。

2.6 其他

另外還有如 Redis 也能做消息隊列,松哥之前也發過文章和大家介紹用 Redis 做普通消息隊列和延遲消息隊列,這裏也就不囉嗦了。

3. 比較

最後,我們再來通過一張圖來比較下各個消息中間件。

小夥伴們在公衆號後臺回覆 mqpkmq,可以獲取這個 Excel 表格鏈接。

好啦,就扯這麼多。

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