NameServer 核心原理解析


之前的文章中,已經把 Broker、Producer 和 Conusmer 的部分源碼和核心的機制介紹的差不多了,但是其實 RocketMQ 中還有一個比較關鍵但是我們平時很容易忽略的組件——NameServer

在日常的使用中,我們接觸的最多的還是 Producer 和 Consumer,而 NameServer 沒有直接跟我們有交互。就像 Kafka 集群背后用於其集群元數據管理的 Zookeeper 集群一樣,NameServer 也在背后支撐着 RocketMQ 正常工作。

你給翻譯翻譯,什么叫 NameServer

NameServer 你可以簡單的把它理解成注冊中心

Broker 啟動的時候會將自己注冊到 NameServer 中,注冊的同時還會將 Broker 的 IP 地址、端口相關的數據,以及保存在 Broker 中的 RocketMQ 集群路由的數據一並跟隨心跳發送到 NameServer。這里的路由信息是指 Topic 下的 MessageQueue 分別都在哪台 Broker 上。

Producer 則會從 NameServer 中獲取元數據,從而將 Message 發到對應的 Broker 中去。

相應的,Consumer 也需要從 NameServer 中獲取數據。平常我們配置消費者,里面重要的信息主要就兩個,分別是你要消費的 Topic 和當前的 Consumer Group。根據配置,Consumer 會去 NameServer 獲取對應的 Topic 都有哪些 Broker,其真實的 IP 地址和端口是多少,拿到了這個之后就可以開始進行消息消費了。

注冊 Broker 都做了什么

這里我們先通過注冊 Broker 的源碼來預熱一下,為后面閱讀整個部分的源碼做准備,直接上代碼。

首先這里做了一個對 Broker 版本的區分,不同的版本采用不同的處理方式,鑒於官網現在最新的版本都已經到了 4.9.0 了,就暫時先不考慮低版本的情況了,后面有時間再討論。

只有向上面那種幾行的代碼會給大家貼出來,其余的代碼我會盡量用流程圖代替

校驗 Body 的完整性

首先是校驗 Broker 傳過來的數據的完整性。很簡單的一個判斷,將 Broker 傳過來的 Body 用 CRC32算法 加密之后,和請求中 Header 中所帶的由 Broker 加密的值進行對比,不同的話就說明數據的完整性出了問題,接下來需要中斷注冊流程。

解析Body

這里分成兩種情況:

  • Body為空
  • Body不為空

如果 Body 為空,則會將當前要注冊的 Broker 的 DataVersion 給重置;

而 **Body 不為空 **則會進行對 Body 進行解析,主要是從中解析出 DataVersion ,代表 Broker 中的數據版本。其次解析出這個 Broker 中存儲的所有 Topic 及其相關的配置。

執行注冊邏輯

這里就是注冊的核心邏輯了,這里為了更加容易理解,我們來分情況討論,就不把兩種情況揉在一起了。

  • 首次注冊
  • 非首次注冊

維護集群中 Broker 的 Name

在整個操作開始之前,會先給 RouteInfoManager 加一把鎖,這個 RouteInfoManager 里面就是 NameServer 存儲數據的地方。這個鎖是個讀寫鎖,使用的是 Java 中的 ReentrantReadWriteLock

這里的 BrokerName 是在 RocketMQ 配置文件中配置的變量。就是用於標識一個 Broker 的名字,但我們知道 Broker 是有主從架構的,並且 RocketMQ 4.5 之后推出的 Dleger 可以實現一主多從,換句話說,一個 Broker Name 可能會對應多個 Broker 實例。

在 MQ 看來,Broker 是多實例部署的;而在 Producer 或者 Consumer 來看,Broker就只有一個。所以,這個步驟內所維護的就是在當前集群中,有多少個這樣的 Broker Name。

維護 Broker 的數據

然后,RocketMQ 會在 brokerAddrTable 中維護每個 Broker 的核心數據,包含:

  • Broker 所處的集群
  • Broker 的名字(上面剛剛討論過)
  • 所有 Broker 的 BrokerID 和 Address 的對應關系,是個 Map,Address 為 IP+端口

同一個 Broker Name 下,為什么會有多個地址信息已經在上個步驟解答過,不在此贅述。

Broker 的數據維護主要有兩個方面:

  • 該 Broker 數據在 brokerAddrTable 中是否存在
  • brokerAddrTable 中維護的數據不能有重復的地址信息

