值得收藏!主流訊息中介軟體技術選型對比大梳理!

語言: CN / TW / HK

hello,大家好,我是張張,「架構精進之路」公號作者。

訊息佇列中介軟體是分散式系統中重要的元件,主要解決應用耦合、非同步訊息、流量削峰等問題。它可以實現高效能、高可用、可伸縮和最終一致性架構,是大型分散式系統不可缺少的中介軟體。

訊息佇列在電商系統、訊息通訊、日誌收集等應用中扮演著關鍵作用,以阿里為例,其研發的訊息佇列(RocketMQ)在歷次天貓 “雙十一” 活動中支撐了萬億級的資料洪峰,為大規模交易提供了有力保障。

作為提升應用效能的重要手段,分散式訊息佇列技術在網際網路領域得到了越來越廣泛的關注 。本文將介紹四種常用的分散式訊息佇列開源軟體: KafkaActiveMQRabbitMQ 及  RocketMQ

在分散式訊息佇列的江湖裡,Kafka 憑藉其優秀的效能佔據重要一席。它最初由 LinkedIn 公司開發,Linkedin 於 2010 年貢獻給了 Apache基金會,之後成為頂級開源專案。

Kafka簡介

關於 Kafka,網上有很多介紹,經過不斷地複製、洗稿、演繹後,難免背離原意,因此,我們還是來看一下官網給出的定義:

Apache Kafka is a distributed streaming platform.

Kafka 作為流平臺具有以下三種能力:

  1. 釋出和訂閱記錄流,類似於訊息佇列或企業訊息系統;

  2. 具有容錯能力,且可以持久化的方式儲存記錄流;

  3. 當記錄流產生時(發生時),可及時對其進行處理。

Kafka 適用於兩類應用:

  1. 建立實時流資料管道,在系統或應用之間可靠地獲取資料;

  2. 建立對資料流進行轉換或反應的實時流應用程式。

kafka 包含四種核心 API。

  • Producer API:基於該 API,應用程式可以將記錄流釋出到一個或多個 Kafka 主題(Topics);

  • Consumer API:基於該 API,應用程式可以訂閱一個或多個主題,並處理主題對應的記錄流;

  • Streams API:基於該 API,應用程式可以充當流處理器,從一個或多個主題消費輸入流,並生成輸出流輸出一個或多個主題,從而有效地將輸入流轉換為輸出流;

  • Connector API:允許構建和執行將 Kafka 主題連線到現有應用程式或資料系統的可重用生產者或消費者。例如,關係資料庫的聯結器可能會捕獲表的每一個更改。

Kafka 特點

作為一種高吞吐量的分散式釋出訂閱訊息系統,Kafka 具有如下特性:

  1. 快速持久化,可以在 O(1) 的系統開銷下進行訊息持久化;

  2. 高吞吐,在一臺普通的伺服器上可以達到 10W/s 的吞吐速率;

  3. 完全的分散式系統,Broker、Producer、Consumer 都原生自動支援分散式,自動實現負載均衡;

  4. 支援同步和非同步複製兩種 HA;

  5. 支援資料批量傳送和拉取;

  6. Zero-Copy,減少 IO 操作步驟;

  7. 資料遷移、擴容對使用者透明;

  8. 無需停機即可擴充套件機器;

  9. 其他特性還包括嚴格的訊息順序、豐富的訊息拉取模型、高效訂閱者水平擴充套件、實時的訊息訂閱、億級的訊息堆積能力、定期刪除機制。

Kafka 部署環境

作業系統

  • Windows:雖然 Kafka 可以在部分 Windows 系統執行,但官方並不推薦;

  • Unix:支援所有版本的 Unix 系統,以及 Linux 和 Solaris系統。

環境要求

  • JDK:Kafka 的最新版本為 2.0.0,JDK 版本需 1.8 及以上;

  • ZooKeeper:Kafka 叢集依賴 ZooKeeper,需根據 Kafka 的版本選擇安裝對應的 ZooKeeper 版本(未來的 Kafka 即將脫離 ZooKeeper)。

Kafka 架構

Kafka 架構

如上圖所示,一個典型的 Kafka 體系架構包括若干 Producer(訊息生產者),若干 Broker(Kafka 支援水平擴充套件,一般 Broker 數量越多,叢集吞吐率越高),若干 Consumer(Group),以及一個 Zookeeper 叢集。Kafka 通過 Zookeeper 管理叢集配置,選舉 Leader,以及在 Consumer Group 發生變化時進行 Rebalance。Producer 使用 Push(推)模式將訊息釋出到 Broker,Consumer 使用 Pull(拉)模式從 Broker 訂閱並消費訊息。

各個名詞的解釋請見下表:

Kafka 核心元件

Kafka 高可用方案

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

Kafka 高可用方案

基於上圖的架構,當 Producer Push 的訊息寫入 Partition(分割槽) 時,Leader 所在的 Broker(Kafka 節點)會將訊息寫入自己的分割槽,同時還會將此訊息複製到各個 Follower,實現同步。如果某個 Follower 掛掉,Leader 會再找一個替代並同步訊息;如果 Leader 掛了,將會從 Follower 中選舉出一個新的 Leader 替代,繼續業務,這些都是由 ZooKeeper 完成的。

