前言
RocketMQ是一款分布式、隊列模型的消息中間件,由阿里巴巴自主研發的一款具有低延遲、高並發、高性能和可靠性、萬億級別容量、可靈活擴展的消息中間件。它是阿里巴巴於2012年開源的第三代分布式消息中間件,早期開源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的性能瓶頸。