常見消息中間件大 PK
說到消息中間件,估計大伙多多少少都能講出來一些,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 消息服務支持兩種消息模型:
- 點對點或隊列模型
- 發布/訂閱模型
在點對點或隊列模型下,一個生產者向一個特定的隊列發布消息,一個消費者從該隊列中讀取消息。這里,生產者知道消費者的隊列,并直接將消息發送到對應的隊列。這是一種點對點的消息模型,這種模式被概括為:
- 只有一個消費者將獲得消息。
- 生產者不需要在消費者消費該消息期間處于運行狀態,消費者也同樣不需要在消息發送時處于運行狀態,即消息的生產者和消費者是完全解耦的。
- 每一個成功處理的消息都由消息消費者簽收。
發布者/訂閱者模型支持向一個特定的消息主題發布消息,消費者則可以定義自己感興趣的主題,這是一種點對面的消息模型,這種模式可以被概括為:
- 多個消費者可以消費消息。
- 在發布者和訂閱者之間存在時間依賴性,發布者需要創建一個訂閱(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 表格鏈接。
好啦,就扯這么多。
本文轉載自微信公眾號「江南一點雨」,作者猿妹 整編。轉載本文請聯系江南一點雨公眾號。