Kafka 優缺點

優點主要包括以下幾點:

  1. 客戶端語言豐富,支援 Java、.NET、PHP、Ruby、Python、Go 等多種語言;

  2. 效能卓越,單機寫入 TPS 約在百萬條/秒,訊息大小 10 個位元組;

  3. 提供完全分散式架構,並有 Replica 機制,擁有較高的可用性和可靠性,理論上支援訊息無限堆積;

  4. 支援批量操作;

  5. 消費者採用 Pull 方式獲取訊息,訊息有序,通過控制能夠保證所有訊息被消費且僅被消費一次;

  6. 有優秀的第三方 Kafka Web 管理介面 Kafka-Manager;

  7. 在日誌領域比較成熟,被多家公司和多個開源專案使用。

缺點主要有:

  1. Kafka 單機超過 64 個佇列/分割槽,Load 會發生明顯的飆高現象,佇列越多,Load 越高,傳送訊息響應時間越長;

  2. 使用短輪詢方式,實時性取決於輪詢間隔時間;

  3. 消費失敗不支援重試;

  4. 支援訊息順序,但是一臺代理宕機後,就會產生訊息亂序;

  5. 社群更新較慢。

ActiveMQ

ActiveMQ 是 Apache 下的一個子專案。之所以把它放在第二位介紹,是因為它官網上的說明:

Apache ActiveMQ is the most popular and powerful open source messaging and Integration Patterns server.

居然沒有“之一”,不太謙虛呀,放在第二位,以示“誡勉”。

ActiveMQ 簡介

ActiveMQ 由 Apache 出品,據官網介紹,它是最流行和最強大的開源訊息匯流排。ActiveMQ 是一個完全支援 JMS1.1 和 J2EE 1.4 規範的 JMS Provider 實現,非常快速,支援多種語言的客戶端和協議,而且可以非常容易地嵌入到企業的應用環境中,並有許多高階功能。

ActiveMQ 基於 Java 語言開發,目前最新版本為 5.1.5.6。

ActiveMQ 特點

ActiveMQ 的特點,官網在 Features 一欄中做了非常詳細的說明,我做了下翻譯,如下:

  1. 支援多種語言和協議編寫客戶端。語言包括 Java、C、C++、C#、Ruby、Perl、Python、PHP。應用協議包括 OpenWire、Stomp REST、WS Notification、XMPP、AMQP;

  2. 完全支援 JMS1.1 和 J2EE 1.4 規範(持久化、XA 訊息、事務);

  3. 完全支援 JMS 客戶端和訊息代理中的企業整合模式;

  4. 支援許多高階特性,例如訊息組、虛擬目的地、萬用字元和複合目的地;

  5. 支援 Spring,ActiveMQ 可以很容易地嵌入 Spring 應用程式中,並使用 Spring 的 XML 配置機制進行配置;

  6. 通過了常見 J2EE 伺服器(如 Geronimo、JBoss4、GlassFish、WebLogic)的測試,其中通過 JCA 1.5 Resource Adaptors 的配置,可以讓 ActiveMQ 自動部署到任何相容 J2EE 1.4 商業伺服器上;

  7. 支援多種傳輸協議,如 VM、TCP、SSL、NIO、UDP、Multicast、JGroups 以及 JXTA;

  8. 支援通過 JDBC 和 Journal 提供高速的訊息持久化;

  9. 從設計上保證了高效能的叢集,客戶端-伺服器,點對點;

  10. REST API 為訊息提供技術無關和基於語言的 Web API;

  11. AJAX 允許使用純 DHTML 實現 Web 流對 Web 瀏覽器的支援,允許 Web 瀏覽器成為訊息傳遞結構的一部分;

  12. 獲得 CXF 和 Axes 的支援,使得 ActiveMQ 可以很容易地嵌入 Web 服務棧中的任何一個,以提供可靠的訊息傳遞;

  13. 很容易呼叫內嵌 JMS Provider,進行測試。

ActiveMQ 部署環境

相較於 Kafka,ActiveMQ 的部署簡單很多,支援多個版本的 Windows 和 Unix 系統,此外,ActiveMQ 由 Java 語言開發而成,因此需要 JRE 支援。

硬體要求

  • 如果以二進位制檔案安裝,ActiveMQ 5.x 需要 60M 空間。當然,需要額外的磁碟空間來持久化訊息;

  • 如果下載 ActiveMQ 5.x 原始檔,自行編譯構建, 則需要 300M 空間。

作業系統

  • Windows:支援 Windows XP SP2、Windows 2000、Windows Vista、Windows 7;

  • Unix:支援 Ubuntu Linux、Powerdog Linux、MacOS、AIX、HP-UX、Solaris,或者其它任何支援 Java 的 Unix 平臺。

環境要求

  • Java 執行環境(JRE),版本 1.7 及以上,如果以原始碼自行編譯構建,則還需要安裝 JDK;

  • 需要為 JRE 配置環境變數,通常命名為 JAVA_HOME;

  • 如果以原始檔自行編譯構建,需安裝 Maven 3.0.0 及以上版本,同時,依賴的 JAR 包需要新增到 classpath 中。

ActiveMQ 架構

ActiveMQ 的主體架構如下圖所示。

ActiveMQ 架構

