超贊,大神總結(jié)的主流消息中間件技術(shù)選型對比與參考!
你知道的越多,不知道的就越多,業(yè)余的像一棵小草!
你來,我們一起精進!你不來,我和你的競爭對手一起精進!
編輯:業(yè)余草
推薦:https://www.xttblog.com/?p=5267
消息隊列中間件是分布式系統(tǒng)中重要的組件,主要解決應(yīng)用耦合、異步消息、流量削鋒等問題。它可以實現(xiàn)高性能、高可用、可伸縮和最終一致性架構(gòu),是大型分布式系統(tǒng)不可缺少的中間件。
消息隊列在電商系統(tǒng)、消息通訊、日志收集等應(yīng)用中扮演著關(guān)鍵作用,以阿里為例,其研發(fā)的消息隊列(RocketMQ)在歷次天貓 “雙十一” 活動中支撐了萬億級的數(shù)據(jù)洪峰,為大規(guī)模交易提供了有力保障。
作為提升應(yīng)用性能的重要手段,分布式消息隊列技術(shù)在互聯(lián)網(wǎng)領(lǐng)域得到了越來越廣泛的關(guān)注 。本文將介紹四種常用的分布式消息隊列開源軟件:Kafka、ActiveMQ、RabbitMQ 及 RocketMQ。
Kafka
在分布式消息隊列的江湖里,Kafka 憑借其優(yōu)秀的性能占據(jù)重要一席。它最初由 LinkedIn 公司開發(fā),Linkedin 于 2010 年貢獻給了 Apache基金會,之后成為頂級開源項目。
Kafka簡介
關(guān)于 Kafka,網(wǎng)上有很多介紹,經(jīng)過不斷地復(fù)制、洗稿、演繹后,難免背離原意,因此,我們還是來看一下官網(wǎng)給出的定義:
?Apache Kafka is a distributed streaming platform.
?
Kafka 作為流平臺具有以下三種能力:
發(fā)布和訂閱記錄流,類似于消息隊列或企業(yè)消息系統(tǒng); 具有容錯能力,且可以持久化的方式存儲記錄流; 當記錄流產(chǎn)生時(發(fā)生時),可及時對其進行處理。
Kafka 適用于兩類應(yīng)用:
建立實時流數(shù)據(jù)管道,在系統(tǒng)或應(yīng)用之間可靠地獲取數(shù)據(jù); 建立對數(shù)據(jù)流進行轉(zhuǎn)換或反應(yīng)的實時流應(yīng)用程序。
kafka 包含四種核心 API。
Producer API:基于該 API,應(yīng)用程序可以將記錄流發(fā)布到一個或多個 Kafka 主題(Topics); Consumer API:基于該 API,應(yīng)用程序可以訂閱一個或多個主題,并處理主題對應(yīng)的記錄流; Streams API:基于該 API,應(yīng)用程序可以充當流處理器,從一個或多個主題消費輸入流,并生成輸出流輸出一個或多個主題,從而有效地將輸入流轉(zhuǎn)換為輸出流; Connector API:允許構(gòu)建和運行將 Kafka 主題連接到現(xiàn)有應(yīng)用程序或數(shù)據(jù)系統(tǒng)的可重用生產(chǎn)者或消費者。例如,關(guān)系數(shù)據(jù)庫的連接器可能會捕獲表的每一個更改。
Kafka 特點
作為一種高吞吐量的分布式發(fā)布訂閱消息系統(tǒng),Kafka 具有如下特性:
快速持久化,可以在 O(1) 的系統(tǒng)開銷下進行消息持久化; 高吞吐,在一臺普通的服務(wù)器上可以達到 10W/s 的吞吐速率; 完全的分布式系統(tǒng),Broker、Producer、Consumer 都原生自動支持分布式,自動實現(xiàn)負載均衡; 支持同步和異步復(fù)制兩種 HA; 支持數(shù)據(jù)批量發(fā)送和拉??; Zero-Copy,減少 IO 操作步驟; 數(shù)據(jù)遷移、擴容對用戶透明; 無需停機即可擴展機器; 其他特性還包括嚴格的消息順序、豐富的消息拉取模型、高效訂閱者水平擴展、實時的消息訂閱、億級的消息堆積能力、定期刪除機制。
Kafka 部署環(huán)境
操作系統(tǒng)
Windows:雖然 Kafka 可以在部分 Windows 系統(tǒng)運行,但官方并不推薦; Unix:支持所有版本的 Unix 系統(tǒng),以及 Linux 和 Solaris系統(tǒng)。
環(huán)境要求
JDK:Kafka 的最新版本為 2.0.0,JDK 版本需 1.8 及以上; ZooKeeper:Kafka 集群依賴 ZooKeeper,需根據(jù) Kafka 的版本選擇安裝對應(yīng)的 ZooKeeper 版本(未來的 Kafka 即將脫離 ZooKeeper)。
Kafka 架構(gòu)

如上圖所示,一個典型的 Kafka 體系架構(gòu)包括若干 Producer(消息生產(chǎn)者),若干 Broker(Kafka 支持水平擴展,一般 Broker 數(shù)量越多,集群吞吐率越高),若干 Consumer(Group),以及一個 Zookeeper 集群。Kafka 通過 Zookeeper 管理集群配置,選舉 Leader,以及在 Consumer Group 發(fā)生變化時進行 Rebalance。Producer 使用 Push(推)模式將消息發(fā)布到 Broker,Consumer 使用 Pull(拉)模式從 Broker 訂閱并消費消息。
各個名詞的解釋請見下表:

Kafka 高可用方案
Kafka 高可用性的保障來源于其健壯的副本(Replication)策略。為了提高吞吐能力,Kafka 中每一個 Topic 分為若干 Partitions;為了保證可用性,每一個 Partition 又設(shè)置若干副本(Replicas);為了保障數(shù)據(jù)的一致性,Zookeeper 機制得以引入?;?Zookeeper,Kafka 為每一個 Partition 找一個節(jié)點作為 Leader,其余備份作為 Follower,只有 Leader 才能處理客戶端請求,而 Follower 僅作為副本同步 Leader 的數(shù)據(jù),如下示意圖:TopicA 分為兩個 Partition,每個 Partition 配置兩個副本。

