MQ系列3:RocketMQ 架構分析
MQ系列1:消息中間件執行原理
MQ系列2:消息中間件的技術選型
1 背景
我們前面兩篇對主流消息隊列的基本構成和技術選型做了詳細的分析。從本篇開始,我們會專註當下主流MQ之一的RocketMQ。
從他的如下的幾個方面去討論:
- 基礎能力(如 組織構成、消息發送、消息存儲(持久化)、消息通訊、消息消費)
- 功能性方面(如消息堆積、消息回溯、消息追蹤、消息過濾),
- 高可用性方面(如 消息順序性保障、消息冪等性保障、消息安全性保障、消息事務性保障),
- 性能方面(如時效性,單機吞吐率)
1.1 RocketMQ是的基本組件構成
RocketMQ主要有四大核心組成部分:NameServer、Broker、Producer以及Consumer四部分。
- NameServer:Name Server是一個幾乎無狀態節點,可集群部署,節點之間無任何資訊同步。NameServer 是整個 RocketMQ 的 “中央大腦 ” ,它是 RocketMQ 的服務註冊中心,所以 RocketMQ 需要先啟動 NameServer 再啟動 Rocket 中的 Broker。
- Broker: 消息伺服器,作為Server提供消息核心服務, 它接收並存儲Producer生產的消息,也提供消息給Consumer消費。Broker一般會分主從,Master 可讀可寫,Slave 只讀。
- Producer: 消息生產者,消息的發送方,負責生產消息傳輸給broker。RocketMQ提供了發送:同步、非同步和單向(one-way)的多種模式。
- Consumer: 消息消費者,消息的處理方,負責從broker獲取消息並進行業務邏輯處理。
另外其他如 Topic、 Message,也是重要的組成部分:
- Topic:主題,發布/訂閱模式下的消息統一彙集地,不同生產者向topic發送消息,由MQ伺服器分發到不同的訂閱者,實現消息的廣播
- Message:消息體,根據不同通訊協議定義的固定格式進行編碼的數據包,來封裝業務數據,實現消息的傳輸。
2 RocketMQ 消息架構的演進過程
2.1 簡單的生產消費模式
根據我們前面所學的內容,消息隊列很重要的一個工作就是對生產和消費者進行解耦的過程。有人負責生產,有人負責消費,兩者沒有直接交互,交給中介者去處理。
比如說系統A會交給系統B去處理一些事情,但是A不想直接跟B有關聯,避免耦合太強,就可以通過在A,B中間加入消息隊列,A將要任務的事情交給消息隊列 ,B訂閱消息隊列來執行任務。
這種典型的模式是由兩個執行緒和一個隊列構成:
- 生產者執行緒:生產任務,並把任務推送到隊列里。
- 消費者執行緒:從隊列裡面獲取任務,並進行任務處理操作,這就是消費的過程。

目前這種還只是初級版本的 生產-消費者模式,構成了基本的消息隊列 。另外為了消息隊列的可用性,我們一般會把消費者,隊列,生產者放到不同的服務機上,變成分散式消息隊列,這樣哪怕消費者所在的主機掛了,依舊不影響消息生產。
2.2 Topic模式對消息進行歸類
主題(Topic)可以看做消息的歸類,我們將消息進行類型劃分,相同類型的消息稱為一個 Topic。比如我們在淘寶或京東上購買商品的的過程,就可能產生:購物車消息、交易消息、物流消息等,1條消息必然歸屬於1個 Topic 。
1個 Topic可以有0 ~ n 個生產者向其發送消息;也可以被 0~n 個消費者訂閱和處理,於是就有出現了生產者組和消費者組,如下圖:

2.3 Broker 集群模式
隨著生產者和消費者的不斷擴大,原本單一的Broker數據處理的能力始終是有限的(無論是被寫入、存儲或者被消費),所以這個時候就需要對Broker進行scale out,來分擔單機的壓力。我們稱之為 Broker 集群模式。在 微服務系列、MySQL系列、Redis系列 中,我們已經了解過很多Cluster模式的案例。