傳輸協議 :訊息之間的傳遞,無疑需要協議進行溝通,啟動一個 ActiveMQ 便開啟一個監聽埠。ActiveMQ 提供了廣泛的連線模式,主要包括 SSL、STOMP、XMPP。ActiveMQ 預設的使用協議為 OpenWire,埠號為 61616。

通訊方式 :ActiveMQ 有兩種通訊方式,Point-to-Point Model(點對點模式),Publish/Subscribe Model (釋出/訂閱模式),其中在 Publich/Subscribe 模式下又有持久化訂閱和非持久化訂閱兩種訊息處理方式。

訊息儲存 :在實際應用中,重要的訊息通常需要持久化到資料庫或檔案系統中,確保伺服器崩潰時,資訊不會丟失。

Cluster(叢集) :最常見到叢集方式包括 Network of Brokers 和 Master Slave。

Monitor(監控) :ActiveMQ 一般由 JMX 進行監控。

預設配置下的 ActiveMQ 只適合學習而不適用於實際生產環境,ActiveMQ 的效能需要通過配置挖掘,其效能提高包括程式碼級效能、規則效能、儲存效能、網路效能以及多節點協同方法(叢集方案),所以我們優化 ActiveMQ 的中心思路也是這樣的:

  1. 優化 ActiveMQ 單個節點效能,包括 NIO 模型選擇和儲存選擇。

  2. 配置 ActiveMQ 叢集(ActiveMQ 的高效能和高可用需要通過叢集表現出來)。

在生產環境中,ActiveMQ 叢集的部署方式主要有下面兩種。

  • Master Slave 模式:實現高可用,當主伺服器宕機時,備用伺服器可以升主,以保證服務的繼續。

  • Broker Clusters 模式:實現負載均衡,多個 Broker 之間同步訊息,以達到伺服器負載的可能。

ActiveMQ 高可用方案

官網介紹ActiveMQ有兩種方式來實現Master/Slave,分別是Shared File System Master Slave、JDBC Master Slave。

ActiveMQ 高可用方案

在生產環境中,高可用(High Availability,HA)可謂 “剛需”, ActiveMQ 的高可用性架構基於 Master/Slave 模型。ActiveMQ 總共提供了四種配置方案來配置 HA,其中 Shared Nothing Master/Slave 在 5.8 版本之後不再使用了,並在 ActiveMQ 5.9 版本中引入了基於 Zookeeper 的 Replicated LevelDB Store HA 方案。

關於幾種 HA 方案的詳細介紹,讀者可檢視官網說明,在此,我僅做簡單介紹。

方案一: Shared Nothing Master/Slave

這是一種最簡單最典型的 Master-Slave 模式,Master 與 Slave 有各自的儲存系統,不共享任何資料。“Shared Nothing” 模式有很多侷限性,存在丟失訊息、“雙主”等問題。目前,在要求嚴格的生產環境中幾乎沒有應用,是一種趨於淘汰的方案,因此,本文就不作介紹了。

方案二: Shared Storage Master/Slave

這是很常用的一種架構。“共享儲存”意味著 Master 與 Slave 之間的資料是共享的。為了實現資料共享,有兩種方式:

  1. Shared Database Master/Slave

  2. Shared File system Master/Slave

(1)Shared File System Master/Slaves

這是基於共享檔案系統的 Master/Slaves 模式。此處所謂的“共享檔案系統”目前只能是基於 POSIX 介面可以訪問的檔案系統,比如本地檔案系統或者 SAN 分散式共享檔案系統(如 glusterFS)。對於 Broker 而言,啟動時將會首先獲取儲存引擎的檔案鎖,如果獲取成功才能繼續初始化 transportConnector,否則它將一直嘗試獲取鎖(tryLock),這對於共享檔案系統而言,需要嚴格確保任何時候只能有一個程序獲取排他鎖。如果你選擇的 SAN 檔案系統不能保證此條件,那麼將不能作為 Master/Slavers 的共享儲存引擎。

“Shared File System”這種方式是最常用的模式,架構簡單,可靠實用。我們只需要一個 SAN 檔案系統即可。

(2)JDBC Store Master/Slaves

顯而易見,資料儲存引擎為 Database,ActiveMQ 通過 JDBC 方式與 Database 互動,排他鎖使用 Database 的表級排他鎖。JDBC Store 相對於日誌檔案而言,通常被認為是低效的,儘管資料的可見性較好,但是 Database 的擴容能力非常弱,無法良好地適應高併發、大資料情況(嚴格來說,單組 M-S 架構是無法支援大資料的),況且 ActiveMQ 的訊息通常儲存時間較短,頻繁地寫入,頻繁地刪除,都是效能的影響點。我們通常在研究 ActiveMQ 儲存原理時使用 JDBC Store,或者在對資料一致性(可靠性、可見性)要求較高的中小型應用環境中使用,比如訂單系統中交易流程支撐系統等。但由於 JDBC 架構實施簡便,易於管理,我們仍然傾向於首選這種方式。

在使用 JDBC Store 之前,必須有一個穩定的 Database,且為 AcitveMQ 中的連結使用者授權“建立表”和普通 CRUD 的許可權。Master 與 Slave 中的配置檔案基本一樣,開發者需要注意 brokerName 和 brokerId 全域性不可重複。此外還需要把相應的 jdbc-connector 的 Jar 包複製到 ${acitvemq}/lib/optional 目錄下。

