點選上方藍色“架構師修煉”,選擇“設為星标”
消息隊列中間件是分布式系統中重要的元件,主要解決應用耦合、異步消息、流量削鋒等問題。它可以實作高性能、高可用、可伸縮和最終一緻性架構,是大型分布式系統不可缺少的中間件。
消息隊列在電商系統、消息通訊、日志收集等應用中扮演着關鍵作用,以阿裡為例,其研發的消息隊列(RocketMQ)在曆次天貓 “雙十一” 活動中支撐了萬億級的資料洪峰,為大規模交易提供了有力保障。
作為提升應用性能的重要手段,分布式消息隊列技術在網際網路領域得到了越來越廣泛的關注 。本文将介紹四種常用的分布式消息隊列開源軟體:
Kafka
、
ActiveMQ
、
RabbitMQ
及
RocketMQ
。
Kafka
在分布式消息隊列的江湖裡,Kafka 憑借其優秀的性能占據重要一席。它最初由 LinkedIn 公司開發,Linkedin 于 2010 年貢獻給了 Apache基金會,之後成為頂級開源項目。
Kafka簡介
關于 Kafka,網上有很多介紹,經過不斷地複制、洗稿、演繹後,難免背離原意,是以,我們還是來看一下官網給出的定義:
❝Apache Kafka is a distributed streaming platform.
❞
Kafka 作為流平台具有以下三種能力:
- 釋出和訂閱記錄流,類似于消息隊列或企業消息系統;
- 具有容錯能力,且可以持久化的方式存儲記錄流;
- 當記錄流産生時(發生時),可及時對其進行處理。
Kafka 适用于兩類應用:
- 建立實時流資料管道,在系統或應用之間可靠地擷取資料;
- 建立對資料流進行轉換或反應的實時流應用程式。
kafka 包含四種核心 API。
- Producer API:基于該 API,應用程式可以将記錄流釋出到一個或多個 Kafka 主題(Topics);
- Consumer API:基于該 API,應用程式可以訂閱一個或多個主題,并處理主題對應的記錄流;
- Streams API:基于該 API,應用程式可以充當流處理器,從一個或多個主題消費輸入流,并生成輸出流輸出一個或多個主題,進而有效地将輸入流轉換為輸出流;
- Connector API:允許建構和運作将 Kafka 主題連接配接到現有應用程式或資料系統的可重用生産者或消費者。例如,關系資料庫的連接配接器可能會捕獲表的每一個更改。
Kafka 特點
作為一種高吞吐量的分布式釋出訂閱消息系統,Kafka 具有如下特性:
- 快速持久化,可以在 O(1) 的系統開銷下進行消息持久化;
- 高吞吐,在一台普通的伺服器上可以達到 10W/s 的吞吐速率;
- 完全的分布式系統,Broker、Producer、Consumer 都原生自動支援分布式,自動實作負載均衡;
- 支援同步和異步複制兩種 HA;
- 支援資料批量發送和拉取;
- Zero-Copy,減少 IO 操作步驟;
- 資料遷移、擴容對使用者透明;
- 無需停機即可擴充機器;
- 其他特性還包括嚴格的消息順序、豐富的消息拉取模型、高效訂閱者水準擴充、實時的消息訂閱、億級的消息堆積能力、定期删除機制。
Kafka 部署環境
作業系統
- Windows:雖然 Kafka 可以在部分 Windows 系統運作,但官方并不推薦;
- Unix:支援所有版本的 Unix 系統,以及 Linux 和 Solaris系統。
環境要求
- JDK:Kafka 的最新版本為 2.0.0,JDK 版本需 1.8 及以上;
- ZooKeeper:Kafka 叢集依賴 ZooKeeper,需根據 Kafka 的版本選擇安裝對應的 ZooKeeper 版本(未來的 Kafka 即将脫離 ZooKeeper)。
Kafka 架構
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcuUTNzIWM1YmNxM2MwEDZjZmMmZGOhR2Y2MjY0YWN5YmNvw1MwEDM3UzNtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
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 優缺點
優點主要包括以下幾點:
- 用戶端語言豐富,支援 Java、.NET、PHP、Ruby、Python、Go 等多種語言;
- 性能卓越,單機寫入 TPS 約在百萬條/秒,消息大小 10 個位元組;
- 提供完全分布式架構,并有 Replica 機制,擁有較高的可用性和可靠性,理論上支援消息無限堆積;
- 支援批量操作;
- 消費者采用 Pull 方式擷取消息,消息有序,通過控制能夠保證所有消息被消費且僅被消費一次;
- 有優秀的第三方 Kafka Web 管理界面 Kafka-Manager;
- 在日志領域比較成熟,被多家公司和多個開源項目使用。
缺點主要有:
- Kafka 單機超過 64 個隊列/分區,Load 會發生明顯的飙高現象,隊列越多,Load 越高,發送消息響應時間越長;
- 使用短輪詢方式,實時性取決于輪詢間隔時間;
- 消費失敗不支援重試;
- 支援消息順序,但是一台代理當機後,就會産生消息亂序;
- 社群更新較慢。
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 一欄中做了非常詳細的說明,我做了下翻譯,如下:
- 支援多種語言和協定編寫用戶端。語言包括 Java、C、C++、C#、Ruby、Perl、Python、PHP。應用協定包括 OpenWire、Stomp REST、WS Notification、XMPP、AMQP;
- 完全支援 JMS1.1 和 J2EE 1.4 規範(持久化、XA 消息、事務);
- 完全支援 JMS 用戶端和消息代理中的企業內建模式;
- 支援許多進階特性,例如消息組、虛拟目的地、通配符和複合目的地;
- 支援 Spring,ActiveMQ 可以很容易地嵌入 Spring 應用程式中,并使用 Spring 的 XML 配置機制進行配置;
- 通過了常見 J2EE 伺服器(如 Geronimo、JBoss4、GlassFish、WebLogic)的測試,其中通過 JCA 1.5 Resource Adaptors 的配置,可以讓 ActiveMQ 自動部署到任何相容 J2EE 1.4 商業伺服器上;
- 支援多種傳輸協定,如 VM、TCP、SSL、NIO、UDP、Multicast、JGroups 以及 JXTA;
- 支援通過 JDBC 和 Journal 提供高速的消息持久化;
- 從設計上保證了高性能的叢集,用戶端-伺服器,點對點;
- REST API 為消息提供技術無關和基于語言的 Web API;
- AJAX 允許使用純 DHTML 實作 Web 流對 Web 浏覽器的支援,允許 Web 浏覽器成為消息傳遞結構的一部分;
- 獲得 CXF 和 Axes 的支援,使得 ActiveMQ 可以很容易地嵌入 Web 服務棧中的任何一個,以提供可靠的消息傳遞;
- 很容易調用内嵌 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 的中心思路也是這樣的:
- 優化 ActiveMQ 單個節點性能,包括 NIO 模型選擇和存儲選擇。
- 配置 ActiveMQ 叢集(ActiveMQ 的高性能和高可用需要通過叢集表現出來)。
在生産環境中,ActiveMQ 叢集的部署方式主要有下面兩種。
- Master Slave 模式:實作高可用,當主伺服器當機時,備用伺服器可以升主,以保證服務的繼續。
- Broker Clusters 模式:實作負載均衡,多個 Broker 之間同步消息,以達到伺服器負載的可能。
ActiveMQ 高可用方案
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 之間的資料是共享的。為了實作資料共享,有兩種方式:
- Shared Database Master/Slave
- 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 目錄下。
方案三:
Replicated LevelDB Store
基于複制的 LevelDB Store,是 ActiveMQ 最新的 HA 方案,在 5.9+ 版本中獲得支援。相較于方案二中的兩種“Shared Storage”模式,本方案在存儲和通訊機制上,更符合“Master-Slave”模型。
“Replicated LevelDB”同樣允許有多個 Slaves,而且 Slaves 的個數有了限制性的限制,這歸結于其使用 ZooKeeper 選舉 Master。要進行選舉,則需要多數派的“參與者”。因為 Replicated LevelDB Store 中有多個 Broker,從多個 Broker 中選舉出一個成為 Master,其他的則成為 Slave。隻有 Master 接收 Client 的連接配接,Slave 負責連接配接到 Master,并接收(同步方式、異步方式)Master 上的資料。每個 Broker 執行個體将消息資料儲存本地(類似于“Shared Nothing”),它們之間并不共享任何資料,是以,某種意義上把“Replicated LevelDB”歸類為“Shared Storage”并不妥當。
特别說明:ActiveMQ 官網警告,LevelDB 不再作為推薦的存儲方案,取而代之的是 KahaDB。
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 優缺點
優點主要有以下幾點。
- 跨平台(Java 編寫與平台無關,ActiveMQ 幾乎可以運作在任何 JVM 上);
- 可以使用 JDBC,将資料持久化到資料庫。雖然使用 JDBC 會降低 ActiveMQ 的性能, 但資料庫一直都是開發人員最熟悉的存儲媒體。将消息存到資料庫,看得見摸得着。而且公司有專門的 DBA 去對資料庫進行調優,主從分離;
- 支援 JMS 的統一接口;
- 支援自動重連;
- 有安全機制:支援基于 Shiro、JAAS 等多種安全配置機制,可以對 Queue/Topic 進行認證和授權;
- 擁有完善的監控體系,包括 Web Console、JMX、Shell 指令行,以及 Jolokia 的 REST API;
- 界面友善:提供的 Web Console 可以滿足大部分需求,此外,還有很多第三方元件可以使用,如 Hawtio。
其缺點主要有以下幾點:
- 社群活躍度較低,更新慢,增加維護成本;
- 網絡資料顯示,ActiveMQ 存在一些莫名其妙的問題,會丢失消息;
- 目前,官方将重心放到 ActiveMQ 6.0 下一代産品 Apollo 上,對 5.x 的維護較少;
- 不适合用于上千個隊列的應用場景。
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 代表一個會話任務。
消息隊列的使用過程如下:
- 用戶端連接配接到消息隊列伺服器,打開一個 Channel。
- 用戶端聲明一個 Exchange,并設定相關屬性。
- 用戶端聲明一個 Queue,并設定相關屬性。
- 用戶端使用 Routing Key,在 Exchange 和 Queue 之間建立好綁定關系。
- 用戶端投遞消息到 Exchange。Exchange 接收到消息後,根據消息的 Key 和已經設定的 Binding,進行消息路由,将消息投遞到一個或多個隊列裡。
- 有三種類型的 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 性能較好、高并發;
- 健壯、穩定、易用、跨平台、支援多種語言用戶端、文檔齊全;
- 有消息确認機制和持久化機制,可靠性高;
- 高度可定制的路由;
- 管理界面較豐富,在網際網路公司也有較大規模的應用;
- 社群活躍度高,更新快。
缺點主要有:
- 盡管結合 Erlang 語言本身的并發優勢,性能較好,但是不利于做二次開發和維護;
- 實作了代理架構,意味着消息在發送到用戶端之前可以在中央節點上排隊。此特性使得 RabbitMQ 易于使用和部署,但使得其運作速度較慢,因為中央節點增加了延遲,消息封裝後也比較大;
- 需要學習比較複雜的接口和協定,學習和維護成本較高。
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 是一款低延遲、高可靠、可伸縮、易于使用的消息中間件。具有以下特性:
- 支援釋出/訂閱(Pub/Sub)和點對點(P2P)消息模型;
- 隊列中有着可靠的先進先出(FIFO)和嚴格的順序傳遞;
- 支援拉(Pull)和推(Push)兩種消息模式;
- 單一隊列百萬消息的堆積能力;
- 支援多種消息協定,如 JMS、MQTT 等;
- 分布式高可用的部署架構,滿足至少一次消息傳遞語義;
- 提供 Docker 鏡像用于隔離測試和雲叢集部署;
- 提供配置、名額和監控等功能豐富的 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 種部署方式。
- 單個 Master 模式
除了配置簡單,沒什麼優點。
它的缺點是不可靠。該機器重新開機或當機,将導緻整個服務不可用,是以,生産環境幾乎不采用這種方案。
- 多個 Master 模式
配置簡單,性能最高,是它的優點。
它的缺點是:可能會有少量消息丢失(異步刷盤丢失少量消息,同步刷盤不丢失),單台機器重新開機或當機期間,該機器下未被消費的消息在機器恢複前不可訂閱,影響消息實時性。
特别說明:當使用多 Master 無 Slave 的叢集搭建方式時,Master 的 brokerRole 配置必須為 ASYNC_MASTER。如果配置為 SYNC_MASTER,則 producer 發送消息時,傳回值的 SendStatus 會一直是 SLAVE_NOT_AVAILABLE。
- 多 Master 多 Slave 模式:異步複制
其優點為:即使磁盤損壞,消息丢失得非常少,消息實時性不會受影響,因為 Master 當機後,消費者仍然可以從 Slave 消費,此過程對應用透明,不需要人工幹預,性能同多 Master 模式幾乎一樣。
它的缺點為:
Master 當機或磁盤損壞時會有少量消息丢失
。
- 多 Master 多 Slave 模式:同步雙寫
其優點為:資料與服務都無單點,Master 當機情況下,消息無延遲,服務可用性與資料可用性都非常高。
其缺點為:性能比異步複制模式稍低,大約低 10% 左右,發送單個消息的 RT 會稍高,目前主當機後,備機不能自動切換為主機,後續會支援自動切換功能。
RocketMQ 優缺點
優點主要包括以下幾點。
- 單機支援 1 萬以上持久化隊列;
- RocketMQ 的所有消息都是持久化的,先寫入系統 Page Cache,然後刷盤,可以保證記憶體與磁盤都有一份資料,通路時,直接從記憶體讀取;
- 模型簡單,接口易用(JMS 的接口很多場合并不太實用);
- 性能非常好,可以大量堆積消息在 Broker 中;
- 支援多種消費模式,包括叢集消費、廣播消費等;
- 各個環節分布式擴充設計,主從 HA;
- 社群較活躍,版本更新較快。
缺點主要有:
- 支援的用戶端語言不多,目前是 Java、C++ 和 Go,後兩種尚不成熟;
- 沒有 Web 管理界面,提供了 CLI(指令行界面)管理工具來進行查詢、管理和診斷各種問題;
- 沒有在 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/