第一個過於基礎簡單,就不再贅述。我們重點看第二個點,我們知道會有多個 Broker 地址,存在一個 Map 中,因為 Broker 是基於主從架構。那不知道你有沒有想過,NameServer 如何區分 的呢?

答案是通過 Map 的 Key,如果是 0 則代表是 Master 節點,1 則代表 Slave 節點,因為 RocketMQ 自己實現的 Broker 主從架構是一主一從,而一主多從則是由 RocketMQ 4.5 之后加入的 Dleger 實現的,暫時先不討論。區分的邏輯如下圖:

那什么時候會出現重復呢?

答案是主從切換

舉個例子,假設某個 Slave Broker 的 Address 為 192.168.1.101:8081 ,且已經注冊。此時brokerAddrs 中已經有一個key: 1 value: 192.168.1.101:8081 記錄了。

當集群中的 Master 宕機之后,會進行故障恢復,假設選中了上面這個 Broker 為新的 Master,在進行注冊的時候會發現,brokerAddrs 中已經有一個同樣的 Address 了,只是 Key 不同。但是由於它們從本質上來說就是同一台機器,如果不將 key 為1,也就是角色為 Slave 的記錄去掉,就會造成數據一致性的問題。

簡單總結一下來說,同一個 Adreess,在 brokerAddrs 中只能存在一個。感興趣的可以看一下源碼,其實跟上面文字描述的邏輯是一樣的。

去除了重復的 Address 數據之后,就會將本次注冊的 Broker 的數據注冊進 brokerAddrs 中。

維護 MessageQueue 的數據

這里主要是根據 Broker 的數據更新其 MessageQueue 相關的數據。接下來,我們詳細解析一下 Message Queue 的維護流程,同樣會給出源碼和流程圖,兩部分等價,可選擇性觀看。

當 Master 節點來注冊時,如果是首次注冊或者數據有更新,便會調用一個方法createAndUpdateQueueData去維護 MessageQueue 相關的數據。這里對數據是否更新的判斷,是基於 DataVersion 的,代表 Broker 數據的版本。

此后通過 Topic 的 Name 拿到對應的 MessageQueue 的列表,這里可能會有點疑問,一個 Topic 難道不應該只有一個對 MessageQueue 相關的配置嗎,為什么這里拿到的是個列表?

小了,格局小了

Topic 是個邏輯上的概念,一個 Topic 的 MessageQueue 會分布在不同的 Broker 上,所有這里是個列表。

更新的流程如上圖,拿到了 MessageQueue 的列表之后,會和本次注冊的 Broker 中的 MessageQueue 數據做一個對比,如果發現不同就進行全量的替換,沒什么其他的復雜對比邏輯。源碼等同上圖,感興趣的可以自行查看。

維護 Broker 的存活信息

到這里,MessageQueue 相關的邏輯就處理完了,接下來 NameServer 會再去更新 brokerLiveTable 中的數據,這里存放了當前正在活躍的所有 Broker。這塊的作用后續會講。

NameServer 啟動流程

上面通過了解注冊 Broker的整個流程,對整個 NameServer 的架構有了個大概的了解,接下來再從整體視角來看一下 NameServer。

NameServer的主要流程
NameServer的主要流程

整體的流程上面這張圖已經給出來了,就不放源碼了,意義不大。

這里說一下掃描不再活躍的Broker,這個后台線程會每 10秒 鍾執行一次,這里會對上文提到的 brokerLiveTable 進行遍歷處理,因為這里面維護了所有的正在活躍的 Broker。

如果某個 Broker 超過了 120秒 沒有發送心跳給 NameServer,就會將其從 brokerLiveTable 中移除。

NameServer 可處理的操作

上面簡單了解了 注冊 Broker 的流程,實際上 NameServer 還支持很多其他的操作,這里就不再這里列出來了,看了沒有意義,感興趣的可以自己去網上找,一大堆的資料。而且 Register Broker 這個操作中所涉及到源碼中的數據結構,其他的操作都會用到,所以了解了 Register Broker 之后,再去閱讀其他操作的源碼會非常的順。

好了以上就是本篇博客的全部內容了,歡迎微信搜索關注【SH的全棧筆記】,回復【隊列】獲取MQ學習資料,包含基礎概念解析和RocketMQ詳細的源碼解析,持續更新中。

如果你覺得這篇文章對你有幫助,還麻煩點個贊關個注分個享留個言


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM