前言
RocketMQ是一款分散式、佇列模型的訊息中介軟體,由阿里巴巴自主研發的一款適用於高併發、高可靠性、海量資料場景的訊息中介軟體。早期開源2.X版本名為MetaQ;2015年迭代3.X版本,更名為RocketMQ,2016年貢獻給Apache,經過一年多的孵化,最終成為Apache的頂級開源專案之一。RocketMQ是在Kafka的基礎上發展起來的,它的誕生參考借鑑了Apache Kafka(後面的文章我會單獨介紹Kafka)。起因是隨著阿里巴巴業務的發展,他們發現Kafka對於具體的業務場景支援的不完善,於是阿里巴巴的團隊借鑑Kafka的設計思路,並結合自身“雙十一”場景,自行開發了更貼合自己業務場景的RocketMQ,對Kafka進行了合理的擴充套件和API豐富。RocketMQ的訊息路由、儲存、叢集劃分等設計思路與Kafka都極其相似,唯一的不同是 RocketMQ 對於業務特性的支援更完善,所以更適用於業務場景。
1 專業術語
每一個技術框架,都有它的專有名詞,RocketMQ的專業術語如下:
1)Producer:訊息生產者,負責產生訊息,一般由業務系統負責產生訊息。
2)Consumer:訊息消費者,負責消費訊息,一般由後臺系統負責非同步消費。
3)Pull Consumer:Consumer的一種,需要主動請求Broker拉取訊息。
4)Push Consumer:Consumer的一種,需要向Consumer物件註冊監聽。
5)Producer Group:生產者集合,一般用於傳送一類訊息。
6)Consumer Group:消費者集合,一般用於接受一類訊息進行消費。
7)Broker:MQ訊息服務(中專角色,用於訊息儲存和生產消費轉發)。
2 能力與支援
1)支援叢集模型、負載均衡、水平擴充套件能力,如下面我們要講的叢集架構。
2)億級別的訊息堆積能力。
3)採用零拷貝的原理、順序寫盤、隨機讀(索引檔案)。
4)豐富的API使用。
5)程式碼優秀,底層通訊框架採用Netty NIO框架。
6)NameServer代替Zookeeper。
7)強調叢集無單點,可擴充套件,任意一點高可用,水平可擴充套件。
8)訊息失敗重試機制、訊息可查詢。
9)開源社群活躍度高,足夠成熟(經過雙十一考驗)。
3 核心原始碼包及功能說明
如下圖,我們看一下RocketMQ原始碼包的組成,這有利於我們以後更深入的學習。
1)rocketmq-broker 主要的業務邏輯,訊息收發,主從同步,pagecache
2)rocketmq-client 客戶端介面,比如生產者和消費者
3)rocketmq-common 公用資料結構等等
4)rocketmq-distribution 編譯模組,編譯輸出等
5)rocketmq-example 示例,比如生產者和消費者
6)rocketmq-fliter 進行Broker過濾的不感興趣的訊息傳輸,減小頻寬壓力
7)rocketmq-logappender、rocketmq-logging日誌相關
8)rocketmq-namesrv Namesrv服務,用於服務協調
9)rocketmq-openmessaging 對外提供服務
10)rocketmq-remoting 遠端呼叫介面,封裝Netty底層通訊
11)rocketmq-srvutil 提供一些公用的工具方法,比如解析命令列引數
12)rocketmq-store 訊息儲存核心包
13)rocketmq-test 提供一些測試程式碼包
14)rocketmq-tools 管理工具,比如有名的mqadmin工具
4 叢集架構
RocketMQ為我們提供了豐富的叢集架構模型,包括單點模式、主從模式、雙主模式以及生產上使用最多的雙主雙主模式(或者說多主多從模式),我們來看一下最經典的雙主雙從模式,如下圖:
1)NameServer叢集
NameServer叢集作為超輕量級的配置中心,儲存當前叢集所有的Broker資訊、Topic與Broker的對應關係。每個NameServer記錄完整的路由資訊,提供等效的讀寫服務,並支援快速儲存擴充套件。NameServer只做叢集後設資料儲存和心跳工作,功能簡單,穩定性高。多個NameServer之間沒有通訊,不必保障節點間的資料強一致性,也就是說NameServer叢集是一個多機熱備的概念,單臺NameServer當機不影響其他NameServer工作。需要注意的是,及時整個NameServer叢集當機了,已經正常工作的Producer、Consumer、Broker仍然能正常工作,但新起的Producer、Consumer、Broker就無法工作。
NameServer採用的是心跳機制,具體如下:
a、單個Broker跟所有NameServer保持心跳請求,心跳間隔為30秒,心跳請求中包括當前Broker所有的Topic資訊。需要注意的是,Broker向Namesrv發心跳時, 會帶上當前自己所負責的所有Topic資訊,如果Topic個數太多(萬級別),會導致一次心跳中,就Topic的資料就幾十M,網路情況差的話, 網路傳輸失敗,心跳失敗,導致Namesrv誤認為Broker心跳失敗。
b、NameServer會反查Broer的心跳資訊, 如果某個Broker在2分鐘之內都沒有心跳,則認為該Broker下線,調整Topic跟Broker的對應關係。但此時NameServer不會主動通知Producer、Consumer有Broker當機。
c、Consumer跟Broker是長連線,會每隔30秒發心跳資訊到Broker。Broker端每10秒檢查一次當前存活的Consumer,若發現某個Consumer 2分鐘內沒有心跳, 就斷開與該Consumer的連線,並且向該消費組的其他例項傳送通知,觸發該消費者叢集的負載均衡(rebalance)。
d、生產者每30秒從Namesrv獲取Topic跟Broker的對映關係,更新到本地記憶體中。再跟Topic涉及的所有Broker建立長連線,每隔30秒發一次心跳。 在Broker端也會每10秒掃描一次當前註冊的Producer,如果發現某個Producer超過2分鐘都沒有發心跳,則斷開連線。
2)Producer叢集
Producer叢集就是訊息生產者叢集,它們在同一個生產者組Producer Group。Producer與Name Server叢集中的其中一個節點(隨機選擇)建立長連線,定期從Name Server取Topic路由資訊,並向提供Topic服務的Master建立長連線,且定時向Master傳送心跳。Producer完全無狀態,可叢集部署。
3)Consumer叢集
Consumer叢集就是訊息消費者,它們在同一個消費者組Consumer Group。Consumer與Name Server叢集中的其中一個節點(隨機選擇)建立長連線,定期從Name Server取Topic路由資訊,並向提供Topic服務的Master、Slave建立長連線,且定時向Master、Slave傳送心跳。Consumer既可以從Master訂閱訊息,也可以從Slave訂閱訊息,訂閱規則由Broker配置決定。
4)Broker叢集
對於Broker來說,通常Master和Slave為一組服務,它們互為主從節點,通過NameServer與外部的Client端暴露統一的叢集入口。Broker就是訊息儲存的核心MQ服務。
5 總結
RockerMQ作為國內頂級的訊息中介軟體,其效能主要依賴於天然的分散式Topic/Queue,並且其記憶體與磁碟都會儲存訊息資料,借鑑了Kafka的“空中接力”概念,就是指資料不一定落地,RocketMQ提供了同步/非同步雙寫、同步/非同步複製的特性。在真正的生產環境中應該選擇符合自己業務的配置。下面針對RocketMQ的高效能和瓶頸加以說明:
1)在實際生產環境中面臨的主要瓶頸最終會落在IOPS上,也就是磁碟讀寫能力。當高峰期來臨,每秒收發訊息IOPS達到10W+訊息,在雲環境上,雲環境的SSD物理儲存顯然和自建機房SSD有著很大的差距,這一點我們無論是從資料庫的磁碟效能、還是搜尋服務(ElasticSearch)的磁碟效能,都能給出準確的瓶頸點,單機IOPS達到1萬左右就是雲端儲存SSD的效能瓶頸,在這裡我們也看到了“木桶短板原理”的效應,在真正的生產中,CPU的工作主要在等待IO操作,高併發下CPU資源接近極限,但是IOPS還是達不到我們想要的效果。
2)RocketMQ的效能已經足夠好,但是在很多時候,我們的業務會有一些非核心的訊息投遞,可以進行訊息中介軟體的業務拆分,把不重要的訊息(允許訊息丟失、非可靠性投遞的訊息)採用Kafka的非同步傳送機制,借住Kafka強大的吞吐量和訊息堆積能力來做業務分流,以此緩解RocketMQ的效能瓶頸。