ActiveMQ HA 方案之 Network Bridges 模式

在前面我已經介紹的幾種 HA 方案,本質上都只有一個 Master 節點,無法滿足高併發、大吞吐量的商用場景,因此,ActiveMQ 官方推出了 “網橋”架構模式,即真正的“分散式訊息佇列”。該模式可應對大規模 Clients、高密度的訊息增量的場景;它以叢集的模式,承載較大資料量的應用。

ActiveMQ HA 方案之 Network Bridges 模式

如上圖所示,叢集由多個子 Groups 構成,每個 Group 為 M-S 模式、共享儲存;多個 Groups 之間基於“Network Connector”建立連線(Master-Slave 協議),通常為雙向連線,所有的 Groups 之間彼此相連,Groups 之間形成“訂閱”關係,比如 G2 在邏輯上為 G1 的訂閱者(訂閱的策略是根據各個 Broker 上消費者的 Destination 列表進行分類),訊息的轉發原理也基於此。對於 Client 而言,仍然支援 Failover,Failover 協議中可以包含叢集中“多數派”的節點地址。

Topic 訂閱者的訊息,將會在所有 Group 中複製儲存,對於 Queue 的訊息,將會在 Brokers 之間轉發,並最終到達 Consumer 所在的節點。

Producers 和 Consumers 可以與任何 Group 中的 Master 建立連線並進行訊息通訊,當 Brokers 叢集拓撲變化時,Producers 或 Consumers 的個數變化時,將會動態平衡 Clients 的連線位置。Brokers 之間通過“Advisory”機制來同步 Clients 的連線資訊,比如新的 Consumers 加入,Broker 將會發送 Advisory 訊息(內部的通道)通知其他 Brokers。

叢集模式提供了較好的可用性擔保能力,在某些特性上或許需要權衡,比如 Queue 訊息的有序性將會打破,因為同一個 Queue 的多個 Consumer 可能位於不同的 Group 上,如果某個 Group 實現,那麼儲存在其上的訊息只有當其恢復後才能對 Clients 可見。

“網路轉發橋”叢集模式,構建複雜,維護成本高,可以在生產環境中使用。

ActiveMQ 優缺點

優點主要有以下幾點。

  1. 跨平臺(Java 編寫與平臺無關,ActiveMQ 幾乎可以執行在任何 JVM 上);

  2. 可以使用 JDBC,將資料持久化到資料庫。雖然使用 JDBC 會降低 ActiveMQ 的效能, 但資料庫一直都是開發人員最熟悉的儲存介質。將訊息存到資料庫,看得見摸得著。而且公司有專門的 DBA 去對資料庫進行調優,主從分離;

  3. 支援 JMS 的統一介面;

  4. 支援自動重連;

  5. 有安全機制:支援基於 Shiro、JAAS 等多種安全配置機制,可以對 Queue/Topic 進行認證和授權;

  6. 擁有完善的監控體系,包括 Web Console、JMX、Shell 命令列,以及 Jolokia 的 REST API;

  7. 介面友善:提供的 Web Console 可以滿足大部分需求,此外,還有很多第三方元件可以使用,如 Hawtio。

其缺點主要有以下幾點:

  1. 社群活躍度較低,更新慢,增加維護成本;

  2. 網路資料顯示,ActiveMQ 存在一些莫名其妙的問題,會丟失訊息;

  3. 目前,官方將重心放到 ActiveMQ 6.0 下一代產品 Apollo 上,對 5.x 的維護較少;

  4. 不適合用於上千個佇列的應用場景。

RabbitMQ

RabbitMQ 是由 RabbitMQ Technologies Ltd 開發並提供技術支援的開源軟體。該公司在 2010 年 4 月被 SpringSource(VMWare 的一個部門)收購。在 2013 年 5 月被併入 Pivotal。事實上 VMWare、Pivotal 和 EMC 同屬一家,不同的是 VMWare 是獨立上市子公司,而 Pivotal 整合了 EMC 的某些資源,現在並沒有上市。

RabbitMQ 簡介

RabbitMQ 是流行的開源訊息佇列系統,最新版本為 3.7.8。RabbitMQ 是 AMQP(Advanced Message Queuing Protocol)的標準實現。支援多種客戶端,如 Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP 等,支援 AJAX、持久化。用於在分散式系統中儲存轉發訊息,在易用性、擴充套件性、高可用性等方面表現不俗。

RabbitMQ 採用 Erlang 語言開發。Erlang 是一種面向併發執行環境的通用程式語言。該語言由愛立信公司在 1986 年開始開發,目的是創造一種可以應對大規模併發活動的程式語言和執行環境。Erlang 問世於 1987 年,經過十年的發展,於 1998 年釋出開源版本。

Erlang 是一個結構化、動態型別程式語言,內建平行計算支援。使用 Erlang 編寫出的應用執行時通常由成千上萬個輕量級程序組成,並通過訊息傳遞相互通訊。程序間上下文切換對於 Erlang 來說僅僅只是一兩個環節,比起 C 程式的執行緒切換要高效得多。Erlang 執行時環境是一個虛擬機器,有點像 Java 虛擬機器,這樣程式碼一經編譯,同樣可以隨處執行。它的執行時系統甚至允許程式碼在不被中斷的情況下更新。另外位元組程式碼也可以編譯成原生代碼執行。

RabbitMQ 特點

根據官方介紹,RabbitMQ 是部署最廣泛的訊息代理,有以下特點:

  • 非同步訊息傳遞,支援多種訊息傳遞協議、訊息佇列、傳遞確認機制,靈活的路由訊息到佇列,多種交換型別;

  • 良好的開發者體驗,可在許多作業系統及雲環境中執行,併為大多數流行語言提供各種開發工具;

  • 可插拔身份認證授權,支援 TLS(Transport Layer Security)和 LDAP(Lightweight Directory Access Protocol)。輕量且容易部署到內部、私有云或公有云中;

  • 分散式部署,支援叢集模式、跨區域部署,以滿足高可用、高吞吐量應用場景;

  • 有專門用於管理和監督的 HTTP-API、命令列工具和 UI;

  • 支援連續整合、操作度量和整合到其他企業系統的各種工具和外掛陣列。可以外掛方式靈活地擴充套件 RabbitMQ 的功能。

綜上所述,RabbitMQ 是一個“體系較為完善”的訊息代理系統,效能好、安全、可靠、分散式,支援多種語言的客戶端,且有專門的運維管理工具。

RabbitMQ 部署環境

RabbitMQ 支援多個版本的 Windows 和 Unix 系統,此外,ActiveMQ 由 Erlang 語言開發而成,因此需要 Erlang 環境支援。某種意義上,RabbitMQ 具有在所有支援 Erlang 的平臺上執行的潛力,從嵌入式系統到多核心叢集還有基於雲端的伺服器。

作業系統

  • 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 發行版,Fedora 和其它基於 RPM 包管理方式的 Linux 發行版,openSUSE 和衍生的發行版,以及 Solaris、BSD、MacOSX 等。

環境要求

  • RabbitMQ 採用 Erlang 開發,需要安裝 Erlang 環境;

  • 不同版本的 JDK 支援的 Erlang 和 RabbitMQ Server 的版本也有所不同,建議採用高版本 JDK,避免相容性問題。

RabbitMQ 架構

根據官方文件說明,RabbitMQ 的架構圖如下所示:

RabbitMQ 架構

接下來解釋幾個重要的概念。

  • Broker:即訊息佇列伺服器實體。

  • Exchange:訊息交換機,它指定訊息按什麼規則,路由到哪個佇列。

  • Queue:訊息佇列載體,每個訊息都會被投入到一個或多個佇列。

  • Binding:繫結,它的作用是把 Exchange 和 Queue 按照路由規則繫結起來。

  • Routing Key:路由關鍵字,Exchange 根據這個關鍵字進行訊息投遞。

  • Vhost:虛擬主機,一個 Broker 裡可以開設多個 Vhost,用作不同使用者的許可權分離。

  • Producer:訊息生產者,就是投遞訊息的程式。

  • Consumer:訊息消費者,就是接受訊息的程式。

  • Channel:訊息通道,在客戶端的每個連線裡,可建立多個 Channel,每個 Channel 代表一個會話任務。

訊息佇列的使用過程如下:

  1. 客戶端連線到訊息佇列伺服器,開啟一個 Channel。

  2. 客戶端宣告一個 Exchange,並設定相關屬性。

  3. 客戶端宣告一個 Queue,並設定相關屬性。

  4. 客戶端使用 Routing Key,在 Exchange 和 Queue 之間建立好繫結關係。

  5. 客戶端投遞訊息到 Exchange。Exchange 接收到訊息後,根據訊息的 Key 和已經設定的 Binding,進行訊息路由,將訊息投遞到一個或多個佇列裡。

  6. 有三種類型的 Exchange,即 Direct、Fanout、Topic,每個實現了不同的路由演算法(Routing Algorithm)。

Direct Exchange :完全根據 Key 投遞。如果 Routing Key 匹配,Message 就會被傳遞到相應的 Queue 中。其實在 Queue 建立時,它會自動地以 Queue 的名字作為 Routing Key 來繫結 Exchange。例如,繫結時設定了 Routing Key 為“abc”,那麼客戶端提交的訊息,只有設定了 Key為“abc”的才會投遞到佇列中。

Fanout Exchange :該型別 Exchange 不需要 Key。它採取廣播模式,一個訊息進來時,便投遞到與該交換機繫結的所有佇列中。

Topic Exchange :對 Key 進行模式匹配後再投遞。比如符號“#”匹配一個或多個詞,符號“.”正好匹配一個詞。例如“abc.#”匹配“abc.def.ghi”,“abc.”只匹配“abc.def”。

RabbitMQ 高可用方案

就分散式系統而言,實現高可用(High Availability,HA)的策略基本一致,即副本思想,當主節點宕機之後,作為副本的備節點迅速“頂上去”繼續提供服務。此外,單機的吞吐量是極為有限的,為了提升效能,通常都採用“人海戰術”,也就是所謂的叢集模式。