基于上圖的架構(gòu),當 Producer Push 的消息寫入 Partition(分區(qū)) 時,Leader 所在的 Broker(Kafka 節(jié)點)會將消息寫入自己的分區(qū),同時還會將此消息復(fù)制到各個 Follower,實現(xiàn)同步。如果某個 Follower 掛掉,Leader 會再找一個替代并同步消息;如果 Leader 掛了,將會從 Follower 中選舉出一個新的 Leader 替代,繼續(xù)業(yè)務(wù),這些都是由 ZooKeeper 完成的。
Kafka 優(yōu)缺點
優(yōu)點主要包括以下幾點:
客戶端語言豐富,支持 Java、.NET、PHP、Ruby、Python、Go 等多種語言; 性能卓越,單機寫入 TPS 約在百萬條/秒,消息大小 10 個字節(jié); 提供完全分布式架構(gòu),并有 Replica 機制,擁有較高的可用性和可靠性,理論上支持消息無限堆積; 支持批量操作; 消費者采用 Pull 方式獲取消息,消息有序,通過控制能夠保證所有消息被消費且僅被消費一次; 有優(yōu)秀的第三方 Kafka Web 管理界面 Kafka-Manager; 在日志領(lǐng)域比較成熟,被多家公司和多個開源項目使用。
缺點主要有:
Kafka 單機超過 64 個隊列/分區(qū),Load 會發(fā)生明顯的飆高現(xiàn)象,隊列越多,Load 越高,發(fā)送消息響應(yīng)時間越長; 使用短輪詢方式,實時性取決于輪詢間隔時間; 消費失敗不支持重試; 支持消息順序,但是一臺代理宕機后,就會產(chǎn)生消息亂序; 社區(qū)更新較慢。
ActiveMQ
ActiveMQ 是 Apache 下的一個子項目。之所以把它放在第二位介紹,是因為它官網(wǎng)上的說明:
?Apache ActiveMQ is the most popular and powerful open source messaging and Integration Patterns server.
?
居然沒有“之一”,不太謙虛呀,放在第二位,以示“誡勉”。
ActiveMQ 簡介
ActiveMQ 由 Apache 出品,據(jù)官網(wǎng)介紹,它是最流行和最強大的開源消息總線。ActiveMQ 是一個完全支持 JMS1.1 和 J2EE 1.4 規(guī)范的 JMS Provider 實現(xiàn),非常快速,支持多種語言的客戶端和協(xié)議,而且可以非常容易地嵌入到企業(yè)的應(yīng)用環(huán)境中,并有許多高級功能。
ActiveMQ 基于 Java 語言開發(fā),目前最新版本為 5.1.5.6。
ActiveMQ 特點
ActiveMQ 的特點,官網(wǎng)在 Features 一欄中做了非常詳細的說明,我做了下翻譯,如下:
支持多種語言和協(xié)議編寫客戶端。語言包括 Java、C、C++、C#、Ruby、Perl、Python、PHP。應(yīng)用協(xié)議包括 OpenWire、Stomp REST、WS Notification、XMPP、AMQP; 完全支持 JMS1.1 和 J2EE 1.4 規(guī)范(持久化、XA 消息、事務(wù)); 完全支持 JMS 客戶端和消息代理中的企業(yè)集成模式; 支持許多高級特性,例如消息組、虛擬目的地、通配符和復(fù)合目的地; 支持 Spring,ActiveMQ 可以很容易地嵌入 Spring 應(yīng)用程序中,并使用 Spring 的 XML 配置機制進行配置; 通過了常見 J2EE 服務(wù)器(如 Geronimo、JBoss4、GlassFish、WebLogic)的測試,其中通過 JCA 1.5 Resource Adaptors 的配置,可以讓 ActiveMQ 自動部署到任何兼容 J2EE 1.4 商業(yè)服務(wù)器上; 支持多種傳輸協(xié)議,如 VM、TCP、SSL、NIO、UDP、Multicast、JGroups 以及 JXTA; 支持通過 JDBC 和 Journal 提供高速的消息持久化; 從設(shè)計上保證了高性能的集群,客戶端-服務(wù)器,點對點; REST API 為消息提供技術(shù)無關(guān)和基于語言的 Web API; AJAX 允許使用純 DHTML 實現(xiàn) Web 流對 Web 瀏覽器的支持,允許 Web 瀏覽器成為消息傳遞結(jié)構(gòu)的一部分; 獲得 CXF 和 Axes 的支持,使得 ActiveMQ 可以很容易地嵌入 Web 服務(wù)棧中的任何一個,以提供可靠的消息傳遞; 很容易調(diào)用內(nèi)嵌 JMS Provider,進行測試。
ActiveMQ 部署環(huán)境
相較于 Kafka,ActiveMQ 的部署簡單很多,支持多個版本的 Windows 和 Unix 系統(tǒng),此外,ActiveMQ 由 Java 語言開發(fā)而成,因此需要 JRE 支持。
硬件要求
如果以二進制文件安裝,ActiveMQ 5.x 需要 60M 空間。當然,需要額外的磁盤空間來持久化消息; 如果下載 ActiveMQ 5.x 源文件,自行編譯構(gòu)建, 則需要 300M 空間。
操作系統(tǒng)
Windows:支持 Windows XP SP2、Windows 2000、Windows Vista、Windows 7; Unix:支持 Ubuntu Linux、Powerdog Linux、MacOS、AIX、HP-UX、Solaris,或者其它任何支持 Java 的 Unix 平臺。
環(huán)境要求
Java 運行環(huán)境(JRE),版本 1.7 及以上,如果以源碼自行編譯構(gòu)建,則還需要安裝 JDK; 需要為 JRE 配置環(huán)境變量,通常命名為 JAVA_HOME; 如果以源文件自行編譯構(gòu)建,需安裝 Maven 3.0.0 及以上版本,同時,依賴的 JAR 包需要添加到 classpath 中。
ActiveMQ 架構(gòu)
ActiveMQ 的主體架構(gòu)如下圖所示。