這邊需要注意,每個Broker 可以包含1個 Broker Master 和 至少 1個Broker Slave ,所以它是主從結構,通過 Data Sync、Async 來進行數據同步。 Producer 只能將消息發送到 Broker Master,但是 Consumer 同時和Broker Master和 Broker Slave 建立長連接,既可以從 Master 訂閱消息,也可以從 Slave 訂閱消息。
- Broker Master:可以用於消息生產,也可以用於消息消費,並將消息數據 Sync / Async 到Slave。
- Broker Slave:只能用於消息消費。
2.4 使用 NameServer 來進行路由管理
我們既然使用了Broker Cluster模式,那麼就會有多個Broker實例。這時候就有新的問題了,producer生產的消息需要發送到哪個Broker中,comsumer又要去哪個Broker裡面去取數據,都需要梳理清楚,不然就很混亂。RocketMQ摒棄了業界常用的zookeeper作為註冊中心(比如Kafka),而是使用自研的 NameServer 來管理 具有映射關係的路由資訊。由它來告訴producer,某個 Topic 的消息可以發給哪些隊列,同時告訴consumer可以從哪些隊列裡面獲取你需要的消息。NameServer 也可以有很多個,組成 NameServer 集群。
總得來說,NameServer是一個功能完整的命名服務組件,提供輕量級的服務發現及完整路由資訊記錄能力,主要包含兩個功能:
- Broker 管理,接收來自 Broker 集群的註冊請求,提供心跳機制,檢測 Broker 是否存活。
- 路由管理,每個 NameServer 持有全部有關 Broker 集群和客戶端請求隊列的路由資訊。
詳細運行流程可以參考如下:

上述的流程圖比較清晰的描述如下運轉流程:
- NameServer 優先啟動。NameServer 是整個 RocketMQ 的「中央大腦」 ,作為 RocketMQ 的服務註冊中心,所以 RocketMQ 需要先啟動 NameServer 再啟動 Rocket 中的 Broker。
- Broker 啟動後,與 NameServer 保持長連接,每 30s 發送一次發送心跳包,來確保Broker是否存活。並將 Broker 資訊 ( IP+、埠等資訊)以及Broker中存儲的Topic資訊上報。註冊成功後,NameServer 集群中就有 Topic 跟 Broker 的映射關係。
- NameServer 如果檢測到Broker 宕機(因為使用心跳機制, 如果檢測超120s(兩分鐘)無響應),則從路由註冊表中將其移除。
- 生產者在發送某個主題的消息之前先從 NamerServer 獲取 Broker 伺服器地址列表(Broker可能是Cluster模式),然後根據負載均衡演算法從列表中選擇1台Broker ,建立連接通道,進行消息發送。
- 消費者在訂閱某個topic的消息之前從 NamerServer 獲取 Broker 伺服器地址列表(Broker可能是Cluster模式),包括關聯的全部Topic隊列資訊。進而獲取當前訂閱 Topic 存在哪些 Broker 上,然後直接跟 Broker 建立連接通道,開始消費數據。
- 生產者和消費者默認每30s 從 NamerServer 獲取 Broker 伺服器地址列表,以及關聯的所有Topic隊列資訊,更新到Client本地。
3 總結
- Topic 主要是為了將消息進行歸類,同一個業務中消息繁複,我們將消息按照特性進行劃分,相同類型的消息稱為一個 Topic。
- 當業務不斷膨脹的時候,需要對Broker進行集群化,每個Broker實例包含1個 Broker Master 和 至少 1個Broker Slave ,通過 Data Sync、Async 來進行數據同步,這樣達到生產和消費分離。
- 使用 NameServer 來進行 Broker 註冊和管理,接收來自 Broker 集群的註冊請求,提供心跳機制,檢測 Broker 是否存活。
- NameServer 也用來進行路由管理,來保證 producer生產的消息需要發送到哪個Broker中,comsumer又要去哪個Broker裡面去取數據。