RabbitMQ 叢集配置方式主要包括以下幾種。

  • Cluster:不支援跨網段,用於同一個網段內的區域網;可以隨意的動態增加或者減少;節點之間需要執行相同版本的 RabbitMQ 和 Erlang。

  • Federation:應用於廣域網,允許單臺伺服器上的交換機或佇列接收發布到另一臺伺服器上的交換機或佇列的訊息,可以是單獨機器或叢集。Federation 佇列類似於單向點對點連線,訊息會在聯盟佇列之間轉發任意次,直到被消費者接受。通常使用 Federation 來連線 Internet 上的中間伺服器,用作訂閱分發訊息或工作佇列。

  • Shovel:連線方式與 Federation 的連線方式類似,但它工作在更低層次。可以應用於廣域網。

RabbitMQ 節點型別有以下幾種。

  • 記憶體節點:記憶體節點將佇列、交換機、繫結、使用者、許可權和 Vhost 的所有元資料定義儲存在記憶體中,好處是可以更好地加速交換機和佇列宣告等操作。

  • 磁碟節點:將元資料儲存在磁碟中,單節點系統只允許磁碟型別的節點,防止重啟 RabbitMQ 時丟失系統的配置資訊。

問題說明 :RabbitMQ 要求叢集中至少有一個磁碟節點,所有其他節點可以是記憶體節點,當節點加入或者離開叢集時,必須要將該變更通知給至少一個磁碟節點。如果叢集中唯一的一個磁碟節點崩潰的話,叢集仍然可以保持執行,但是無法進行操作(增刪改查),直到節點恢復。

解決方案 :設定兩個磁碟節點,至少有一個是可用的,可以儲存元資料的更改。

Erlang Cookie

Erlang Cookie 是保證不同節點可以相互通訊的金鑰,要保證叢集中的不同節點相互通訊必須共享相同的 Erlang Cookie。具體的目錄存放在 /var/lib/rabbitmq/.erlang.cookie。

它的起源要從 rabbitmqctl 命令的工作原理說起。RabbitMQ 底層基於 Erlang 架構實現,所以 rabbitmqctl 會啟動 Erlang 節點,並基於 Erlang 節點使用 Erlang 系統連線 RabbitMQ 節點,在連線過程中需要正確的 Erlang Cookie 和節點名稱,Erlang 節點通過交換 Erlang Cookie 以獲得認證。

映象佇列

RabbitMQ 的 Cluster 叢集模式一般分為兩種,普通模式和映象模式。

  • 普通模式:預設的叢集模式,以兩個節點(Rabbit01、Rabbit02)為例來進行說明。對於 Queue 來說,訊息實體只存在於其中一個節點 Rabbit01(或者 Rabbit02),Rabbit01 和 Rabbit02 兩個節點僅有相同的元資料,即佇列的結構。當訊息進入 Rabbit01 節點的 Queue 後,Consumer 從 Rabbit02 節點消費時,RabbitMQ 會臨時在 Rabbit01、Rabbit02 間進行訊息傳輸,把 A 中的訊息實體取出並經過 B 傳送給 Consumer。所以 Consumer 應儘量連線每一個節點,從中取訊息。即對於同一個邏輯佇列,要在多個節點建立物理 Queue。否則無論 Consumer 連 Rabbit01 或 Rabbit02,出口總在 Rabbit01,會產生瓶頸。當 Rabbit01 節點故障後,Rabbit02 節點無法取到 Rabbit01 節點中還未消費的訊息實體。如果做了訊息持久化,那麼得等 Rabbit01 節點恢復,然後才可被消費;如果沒有持久化的話,就會產生訊息丟失的現象。

  • 映象模式:將需要消費的佇列變為映象佇列,存在於多個節點,這樣就可以實現 RabbitMQ 的 HA,訊息實體會主動在映象節點之間實現同步,而不是像普通模式那樣,在 Consumer 消費資料時臨時讀取。但也存在缺點,叢集內部的同步通訊會佔用大量的網路頻寬。

RabbitMQ 優缺點

優點主要有以下幾點:

  • 由於 Erlang 語言的特性,RabbitMQ 效能較好、高併發;

  • 健壯、穩定、易用、跨平臺、支援多種語言客戶端、文件齊全;

  • 有訊息確認機制和持久化機制,可靠性高;

  • 高度可定製的路由;

  • 管理介面較豐富,在網際網路公司也有較大規模的應用;

  • 社群活躍度高,更新快。

缺點主要有:

  1. 儘管結合 Erlang 語言本身的併發優勢,效能較好,但是不利於做二次開發和維護;

  2. 實現了代理架構,意味著訊息在傳送到客戶端之前可以在中央節點上排隊。此特性使得 RabbitMQ 易於使用和部署,但使得其執行速度較慢,因為中央節點增加了延遲,訊息封裝後也比較大;

  3. 需要學習比較複雜的介面和協議,學習和維護成本較高。

RocketMQ

RocketMQ 由阿里研發團隊開發的分散式佇列,側重於訊息的順序投遞,具有高吞吐量、可靠性等特徵。RocketMQ 於 2013 年開源,2016 年捐贈給 Apache 軟體基金會,並於 2017 年 9 月成為 Apache 基金會的頂級專案。

RocketMQ 簡介