傳輸協(xié)議:消息之間的傳遞,無疑需要協(xié)議進行溝通,啟動一個 ActiveMQ 便打開一個監(jiān)聽端口。ActiveMQ 提供了廣泛的連接模式,主要包括 SSL、STOMP、XMPP。ActiveMQ 默認的使用協(xié)議為 OpenWire,端口號為 61616。
通信方式:ActiveMQ 有兩種通信方式,Point-to-Point Model(點對點模式),Publish/Subscribe Model (發(fā)布/訂閱模式),其中在 Publich/Subscribe 模式下又有持久化訂閱和非持久化訂閱兩種消息處理方式。
消息存儲:在實際應(yīng)用中,重要的消息通常需要持久化到數(shù)據(jù)庫或文件系統(tǒng)中,確保服務(wù)器崩潰時,信息不會丟失。
Cluster(集群):最常見到集群方式包括 Network of Brokers 和 Master Slave。
Monitor(監(jiān)控):ActiveMQ 一般由 JMX 進行監(jiān)控。
默認配置下的 ActiveMQ 只適合學(xué)習(xí)而不適用于實際生產(chǎn)環(huán)境,ActiveMQ 的性能需要通過配置挖掘,其性能提高包括代碼級性能、規(guī)則性能、存儲性能、網(wǎng)絡(luò)性能以及多節(jié)點協(xié)同方法(集群方案),所以我們優(yōu)化 ActiveMQ 的中心思路也是這樣的:
優(yōu)化 ActiveMQ 單個節(jié)點性能,包括 NIO 模型選擇和存儲選擇。 配置 ActiveMQ 集群(ActiveMQ 的高性能和高可用需要通過集群表現(xiàn)出來)。
在生產(chǎn)環(huán)境中,ActiveMQ 集群的部署方式主要有下面兩種。
Master Slave 模式:實現(xiàn)高可用,當主服務(wù)器宕機時,備用服務(wù)器可以升主,以保證服務(wù)的繼續(xù)。 Broker Clusters 模式:實現(xiàn)負載均衡,多個 Broker 之間同步消息,以達到服務(wù)器負載的可能。
ActiveMQ 高可用方案

在生產(chǎn)環(huán)境中,高可用(High Availability,HA)可謂 “剛需”, ActiveMQ 的高可用性架構(gòu)基于 Master/Slave 模型。ActiveMQ 總共提供了四種配置方案來配置 HA,其中 Shared Nothing Master/Slave 在 5.8 版本之后不再使用了,并在 ActiveMQ 5.9 版本中引入了基于 Zookeeper 的 Replicated LevelDB Store HA 方案。
關(guān)于幾種 HA 方案的詳細介紹,讀者可查看官網(wǎng)說明,在此,我僅做簡單介紹。
方案一:Shared Nothing Master/Slave
這是一種最簡單最典型的 Master-Slave 模式,Master 與 Slave 有各自的存儲系統(tǒng),不共享任何數(shù)據(jù)?!癝hared Nothing” 模式有很多局限性,存在丟失消息、“雙主”等問題。目前,在要求嚴格的生產(chǎn)環(huán)境中幾乎沒有應(yīng)用,是一種趨于淘汰的方案,因此,本文就不作介紹了。
方案二:Shared Storage Master/Slave
這是很常用的一種架構(gòu)。“共享存儲”意味著 Master 與 Slave 之間的數(shù)據(jù)是共享的。為了實現(xiàn)數(shù)據(jù)共享,有兩種方式:
Shared Database Master/Slave Shared File system Master/Slave
(1)Shared File System Master/Slaves
這是基于共享文件系統(tǒng)的 Master/Slaves 模式。此處所謂的“共享文件系統(tǒng)”目前只能是基于 POSIX 接口可以訪問的文件系統(tǒng),比如本地文件系統(tǒng)或者 SAN 分布式共享文件系統(tǒng)(如 glusterFS)。對于 Broker 而言,啟動時將會首先獲取存儲引擎的文件鎖,如果獲取成功才能繼續(xù)初始化 transportConnector,否則它將一直嘗試獲取鎖(tryLock),這對于共享文件系統(tǒng)而言,需要嚴格確保任何時候只能有一個進程獲取排他鎖。如果你選擇的 SAN 文件系統(tǒng)不能保證此條件,那么將不能作為 Master/Slavers 的共享存儲引擎。
“Shared File System”這種方式是最常用的模式,架構(gòu)簡單,可靠實用。我們只需要一個 SAN 文件系統(tǒng)即可。
(2)JDBC Store Master/Slaves
顯而易見,數(shù)據(jù)存儲引擎為 Database,ActiveMQ 通過 JDBC 方式與 Database 交互,排他鎖使用 Database 的表級排他鎖。JDBC Store 相對于日志文件而言,通常被認為是低效的,盡管數(shù)據(jù)的可見性較好,但是 Database 的擴容能力非常弱,無法良好地適應(yīng)高并發(fā)、大數(shù)據(jù)情況(嚴格來說,單組 M-S 架構(gòu)是無法支持大數(shù)據(jù)的),況且 ActiveMQ 的消息通常存儲時間較短,頻繁地寫入,頻繁地刪除,都是性能的影響點。我們通常在研究 ActiveMQ 存儲原理時使用 JDBC Store,或者在對數(shù)據(jù)一致性(可靠性、可見性)要求較高的中小型應(yīng)用環(huán)境中使用,比如訂單系統(tǒng)中交易流程支撐系統(tǒng)等。但由于 JDBC 架構(gòu)實施簡便,易于管理,我們?nèi)匀粌A向于首選這種方式。
在使用 JDBC Store 之前,必須有一個穩(wěn)定的 Database,且為 AcitveMQ 中的鏈接用戶授權(quán)“創(chuàng)建表”和普通 CRUD 的權(quán)限。Master 與 Slave 中的配置文件基本一樣,開發(fā)者需要注意 brokerName 和 brokerId 全局不可重復(fù)。此外還需要把相應(yīng)的 jdbc-connector 的 Jar 包復(fù)制到 ${acitvemq}/lib/optional 目錄下。
方案三:Replicated LevelDB Store
基于復(fù)制的 LevelDB Store,是 ActiveMQ 最新的 HA 方案,在 5.9+ 版本中獲得支持。相較于方案二中的兩種“Shared Storage”模式,本方案在存儲和通訊機制上,更符合“Master-Slave”模型。
“Replicated LevelDB”同樣允許有多個 Slaves,而且 Slaves 的個數(shù)有了約束性的限制,這歸結(jié)于其使用 ZooKeeper 選舉 Master。要進行選舉,則需要多數(shù)派的“參與者”。因為 Replicated LevelDB Store 中有多個 Broker,從多個 Broker 中選舉出一個成為 Master,其他的則成為 Slave。只有 Master 接收 Client 的連接,Slave 負責連接到 Master,并接收(同步方式、異步方式)Master 上的數(shù)據(jù)。每個 Broker 實例將消息數(shù)據(jù)保存本地(類似于“Shared Nothing”),它們之間并不共享任何數(shù)據(jù),因此,某種意義上把“Replicated LevelDB”歸類為“Shared Storage”并不妥當。
特別說明:ActiveMQ 官網(wǎng)警告,LevelDB 不再作為推薦的存儲方案,取而代之的是 KahaDB。
ActiveMQ HA 方案之 Network Bridges 模式
在前面我已經(jīng)介紹的幾種 HA 方案,本質(zhì)上都只有一個 Master 節(jié)點,無法滿足高并發(fā)、大吞吐量的商用場景,因此,ActiveMQ 官方推出了 “網(wǎng)橋”架構(gòu)模式,即真正的“分布式消息隊列”。該模式可應(yīng)對大規(guī)模 Clients、高密度的消息增量的場景;它以集群的模式,承載較大數(shù)據(jù)量的應(yīng)用。

如上圖所示,集群由多個子 Groups 構(gòu)成,每個 Group 為 M-S 模式、共享存儲;多個 Groups 之間基于“Network Connector”建立連接(Master-Slave 協(xié)議),通常為雙向連接,所有的 Groups 之間彼此相連,Groups 之間形成“訂閱”關(guān)系,比如 G2 在邏輯上為 G1 的訂閱者(訂閱的策略是根據(jù)各個 Broker 上消費者的 Destination 列表進行分類),消息的轉(zhuǎn)發(fā)原理也基于此。對于 Client 而言,仍然支持 Failover,F(xiàn)ailover 協(xié)議中可以包含集群中“多數(shù)派”的節(jié)點地址。
Topic 訂閱者的消息,將會在所有 Group 中復(fù)制存儲,對于 Queue 的消息,將會在 Brokers 之間轉(zhuǎn)發(fā),并最終到達 Consumer 所在的節(jié)點。
Producers 和 Consumers 可以與任何 Group 中的 Master 建立連接并進行消息通信,當 Brokers 集群拓撲變化時,Producers 或 Consumers 的個數(shù)變化時,將會動態(tài)平衡 Clients 的連接位置。Brokers 之間通過“Advisory”機制來同步 Clients 的連接信息,比如新的 Consumers 加入,Broker 將會發(fā)送 Advisory 消息(內(nèi)部的通道)通知其他 Brokers。
集群模式提供了較好的可用性擔保能力,在某些特性上或許需要權(quán)衡,比如 Queue 消息的有序性將會打破,因為同一個 Queue 的多個 Consumer 可能位于不同的 Group 上,如果某個 Group 實現(xiàn),那么保存在其上的消息只有當其恢復(fù)后才能對 Clients 可見。
“網(wǎng)絡(luò)轉(zhuǎn)發(fā)橋”集群模式,構(gòu)建復(fù)雜,維護成本高,可以在生產(chǎn)環(huán)境中使用。
ActiveMQ 優(yōu)缺點
優(yōu)點主要有以下幾點。
跨平臺(Java 編寫與平臺無關(guān),ActiveMQ 幾乎可以運行在任何 JVM 上); 可以使用 JDBC,將數(shù)據(jù)持久化到數(shù)據(jù)庫。雖然使用 JDBC 會降低 ActiveMQ 的性能, 但數(shù)據(jù)庫一直都是開發(fā)人員最熟悉的存儲介質(zhì)。將消息存到數(shù)據(jù)庫,看得見摸得著。而且公司有專門的 DBA 去對數(shù)據(jù)庫進行調(diào)優(yōu),主從分離; 支持 JMS 的統(tǒng)一接口; 支持自動重連; 有安全機制:支持基于 Shiro、JAAS 等多種安全配置機制,可以對 Queue/Topic 進行認證和授權(quán); 擁有完善的監(jiān)控體系,包括 Web Console、JMX、Shell 命令行,以及 Jolokia 的 REST API; 界面友善:提供的 Web Console 可以滿足大部分需求,此外,還有很多第三方組件可以使用,如 Hawtio。
其缺點主要有以下幾點:
社區(qū)活躍度較低,更新慢,增加維護成本; 網(wǎng)絡(luò)資料顯示,ActiveMQ 存在一些莫名其妙的問題,會丟失消息; 目前,官方將重心放到 ActiveMQ 6.0 下一代產(chǎn)品 Apollo 上,對 5.x 的維護較少; 不適合用于上千個隊列的應(yīng)用場景。
RabbitMQ
RabbitMQ 是由 RabbitMQ Technologies Ltd 開發(fā)并提供技術(shù)支持的開源軟件。該公司在 2010 年 4 月被 SpringSource(VMWare 的一個部門)收購。在 2013 年 5 月被并入 Pivotal。事實上 VMWare、Pivotal 和 EMC 同屬一家,不同的是 VMWare 是獨立上市子公司,而 Pivotal 整合了 EMC 的某些資源,現(xiàn)在并沒有上市。
RabbitMQ 簡介
RabbitMQ 是流行的開源消息隊列系統(tǒng),最新版本為 3.7.8。RabbitMQ 是 AMQP(Advanced Message Queuing Protocol)的標準實現(xiàn)。支持多種客戶端,如 Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP 等,支持 AJAX、持久化。用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息,在易用性、擴展性、高可用性等方面表現(xiàn)不俗。
RabbitMQ 采用 Erlang 語言開發(fā)。Erlang 是一種面向并發(fā)運行環(huán)境的通用編程語言。該語言由愛立信公司在 1986 年開始開發(fā),目的是創(chuàng)造一種可以應(yīng)對大規(guī)模并發(fā)活動的編程語言和運行環(huán)境。Erlang 問世于 1987 年,經(jīng)過十年的發(fā)展,于 1998 年發(fā)布開源版本。
Erlang 是一個結(jié)構(gòu)化、動態(tài)類型編程語言,內(nèi)建并行計算支持。使用 Erlang 編寫出的應(yīng)用運行時通常由成千上萬個輕量級進程組成,并通過消息傳遞相互通訊。進程間上下文切換對于 Erlang 來說僅僅只是一兩個環(huán)節(jié),比起 C 程序的線程切換要高效得多。Erlang 運行時環(huán)境是一個虛擬機,有點像 Java 虛擬機,這樣代碼一經(jīng)編譯,同樣可以隨處運行。它的運行時系統(tǒng)甚至允許代碼在不被中斷的情況下更新。另外字節(jié)代碼也可以編譯成本地代碼運行。
RabbitMQ 特點
根據(jù)官方介紹,RabbitMQ 是部署最廣泛的消息代理,有以下特點:
異步消息傳遞,支持多種消息傳遞協(xié)議、消息隊列、傳遞確認機制,靈活的路由消息到隊列,多種交換類型; 良好的開發(fā)者體驗,可在許多操作系統(tǒng)及云環(huán)境中運行,并為大多數(shù)流行語言提供各種開發(fā)工具; 可插拔身份認證授權(quán),支持 TLS(Transport Layer Security)和 LDAP(Lightweight Directory Access Protocol)。輕量且容易部署到內(nèi)部、私有云或公有云中; 分布式部署,支持集群模式、跨區(qū)域部署,以滿足高可用、高吞吐量應(yīng)用場景; 有專門用于管理和監(jiān)督的 HTTP-API、命令行工具和 UI; 支持連續(xù)集成、操作度量和集成到其他企業(yè)系統(tǒng)的各種工具和插件陣列??梢圆寮绞届`活地擴展 RabbitMQ 的功能。
綜上所述,RabbitMQ 是一個“體系較為完善”的消息代理系統(tǒng),性能好、安全、可靠、分布式,支持多種語言的客戶端,且有專門的運維管理工具。
RabbitMQ 部署環(huán)境
RabbitMQ 支持多個版本的 Windows 和 Unix 系統(tǒng),此外,ActiveMQ 由 Erlang 語言開發(fā)而成,因此需要 Erlang 環(huán)境支持。某種意義上,RabbitMQ 具有在所有支持 Erlang 的平臺上運行的潛力,從嵌入式系統(tǒng)到多核心集群還有基于云端的服務(wù)器。
操作系統(tǒng)
Windows 系列:支持 Windows NT、Windows 2000、Windows XP、Windows Vista、Windows 7、Windows 8,Windows Server 2003/2008/2012、Windows 95、Windows 98; Unix 系列:支持 Ubuntu 和其它基于 Debian 的 Linux 發(fā)行版,F(xiàn)edora 和其它基于 RPM 包管理方式的 Linux 發(fā)行版,openSUSE 和衍生的發(fā)行版,以及 Solaris、BSD、MacOSX 等。
環(huán)境要求
RabbitMQ 采用 Erlang 開發(fā),需要安裝 Erlang 環(huán)境; 不同版本的 JDK 支持的 Erlang 和 RabbitMQ Server 的版本也有所不同,建議采用高版本 JDK,避免兼容性問題。
RabbitMQ 架構(gòu)
根據(jù)官方文檔說明,RabbitMQ 的架構(gòu)圖如下所示:

接下來解釋幾個重要的概念。
Broker:即消息隊列服務(wù)器實體。 Exchange:消息交換機,它指定消息按什么規(guī)則,路由到哪個隊列。 Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列。 Binding:綁定,它的作用是把 Exchange 和 Queue 按照路由規(guī)則綁定起來。 Routing Key:路由關(guān)鍵字,Exchange 根據(jù)這個關(guān)鍵字進行消息投遞。 Vhost:虛擬主機,一個 Broker 里可以開設(shè)多個 Vhost,用作不同用戶的權(quán)限分離。 Producer:消息生產(chǎn)者,就是投遞消息的程序。 Consumer:消息消費者,就是接受消息的程序。 Channel:消息通道,在客戶端的每個連接里,可建立多個 Channel,每個 Channel 代表一個會話任務(wù)。
消息隊列的使用過程如下:
客戶端連接到消息隊列服務(wù)器,打開一個 Channel。 客戶端聲明一個 Exchange,并設(shè)置相關(guān)屬性。 客戶端聲明一個 Queue,并設(shè)置相關(guān)屬性。 客戶端使用 Routing Key,在 Exchange 和 Queue 之間建立好綁定關(guān)系。 客戶端投遞消息到 Exchange。Exchange 接收到消息后,根據(jù)消息的 Key 和已經(jīng)設(shè)置的 Binding,進行消息路由,將消息投遞到一個或多個隊列里。 有三種類型的 Exchange,即 Direct、Fanout、Topic,每個實現(xiàn)了不同的路由算法(Routing Algorithm)。
Direct Exchange:完全根據(jù) Key 投遞。如果 Routing Key 匹配,Message 就會被傳遞到相應(yīng)的 Queue 中。其實在 Queue 創(chuàng)建時,它會自動地以 Queue 的名字作為 Routing Key 來綁定 Exchange。例如,綁定時設(shè)置了 Routing Key 為“abc”,那么客戶端提交的消息,只有設(shè)置了 Key為“abc”的才會投遞到隊列中。
Fanout Exchange:該類型 Exchange 不需要 Key。它采取廣播模式,一個消息進來時,便投遞到與該交換機綁定的所有隊列中。
Topic Exchange:對 Key 進行模式匹配后再投遞。比如符號“#”匹配一個或多個詞,符號“.”正好匹配一個詞。例如“abc.#”匹配“abc.def.ghi”,“abc.”只匹配“abc.def”。
RabbitMQ 高可用方案
就分布式系統(tǒng)而言,實現(xiàn)高可用(High Availability,HA)的策略基本一致,即副本思想,當主節(jié)點宕機之后,作為副本的備節(jié)點迅速“頂上去”繼續(xù)提供服務(wù)。此外,單機的吞吐量是極為有限的,為了提升性能,通常都采用“人海戰(zhàn)術(shù)”,也就是所謂的集群模式。
RabbitMQ 集群配置方式主要包括以下幾種。
Cluster:不支持跨網(wǎng)段,用于同一個網(wǎng)段內(nèi)的局域網(wǎng);可以隨意得動態(tài)增加或者減少;節(jié)點之間需要運行相同版本的 RabbitMQ 和 Erlang。 Federation:應(yīng)用于廣域網(wǎng),允許單臺服務(wù)器上的交換機或隊列接收發(fā)布到另一臺服務(wù)器上的交換機或隊列的消息,可以是單獨機器或集群。Federation 隊列類似于單向點對點連接,消息會在聯(lián)盟隊列之間轉(zhuǎn)發(fā)任意次,直到被消費者接受。通常使用 Federation 來連接 Internet 上的中間服務(wù)器,用作訂閱分發(fā)消息或工作隊列。 Shovel:連接方式與 Federation 的連接方式類似,但它工作在更低層次??梢詰?yīng)用于廣域網(wǎng)。
RabbitMQ 節(jié)點類型有以下幾種。
內(nèi)存節(jié)點:內(nèi)存節(jié)點將隊列、交換機、綁定、用戶、權(quán)限和 Vhost 的所有元數(shù)據(jù)定義存儲在內(nèi)存中,好處是可以更好地加速交換機和隊列聲明等操作。 磁盤節(jié)點:將元數(shù)據(jù)存儲在磁盤中,單節(jié)點系統(tǒng)只允許磁盤類型的節(jié)點,防止重啟 RabbitMQ 時丟失系統(tǒng)的配置信息。
問題說明:RabbitMQ 要求集群中至少有一個磁盤節(jié)點,所有其他節(jié)點可以是內(nèi)存節(jié)點,當節(jié)點加入或者離開集群時,必須要將該變更通知給至少一個磁盤節(jié)點。如果集群中唯一的一個磁盤節(jié)點崩潰的話,集群仍然可以保持運行,但是無法進行操作(增刪改查),直到節(jié)點恢復(fù)。
解決方案:設(shè)置兩個磁盤節(jié)點,至少有一個是可用的,可以保存元數(shù)據(jù)的更改。
Erlang Cookie
Erlang Cookie 是保證不同節(jié)點可以相互通信的密鑰,要保證集群中的不同節(jié)點相互通信必須共享相同的 Erlang Cookie。具體的目錄存放在 /var/lib/rabbitmq/.erlang.cookie。
它的起源要從 rabbitmqctl 命令的工作原理說起。RabbitMQ 底層基于 Erlang 架構(gòu)實現(xiàn),所以 rabbitmqctl 會啟動 Erlang 節(jié)點,并基于 Erlang 節(jié)點使用 Erlang 系統(tǒng)連接 RabbitMQ 節(jié)點,在連接過程中需要正確的 Erlang Cookie 和節(jié)點名稱,Erlang 節(jié)點通過交換 Erlang Cookie 以獲得認證。
鏡像隊列
RabbitMQ 的 Cluster 集群模式一般分為兩種,普通模式和鏡像模式。
普通模式:默認的集群模式,以兩個節(jié)點(Rabbit01、Rabbit02)為例來進行說明。對于 Queue 來說,消息實體只存在于其中一個節(jié)點 Rabbit01(或者 Rabbit02),Rabbit01 和 Rabbit02 兩個節(jié)點僅有相同的元數(shù)據(jù),即隊列的結(jié)構(gòu)。當消息進入 Rabbit01 節(jié)點的 Queue 后,Consumer 從 Rabbit02 節(jié)點消費時,RabbitMQ 會臨時在 Rabbit01、Rabbit02 間進行消息傳輸,把 A 中的消息實體取出并經(jīng)過 B 發(fā)送給 Consumer。所以 Consumer 應(yīng)盡量連接每一個節(jié)點,從中取消息。即對于同一個邏輯隊列,要在多個節(jié)點建立物理 Queue。否則無論 Consumer 連 Rabbit01 或 Rabbit02,出口總在 Rabbit01,會產(chǎn)生瓶頸。當 Rabbit01 節(jié)點故障后,Rabbit02 節(jié)點無法取到 Rabbit01 節(jié)點中還未消費的消息實體。如果做了消息持久化,那么得等 Rabbit01 節(jié)點恢復(fù),然后才可被消費;如果沒有持久化的話,就會產(chǎn)生消息丟失的現(xiàn)象。 鏡像模式:將需要消費的隊列變?yōu)殓R像隊列,存在于多個節(jié)點,這樣就可以實現(xiàn) RabbitMQ 的 HA,消息實體會主動在鏡像節(jié)點之間實現(xiàn)同步,而不是像普通模式那樣,在 Consumer 消費數(shù)據(jù)時臨時讀取。但也存在缺點,集群內(nèi)部的同步通訊會占用大量的網(wǎng)絡(luò)帶寬。
RabbitMQ 優(yōu)缺點
優(yōu)點主要有以下幾點:
由于 Erlang 語言的特性,RabbitMQ 性能較好、高并發(fā); 健壯、穩(wěn)定、易用、跨平臺、支持多種語言客戶端、文檔齊全; 有消息確認機制和持久化機制,可靠性高; 高度可定制的路由; 管理界面較豐富,在互聯(lián)網(wǎng)公司也有較大規(guī)模的應(yīng)用; 社區(qū)活躍度高,更新快。
缺點主要有:
盡管結(jié)合 Erlang 語言本身的并發(fā)優(yōu)勢,性能較好,但是不利于做二次開發(fā)和維護; 實現(xiàn)了代理架構(gòu),意味著消息在發(fā)送到客戶端之前可以在中央節(jié)點上排隊。此特性使得 RabbitMQ 易于使用和部署,但使得其運行速度較慢,因為中央節(jié)點增加了延遲,消息封裝后也比較大; 需要學(xué)習(xí)比較復(fù)雜的接口和協(xié)議,學(xué)習(xí)和維護成本較高。
RocketMQ
RocketMQ 由阿里研發(fā)團隊開發(fā)的分布式隊列,側(cè)重于消息的順序投遞,具有高吞吐量、可靠性等特征。RocketMQ 于 2013 年開源,2016 年捐贈給 Apache 軟件基金會,并于 2017 年 9 月成為 Apache 基金會的頂級項目。
RocketMQ 簡介
RocketMQ 用 Java 語言實現(xiàn),在設(shè)計時參考了 Kafka,并做出了自己的改進,在消息可靠性上比 Kafka 更好,目前最新版本為 4.3.1。RocketMQ 已經(jīng)被業(yè)界多個大型互聯(lián)網(wǎng)公司采用。
在阿里內(nèi)部,RocketMQ 很好地服務(wù)了集團大大小小上千個應(yīng)用,在每年的雙十一當天,更有不可思議的萬億級消息通過 RocketMQ 流轉(zhuǎn)(在 2017 年的雙 11 當天,整個阿里巴巴集團通過 RocketMQ 流轉(zhuǎn)的線上消息達到了萬億級,峰值 TPS 達到 5600 萬),在阿里大中臺策略上發(fā)揮著舉足輕重的作用。
RocketMQ 特點
RcoketMQ 是一款低延遲、高可靠、可伸縮、易于使用的消息中間件。具有以下特性:
支持發(fā)布/訂閱(Pub/Sub)和點對點(P2P)消息模型; 隊列中有著可靠的先進先出(FIFO)和嚴格的順序傳遞; 支持拉(Pull)和推(Push)兩種消息模式; 單一隊列百萬消息的堆積能力; 支持多種消息協(xié)議,如 JMS、MQTT 等; 分布式高可用的部署架構(gòu),滿足至少一次消息傳遞語義; 提供 Docker 鏡像用于隔離測試和云集群部署; 提供配置、指標和監(jiān)控等功能豐富的 Dashboard。
RocketMQ 部署環(huán)境
操作系統(tǒng)
推薦使用 64 位操作系統(tǒng),包括 Linux、Unix 和 Mac OX。
安裝環(huán)境
JDK:RocketMQ 基于 Java 語言開發(fā),需 JDK 支持,版本 64bit JDK 1.8 及以上;Maven:編譯構(gòu)建需要 Maven 支持,版本 3.2.x 及以上。
RocketMQ 架構(gòu)
RocketMQ 是一個具有高性能、高可靠、低延遲、分布式的萬億級容量,且可伸縮的分布式消息和流平臺。它由 Name Servers、Brokers、 Producers 和 Consumers 四個部分組成。其架構(gòu)如下圖所示(取自官網(wǎng))。

NameServer 集群
NameServer 是一個功能齊全的服務(wù)器,其角色類似 Kafka 中的 ZooKeeper,支持 Broker 的動態(tài)注冊與發(fā)現(xiàn)。主要包括兩個功能:
Broker 管理。NameServer 接受 Broker 集群的注冊信息并且保存下來作為路由信息的基本數(shù)據(jù)。然后提供心跳檢測機制,檢查 Broker 是否還存活。 路由信息管理。每個 NameServer 將保存關(guān)于 Broker 集群的整個路由信息和用于客戶端查詢的隊列信息。然后 Producer 和 Conumser 通過 NameServer 就可以知道整個 Broker 集群的路由信息,從而進行消息的投遞和消費。
NameServer 通常也是集群的方式部署,各實例間相互不進行信息通訊。Broker 向每一臺 NameServer 注冊自己的路由信息,所以每一個 NameServer 實例上面都保存一份完整的路由信息。當某個 NameServer 因某種原因下線,Broker 仍然可以向其它 NameServer 同步其路由信息,Produce、Consumer 仍然可以動態(tài)感知 Broker 的路由信息。
Broker 集群
Broker 主要負責消息的存儲、投遞、查詢以及服務(wù)高可用保證。為了實現(xiàn)這些功能 Broker 包含了以下幾個重要子模塊。
Remoting Module:整個 Broker 的實體,負責處理來自 Clients 端的請求; Client Manager:負責管理客戶端(Producer、Consumer)和 Consumer 的 Topic 訂閱信息; Store Service:提供方便簡單的 API 接口處理消息存儲到物理硬盤和查詢功能; HA Service:高可用服務(wù),提供 Master Broker 和 Slave Broker 之間的數(shù)據(jù)同步功能; Index Service:根據(jù)特定的 Message Key 對投遞到 Broker 的消息進行索引服務(wù),以提供消息的快速查詢。
Producer 集群
充當消息生產(chǎn)者的角色,支持分布式集群方式部署。Producers 通過 MQ 的負載均衡模塊選擇相應(yīng)的 Broker 集群隊列進行消息投遞。投遞的過程支持快速失敗并且低延遲。
Consumer 集群
充當消息消費者的角色,支持分布式集群方式部署。支持以 Push、pull 兩種模式對消息進行消費。同時也支持集群方式和廣播形式的消費,它提供實時消息訂閱機制,可以滿足大多數(shù)用戶的需求。
RocketMQ 高可用實現(xiàn)原理
毫無懸念,RocketMQ 實現(xiàn)高可用(HA)的方案仍然是基于最淳樸的“副本思想”,但與 Kafka、Redis、Etcd 采用的副本機制有所不同:RocketMQ 的 Master 和 Slave 沒有 Election 機制,也沒有 Failover 機制。
RocketMQ 不具備選舉功能,在集群模式下,Master、Slave 角色需預(yù)先設(shè)置,是固定的;Master 與 Slave 配對是通過指定相同的 brokerName 參數(shù)來實現(xiàn),Master 的 BrokerId 必須是 0,Slave 的 BrokerId 必須是大于 0 的數(shù)。一個 Master 下面可以掛載多個 Slave,同一個 Master 下的多個 Slave 通過指定不同的 BrokerId 來區(qū)分。當 Master 節(jié)點宕機后,消費者仍然可以從 Slave 消費,從而保證生產(chǎn)者已經(jīng) Push 的消息不丟失;由于該 Master 宕機,生產(chǎn)者將消息 Push 到其它 Master,不影響可用性。RocketMQ 的 Broker 有 4 種部署方式。
單個 Master 模式
除了配置簡單,沒什么優(yōu)點。
它的缺點是不可靠。該機器重啟或宕機,將導(dǎo)致整個服務(wù)不可用,因此,生產(chǎn)環(huán)境幾乎不采用這種方案。
多個 Master 模式
配置簡單,性能最高,是它的優(yōu)點。
它的缺點是:可能會有少量消息丟失(異步刷盤丟失少量消息,同步刷盤不丟失),單臺機器重啟或宕機期間,該機器下未被消費的消息在機器恢復(fù)前不可訂閱,影響消息實時性。
特別說明:當使用多 Master 無 Slave 的集群搭建方式時,Master 的 brokerRole 配置必須為 ASYNC_MASTER。如果配置為 SYNC_MASTER,則 producer 發(fā)送消息時,返回值的 SendStatus 會一直是 SLAVE_NOT_AVAILABLE。
多 Master 多 Slave 模式:異步復(fù)制
其優(yōu)點為:即使磁盤損壞,消息丟失得非常少,消息實時性不會受影響,因為 Master 宕機后,消費者仍然可以從 Slave 消費,此過程對應(yīng)用透明,不需要人工干預(yù),性能同多 Master 模式幾乎一樣。
它的缺點為:Master 宕機或磁盤損壞時會有少量消息丟失。
多 Master 多 Slave 模式:同步雙寫
其優(yōu)點為:數(shù)據(jù)與服務(wù)都無單點,Master 宕機情況下,消息無延遲,服務(wù)可用性與數(shù)據(jù)可用性都非常高。
其缺點為:性能比異步復(fù)制模式稍低,大約低 10% 左右,發(fā)送單個消息的 RT 會稍高,目前主宕機后,備機不能自動切換為主機,后續(xù)會支持自動切換功能。
RocketMQ 優(yōu)缺點
優(yōu)點主要包括以下幾點。
單機支持 1 萬以上持久化隊列; RocketMQ 的所有消息都是持久化的,先寫入系統(tǒng) Page Cache,然后刷盤,可以保證內(nèi)存與磁盤都有一份數(shù)據(jù),訪問時,直接從內(nèi)存讀取; 模型簡單,接口易用(JMS 的接口很多場合并不太實用); 性能非常好,可以大量堆積消息在 Broker 中; 支持多種消費模式,包括集群消費、廣播消費等; 各個環(huán)節(jié)分布式擴展設(shè)計,主從 HA; 社區(qū)較活躍,版本更新較快。
缺點主要有:
支持的客戶端語言不多,目前是 Java、C++ 和 Go,后兩種尚不成熟; 沒有 Web 管理界面,提供了 CLI(命令行界面)管理工具來進行查詢、管理和診斷各種問題; 沒有在 MQ 核心中實現(xiàn) JMS 等接口。
幾種消息隊列的比較
目前,消息隊列相關(guān)的開源軟件非常多,本文僅介紹了生產(chǎn)環(huán)境中最常見的 4 種。這些消息隊列各有所長,沒有哪一種消息隊列具備 “一統(tǒng)江湖”的優(yōu)勢,某種程度上,增加了選型的難度。不像分布式緩存和分布式鎖,Redis、Etcd 具備“絕對”優(yōu)勢,選型無需糾結(jié)。
RocketMQ 官方評價
所謂實踐是檢驗真理的唯一標準,實際應(yīng)用中的表現(xiàn)比文字更具說服力。在 RocketMQ 官方文檔中,關(guān)于 RocketMQ 的研發(fā)背景是這樣說的:在我們的研究中,隨著使用 Queue 和 Topic 的增加,ActiveMQ IO 模塊很快達到了瓶頸。我們試圖通過節(jié)流、斷路器或降級來解決這個問題,但效果不佳。所以我們開始關(guān)注當時流行的消息解決方案 Kafka。不幸的是,Kafka 不能滿足我們的要求,特別是在低延遲和高可靠性方面。
簡而言之,ActiveMQ 和 Kafka 的性能都不能滿足阿里的超大規(guī)模應(yīng)用場景。在此背景下,阿里自研了 RocketMQ,并捐贈給了開源社區(qū),目前有超過 100 家企業(yè)在使用其開源版本。關(guān)于 ActiveMQ、Kafka 以及 RocketMQ 的比較如下所示(取自 RocketMQ 官網(wǎng)文檔):

對比四大消息隊列
消息隊列利用高效可靠的消息傳遞機制進行平臺無關(guān)的數(shù)據(jù)交流,并基于數(shù)據(jù)通信來進行分布式系統(tǒng)的集成。目前業(yè)界有很多的 MQ 產(chǎn)品,例如 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq 等,也有直接使用數(shù)據(jù)庫 Redis 充當消息隊列的案例。而這些消息隊列產(chǎn)品,各有側(cè)重,在實際選型時,需要結(jié)合自身需求及 MQ 產(chǎn)品特征,綜合考慮。
以下是四種消息隊列的差異對比(圖片源地址):

參考文獻
RabbitMQ 主頁: https://www.rabbitmq.com/ActiveMQ 主頁: http://activemq.apache.org/RocketMQ 主頁: https://github.com/alibaba/RocketMQKafka 主頁: http://kafka.apache.org/
