RocketMQ源碼分析(一)總體架構

1 系列

  • 總體架構圖
  • producer端發送消息
  • broker端接收消息
  • broker端消息的存儲
  • consumer消費消息
  • 分佈式事務的實現
  • 定時消息的實現
  • 關於順序消費
  • 關於重複消息
  • 關於高可用

2 總體架構圖

先來看下官方給出的總體架構圖c#

RocketMQ的架構圖

  • Producer集羣:擁有相同的producerGroup,通常來說,Producer沒必要要有集羣的概念,這裏的集羣僅僅在RocketMQ的分佈式事務中有用到微信

  • Name Server集羣:提供topic的路由信息,路由信息數據存儲在內存中,broker會定時的發送路由信息到nameserver中的每個機器,來進行更新,因此name server集羣能夠簡單理解爲無狀態(實際狀況下可能存在每一個nameserver機器上的數據有短暫的不一致現象,可是經過定時更新,大部分狀況下都是一致的)架構

  • broker集羣:一個集羣有一個統一的名字,即brokerClusterName,默認是DefaultCluster。一個集羣下有多個master,每一個master下有多個slave。master和slave算是一組,擁有相同的brokerName,不一樣的brokerId,master的brokerId是0,而slave則是大於0的值。master和slave之間能夠進行同步複製或者是異步複製。併發

  • consumer集羣:擁有相同的consumerGroup。負載均衡

下面來講說他們之間的通訊關係異步

  • Producer和Name Server:每個Producer會與Name Server集羣中的一臺機器創建TCP鏈接,會從這臺Name Server上拉取路由信息。分佈式

  • Producer和broker:Producer會和它要發送的topic相關的master類型的broker創建TCP鏈接,用於發送消息以及定時的心跳信息。broker中會記錄該Producer的信息,供查詢使用.net

  • broker與Name Server:broker(不論是master仍是slave)會和每一臺Name Server機器來創建TCP鏈接。broker在啓動的時候會註冊本身配置的topic信息到Name Server集羣的每一臺機器中。即每一臺Name Server都有該broker的topic的配置信息。master與master之間無鏈接,master與slave之間有鏈接線程

  • Consumer和Name Server:每個Consumer會和Name Server集羣中的一臺機器創建TCP鏈接,會從這臺Name Server上拉取路由信息,進行負載均衡設計

  • Consumer和broker:Consumer能夠與master或者slave的broker創建TCP鏈接來進行消費消息,Consumer也會向它所消費的broker發送心跳信息,供broker記錄。

3 kafka的架構圖

來看下kafka的總體架構圖

kafka的總體架構圖

來看看他們之間的鏈接關係

  • Producer和broker:Producer會和它所要發送的topic相關的broker創建TCP鏈接,並經過broker進行其餘broker的發現(這個沒有依賴ZooKeeper進行服務發現)

  • broker和ZooKeeper:broker會將本身註冊在ZooKeeper上,同時依賴ZooKeeper作一些分佈式協調

  • Consumer和ZooKeeper:Consumer會將本身註冊在ZooKeeper上,同時依賴ZooKeeper進行broker發現以及將消費offset記錄在ZooKeeper上

  • Consumer和Broker:Consumer鏈接topic相關的broker進行消息的消費

4 RocketMQ和kafka的對比

4.1 消息的存儲

咱們知道topic是一類消息的統稱,爲了提升消息的寫入和讀取併發能力,將一個topic的消息進行拆分,能夠分散到多個broker中。kafka上稱爲分區,而RocketMQ稱爲隊列。

對於kafka:爲了防止一個分區的消息文件過大,會拆分紅一個個固定大小的文件,因此一個分區就對應了一個目錄。分區與分區之間是相互隔離的。

對於RocketMQ:則是全部topic的數據混在一塊兒進行存儲,默認超過1G的話,則從新建立一個新的文件。消息的寫入過程即寫入該混雜的文件中,而後又有一個線程服務,在不斷的讀取分析該混雜文件,將消息進行分揀,而後存儲在對應隊列目錄中(存儲的是簡要信息,如消息在混雜文件中的offset,消息大小等)

因此RocketMQ須要2次尋找,第一次先找隊列中的消息概要信息,拿到概要信息中的offset,根據這個offset再到混雜文件中找到想要的消息。而kafka則只須要直接讀取分區中的文件便可獲得想要的消息。

看下這裏給出的RocketMQ的日誌文件圖片分佈式開放消息系統(RocketMQ)的原理與實踐

RocketMQ的消息存儲

這裏我本身認爲RocketMQ的作法仍是值得商榷的,這樣的作法在同步刷盤、異步刷盤時效率相對高些(因爲量大因此效率相對高些),可是所有的topic往一個文件裏面寫,每次寫入要進行加鎖控制,原本不相干的topic卻相互影響,就下降的寫入的效率。這個鎖的粒度有點大了,我本身認爲應該一個隊列對應一個CommitLog,這樣作就是減小鎖的粒度問題。

4.1 Prdocuer端的服務發現

就是Producer端如何來發現新的broker地址。

對於kafka來講:Producer端須要配置broker的列表地址,Producer也從一個broker中來更新broker列表地址(從中發現新加入的broker)。

對於RocketMQ來講:Producer端須要Name Server的列表地址,同時還能夠定時從一個HTTP地址中來獲取最新的Name Server的列表地址,而後從其中的一臺Name Server來獲取所有的路由信息,從中發現新的broker。

4.1 消費offset的存儲

對於kafka:Consumer將消費的offset定時存儲到ZooKeeper上,利用ZooKeeper保障了offset的高可用問題。

對於RocketMQ:Consumer將消費的offset定時存儲到broker所在的機器上,這個broker優先是master,若是master掛了的話,則會選擇slave來存儲,broker也是將這些offset定時刷新到本地磁盤上,同時slave會定時的訪問master來獲取這些offset。

4.2 consumer負載均衡

對於負載均衡,在出現分區或者隊列增長或者減小的時候、Consumer增長或者減小的時候都會進行reblance操做。

對於RocketMQ:客戶端本身會定時對全部的topic的進行reblance操做,對於每一個topic,會從broker獲取全部Consumer列表,從broker獲取隊列列表,按照負載均衡策略,計算各自負責哪些隊列。這種就要求進行負載均衡的時候,各個Consumer獲取的數據是一致的,否則不一樣的Consumer的reblance結果就不一樣。

對於kafka:kafka以前也是客戶端本身進行reblance,依靠ZooKeeper的監聽,來監聽上述2種狀況的出現,一旦出現則進行reblance。如今的版本則將這個reblance操做轉移到了broker端來作,不但解決了RocketMQ上述的問題,同時減輕了客戶端的操做,是的客戶端更加輕量級,減小了和其餘語言集成的工做量。詳細見這篇文章Kafka設計解析(四):Kafka Consumer解析

4.3 Name Server和ZooKeeper

Name Server和ZooKeeper的做用大體是相同的,從宏觀上來看,Name Server作的東西不多,就是保存一些運行數據,Name Server之間不互連,這就須要broker端鏈接全部的Name Server,運行數據的改動要發送到每個Name Server來保證運行數據的一致性(這個一致性確實有點弱),這樣就變成了Name Server很輕量級,可是broker端就要作更多的東西了。

而ZooKeeper呢,broker只須要鏈接其中的一臺機器,運行數據分發、一致性都交給了ZooKeeper來完成。

目前先就這幾個大的組件進行簡單的對比,後續會對某些細節進行詳細說明。

歡迎關注微信公衆號:乒乓狂魔

微信公衆號

相關文章
相關標籤/搜索