RocketMQ 用 Java 語言實現,在設計時參考了 Kafka,並做出了自己的改進,在訊息可靠性上比 Kafka 更好,目前最新版本為 4.3.1。RocketMQ 已經被業界多個大型網際網路公司採用。

在阿里內部,RocketMQ 很好地服務了集團大大小小上千個應用,在每年的雙十一當天,更有不可思議的萬億級訊息通過 RocketMQ 流轉(在 2017 年的雙 11 當天,整個阿里巴巴集團通過 RocketMQ 流轉的線上訊息達到了萬億級,峰值 TPS 達到 5600 萬),在阿里大中臺策略上發揮著舉足輕重的作用。

RocketMQ 特點

RcoketMQ 是一款低延遲、高可靠、可伸縮、易於使用的訊息中介軟體。具有以下特性:

  1. 支援釋出/訂閱(Pub/Sub)和點對點(P2P)訊息模型;

  2. 佇列中有著可靠的先進先出(FIFO)和嚴格的順序傳遞;

  3. 支援拉(Pull)和推(Push)兩種訊息模式;

  4. 單一佇列百萬訊息的堆積能力;

  5. 支援多種訊息協議,如 JMS、MQTT 等;

  6. 分散式高可用的部署架構,滿足至少一次訊息傳遞語義;

  7. 提供 Docker 映象用於隔離測試和雲集群部署;

  8. 提供配置、指標和監控等功能豐富的 Dashboard。

RocketMQ 部署環境

作業系統

推薦使用 64 位作業系統,包括 Linux、Unix 和 Mac OX。

安裝環境

JDK:RocketMQ 基於 Java 語言開發,需 JDK 支援,版本 64bit JDK 1.8 及以上;Maven:編譯構建需要 Maven 支援,版本 3.2.x 及以上。

RocketMQ 架構

RocketMQ 是一個具有高效能、高可靠、低延遲、分散式的萬億級容量,且可伸縮的分散式訊息和流平臺。它由 Name Servers、Brokers、 Producers 和 Consumers 四個部分組成。其架構如下圖所示(取自官網)。

RocketMQ 架構

NameServer 叢集

NameServer 是一個功能齊全的伺服器,其角色類似 Kafka 中的 ZooKeeper,支援 Broker 的動態註冊與發現。主要包括兩個功能:

  • Broker 管理。NameServer 接受 Broker 叢集的註冊資訊並且儲存下來作為路由資訊的基本資料。然後提供心跳檢測機制,檢查 Broker 是否還存活。

  • 路由資訊管理。每個 NameServer 將儲存關於 Broker 叢集的整個路由資訊和用於客戶端查詢的佇列資訊。然後 Producer 和 Conumser 通過 NameServer 就可以知道整個 Broker 叢集的路由資訊,從而進行訊息的投遞和消費。

NameServer 通常也是叢集的方式部署,各例項間相互不進行資訊通訊。Broker 向每一臺 NameServer 註冊自己的路由資訊,所以每一個 NameServer 例項上面都儲存一份完整的路由資訊。當某個 NameServer 因某種原因下線,Broker 仍然可以向其它 NameServer 同步其路由資訊,Produce、Consumer 仍然可以動態感知 Broker 的路由資訊。

Broker 叢集

Broker 主要負責訊息的儲存、投遞、查詢以及服務高可用保證。為了實現這些功能 Broker 包含了以下幾個重要子模組。

  • Remoting Module:整個 Broker 的實體,負責處理來自 Clients 端的請求;

  • Client Manager:負責管理客戶端(Producer、Consumer)和 Consumer 的 Topic 訂閱資訊;

  • Store Service:提供方便簡單的 API 介面處理訊息儲存到物理硬碟和查詢功能;

  • HA Service:高可用服務,提供 Master Broker 和 Slave Broker 之間的資料同步功能;

  • Index Service:根據特定的 Message Key 對投遞到 Broker 的訊息進行索引服務,以提供訊息的快速查詢。

Producer 叢集

充當訊息生產者的角色,支援分散式叢集方式部署。Producers 通過 MQ 的負載均衡模組選擇相應的 Broker 叢集佇列進行訊息投遞。投遞的過程支援快速失敗並且低延遲。

Consumer 叢集

充當訊息消費者的角色,支援分散式叢集方式部署。支援以 Push、pull 兩種模式對訊息進行消費。同時也支援叢集方式和廣播形式的消費,它提供實時訊息訂閱機制,可以滿足大多數使用者的需求。

RocketMQ 高可用實現原理

毫無懸念,RocketMQ 實現高可用(HA)的方案仍然是基於最淳樸的“副本思想”,但與 Kafka、Redis、Etcd 採用的副本機制有所不同:RocketMQ 的 Master 和 Slave 沒有 Election 機制,也沒有 Failover 機制。

RocketMQ 不具備選舉功能,在叢集模式下,Master、Slave 角色需預先設定,是固定的;Master 與 Slave 配對是通過指定相同的 brokerName 引數來實現,Master 的 BrokerId 必須是 0,Slave 的 BrokerId 必須是大於 0 的數。一個 Master 下面可以掛載多個 Slave,同一個 Master 下的多個 Slave 通過指定不同的 BrokerId 來區分。當 Master 節點宕機後,消費者仍然可以從 Slave 消費,從而保證生產者已經 Push 的訊息不丟失;由於該 Master 宕機,生產者將訊息 Push 到其它 Master,不影響可用性。RocketMQ 的 Broker 有 4 種部署方式。

  1. 單個 Master 模式

除了配置簡單,沒什麼優點。

它的缺點是不可靠。該機器重啟或宕機,將導致整個服務不可用,因此,生產環境幾乎不採用這種方案。

  1. 多個 Master 模式

配置簡單,效能最高,是它的優點。

它的缺點是:可能會有少量訊息丟失(非同步刷盤丟失少量訊息,同步刷盤不丟失),單臺機器重啟或宕機期間,該機器下未被消費的訊息在機器恢復前不可訂閱,影響訊息實時性。

特別說明:當使用多 Master 無 Slave 的叢集搭建方式時,Master 的 brokerRole 配置必須為 ASYNC_MASTER。如果配置為 SYNC_MASTER,則 producer 傳送訊息時,返回值的 SendStatus 會一直是 SLAVE_NOT_AVAILABLE。

  1. 多 Master 多 Slave 模式:非同步複製

其優點為:即使磁碟損壞,訊息丟失得非常少,訊息實時性不會受影響,因為 Master 宕機後,消費者仍然可以從 Slave 消費,此過程對應用透明,不需要人工干預,效能同多 Master 模式幾乎一樣。

它的缺點為: Master 宕機或磁碟損壞時會有少量訊息丟失

  1. 多 Master 多 Slave 模式:同步雙寫

其優點為:資料與服務都無單點,Master 宕機情況下,訊息無延遲,服務可用性與資料可用性都非常高。

其缺點為:效能比非同步複製模式稍低,大約低 10% 左右,傳送單個訊息的 RT 會稍高,目前主宕機後,備機不能自動切換為主機,後續會支援自動切換功能。

RocketMQ 優缺點

優點主要包括以下幾點。

  1. 單機支援 1 萬以上持久化佇列;

  2. RocketMQ 的所有訊息都是持久化的,先寫入系統 Page Cache,然後刷盤,可以保證記憶體與磁碟都有一份資料,訪問時,直接從記憶體讀取;

  3. 模型簡單,介面易用(JMS 的介面很多場合並不太實用);

  4. 效能非常好,可以大量堆積訊息在 Broker 中;

  5. 支援多種消費模式,包括叢集消費、廣播消費等;

  6. 各個環節分散式擴充套件設計,主從 HA;

  7. 社群較活躍,版本更新較快。

缺點主要有:

  1. 支援的客戶端語言不多,目前是 Java、C++ 和 Go,後兩種尚不成熟;

  2. 沒有 Web 管理介面,提供了 CLI(命令列介面)管理工具來進行查詢、管理和診斷各種問題;

  3. 沒有在 MQ 核心中實現 JMS 等介面。

幾種訊息佇列的比較

目前,訊息佇列相關的開源軟體非常多,本文僅介紹了生產環境中最常見的 4 種。這些訊息佇列各有所長,沒有哪一種訊息佇列具備 “一統江湖”的優勢,某種程度上,增加了選型的難度。不像分散式快取和分散式鎖,Redis、Etcd 具備“絕對”優勢,選型無需糾結。

RocketMQ 官方評價

所謂實踐是檢驗真理的唯一標準,實際應用中的表現比文字更具說服力。在 RocketMQ 官方文件中,關於 RocketMQ 的研發背景是這樣說的:在我們的研究中,隨著使用 Queue 和 Topic 的增加,ActiveMQ IO 模組很快達到了瓶頸。我們試圖通過節流、斷路器或降級來解決這個問題,但效果不佳。所以我們開始關注當時流行的訊息解決方案 Kafka。不幸的是,Kafka 不能滿足我們的要求,特別是在低延遲和高可靠性方面。

簡而言之,ActiveMQ 和 Kafka 的效能都不能滿足阿里的超大規模應用場景。在此背景下,阿里自研了 RocketMQ,並捐贈給了開源社群,目前有超過 100 家企業在使用其開源版本。關於 ActiveMQ、Kafka 以及 RocketMQ 的比較如下所示(取自 RocketMQ 官網文件):

ActiveMQ、Kafka 以及 RocketMQ 的比較

對比四大訊息佇列

訊息佇列利用高效可靠的訊息傳遞機制進行平臺無關的資料交流,並基於資料通訊來進行分散式系統的整合。目前業界有很多的 MQ 產品,例如 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq 等,也有直接使用資料庫 Redis 充當訊息佇列的案例。而這些訊息佇列產品,各有側重,在實際選型時,需要結合自身需求及 MQ 產品特徵,綜合考慮。

以下是四種訊息佇列的差異對比(圖片源地址):

RabbitMQ/ActiveMQ/RocketMQ/Kafka對比

參考文獻

  • RabbitMQ 主頁: https://www.rabbitmq.com/
  • ActiveMQ 主頁: http://activemq.apache.org/
  • RocketMQ 主頁: https://github.com/alibaba/RocketMQ
  • Kafka 主頁: http://kafka.apache.org/

希望今天的講解對大家有所幫助,謝謝!

Thanks for reading!

關注公眾號,免費領學習資料

如果您覺得還不錯,歡迎關注和轉發~