21 設(shè)計(jì)生產(chǎn)架構(gòu)之前的功課:消息中間件路由中心的架構(gòu)原理是什么?

設(shè)計(jì)生產(chǎn)架構(gòu)之前的功課:消息中間件路由中心的架構(gòu)原理是什么?
1、小猛的RocketMQ研究之路
上回給同事們分享了RocketMQ的基本架構(gòu)后,大家都希望小猛多研究研究RocketMQ的原理,因?yàn)樯洗蝺H僅了解了一些基本原理,還遠(yuǎn)遠(yuǎn)不能讓大家滿足,很多細(xì)節(jié)都存在各種各樣的疑問。
所以小猛發(fā)現(xiàn),自己真是被明哥推到了一個坑里,這哪是簡單的做一下調(diào)研和分享,明明就是讓他來負(fù)責(zé)團(tuán)隊(duì)里至關(guān)重要的RocketMQ技術(shù)??!
不僅要研究透徹一個技術(shù),還要給大家做大量分享,保證團(tuán)隊(duì)能夠成功的將MQ技術(shù)運(yùn)用到訂單系統(tǒng)架構(gòu)里去,這真是一個長期而且艱巨的任務(wù)!
不過小猛轉(zhuǎn)念一想,其實(shí)這也是明哥給自己的一個機(jī)會,畢竟不是每個新人都能這么好運(yùn),一進(jìn)公司就擔(dān)負(fù)起這種核心技術(shù)任務(wù)的。那既然如此,干脆就借著這個機(jī)會深入的研究一下RocketMQ,邊研究邊想辦法把技術(shù)落地去實(shí)踐。
初生牛犢不怕虎,說干就干,小猛的RocketMQ研究之路就這樣開始了。。。
2、研究RocketMQ的一個切入點(diǎn)
首先,小猛思考了一下,研究RocketMQ應(yīng)該從哪個點(diǎn)來切入呢?
他回憶了一下之前自己PPT里做的一個RocketMQ整體架構(gòu)圖。
? ? ? ? ? ?

? ? ? ? ? ??
他仔細(xì)想了一下,其實(shí)RocketMQ這個技術(shù)一共是包含了四個核心的部分:
第一塊就是他的NameServer,這個東西很重要,他要負(fù)責(zé)去管理集群里所有Broker的信息,讓使用MQ的系統(tǒng)可以通過他感知到集群里有哪些Broker。
第二塊就是Broker集群本身了,必須得在多臺機(jī)器上部署這么一個集群,而且還得用主從架構(gòu)實(shí)現(xiàn)數(shù)據(jù)多副本存儲和高可用。
第三塊就是向MQ發(fā)送消息的那些系統(tǒng)了,這些系統(tǒng)一般稱之為生產(chǎn)者,這里也有很多細(xì)節(jié)是值得深究的,因?yàn)檫@些生產(chǎn)者到底是如何從NameServer拉取路由信息的?如何選擇Broker機(jī)器建立連接以及發(fā)送消息的?
第四塊就是從MQ獲取消息的那些系統(tǒng),這些系統(tǒng)一般稱之為消費(fèi)者。
仔細(xì)想想消費(fèi)者里其實(shí)也隱藏了很多的技術(shù)細(xì)節(jié),比如到底是Broker主動推送消息給消費(fèi)者?還是消費(fèi)者自己從Broke里拉取消息?這些也都很值得深究。
那么到底從哪兒入手開始呢?因?yàn)樽约旱乃悸肥沁呇芯窟吢涞兀詈檬浅醪礁闱宄恍㏑ocketMQ的架構(gòu)設(shè)計(jì)細(xì)節(jié),然后就申請一些機(jī)器開始落地部署了,可以測試測試,然后嘗試讓一些生產(chǎn)系統(tǒng)開始使用他。
此時小猛的目光放到了NameServer上,他覺得NameServer正是研究RocketMQ必須優(yōu)先選擇的一個切入點(diǎn),因?yàn)闆]有NameServer,一切都無從談起,可以說這是RocketMQ運(yùn)行的起點(diǎn)。
好,那么就從NameServer開始研究,然后再給大家做一次分享!
3、一次關(guān)于RocketMQ NameServer設(shè)計(jì)原理的技術(shù)分享
小猛花了幾天的時間對RocketMQ的NameServer進(jìn)行了一些研究,得出了很多的心得,對NameServer的設(shè)計(jì)理念和一些細(xì)節(jié)真的有了更深一步的認(rèn)識。
因此他用心做了一份技術(shù)分享PPT,然后召集了團(tuán)隊(duì)里的小伙伴,又做了一次關(guān)于NameServer的技術(shù)分享。
會議室里,大家伙剛坐下,就有不少人對小猛有點(diǎn)意見了。有人說,小猛,你怎么搞的,分享也不搞點(diǎn)干貨,我們都想看看Broker的一些底層原理,比如數(shù)據(jù)是怎么存儲的,怎么寫入磁盤的 ,中間有沒有緩沖層的設(shè)計(jì)之類的。
小猛尷尬的說,大家別著急啊,我其實(shí)也想到了RocketMQ底層那些特別牛X的技術(shù)實(shí)現(xiàn)細(xì)節(jié),但是想來想去,還是覺得應(yīng)該從NameServer先開始,因?yàn)檫@個是RocketMQ的起點(diǎn)啊,沒有他,RocketMQ怎么運(yùn)行呢?
大家伙一聽,覺得還挺對的,那好,耐心聽小猛來講吧。
4、NameServer到底可以部署幾臺機(jī)器?
小猛此時先切入了第一個問題,大家想想,要部署RocketMQ,就得先部署NameServer,那么這個NameServer到底可以部署幾臺機(jī)器呢?
是一臺機(jī)器?還是可以部署多臺機(jī)器?如果部署多臺機(jī)器,他們之間是怎么協(xié)同工作的?
大家面面相覷,沒人說出個所以然來,都催促小猛別賣關(guān)子,趕緊繼續(xù)講,盡量30分鐘內(nèi)搞定分享,大家還得各回各工位,各找各自的產(chǎn)品經(jīng)理繼續(xù)撕需求和寫代碼呢!
小猛腦門黑線了一下,心想自己本來還想跟大家互動一下,結(jié)果大家這么猴急,那好,別啰嗦了,直接一鼓作氣講完吧!
NameServer,首先是支持部署多臺機(jī)器的。也就是說,NameServer是可以集群化部署的,大家回頭看看我之前做的PPT里的圖,小猛打開一張圖,里面畫了一個紅圈。
? ? ? ? ? ?

? ? ? ? ? ??
在當(dāng)時的圖里就是畫了多臺NameServer機(jī)器的,只不過上次分享沒提到了NameServer集群部署這個話題。
那為什么NameServer要集群化部署?
最主要的一個原因,就是高可用性。
因?yàn)榇蠹叶贾溃琋ameServer是集群里非常關(guān)鍵的一個角色,他要管理Broker信息,別人都要通過他才知道跟哪個Broker通信,所以沒了他就會很麻煩!
那么如果NameServer就部署一臺機(jī)器的話,一旦NameServer宕機(jī)了,豈不是會導(dǎo)致RocketMQ集群出現(xiàn)故障?
所以通常來說,NameServer一定會多機(jī)器部署,實(shí)現(xiàn)一個集群,起到高可用的效果,保證任何一臺機(jī)器宕機(jī),其他機(jī)器上的NameServer可以繼續(xù)對外提供服務(wù)!
5、Broker是把自己的信息注冊到哪個NameServer上去?
下一個問題:Broker在啟動的時候是把自己的信息注冊到哪個NameServer上去的?
有的人可能會猜測,是不是這樣,比如一共有10臺Broker機(jī)器,2個NameServer機(jī)器,然后其中5臺Broker會把自己的信息注冊到1個NameServer上去,另外5臺Broker會把自己的信息注冊到另外1個NameServer上去。
小猛這時打開了一個這種猜想的示意圖,在這個圖里,兩個Master Broker分別注冊到了不同的NameServer上去。如下圖所示:
? ? ? ? ? ?

?? ?? ? ? ??
那么到底是不是這樣呢?
答案是:不對
這樣搞有一個最大的問題,如果1臺NameServer上有5個Broker的信息,另外1個NameServer上有另外5個Broker的信息,那么此時任何一個NameServer宕機(jī)了,不就導(dǎo)致5個Broker的信息就沒了嗎?
所以這種做法是不靠譜的,會導(dǎo)致數(shù)據(jù)丟失,系統(tǒng)不可用。
因此正確答案是:每個Broker啟動都得向所有的NameServer進(jìn)行注冊
也就是說,每個NameServer都會有一份集群中所有Broker的信息。
小猛接著打開了下一張圖。
? ? ? ? ? ?

?? ? ? ? ? ?
在這個圖里就示范了一個Master Broker得向兩臺NameServer都進(jìn)行注冊的情況,這才是真正的情況。
6、系統(tǒng)如何從NameServer獲取Broker信息?
下一個問題:扮演生產(chǎn)者和消費(fèi)者的系統(tǒng)們,如何從NameServer那兒獲取到集群的Broker信息呢?
他們需要知道集群里有哪些Broker,才能根據(jù)一定的算法挑選一個Broker去發(fā)送消息或者獲取消息。
有兩種辦法:
第一種辦法是這樣,NameServer那兒會主動發(fā)送請求給所有的系統(tǒng),告訴他們Broker信息。
這種辦法靠譜嗎?明顯不靠譜,因?yàn)镹ameServer怎么知道要推送Broker信息給哪些系統(tǒng)?未卜先知嗎?
第二種辦法是這樣的,每個系統(tǒng)自己每隔一段時間,定時發(fā)送請求到NameServer去拉取最新的集群Broker信息。
這個辦法是靠譜的,沒有什么明顯的缺陷,所以RocketMQ中的生產(chǎn)者和消費(fèi)者就是這樣,自己主動去NameServer拉取Broker信息的。
小猛接著打開了一張圖。
? ? ? ? ? ?

? ? ? ? ? ??
順便在這里解釋一下,圖里的路由信息,大致可以理解為集群里的Broker信息以及其他相關(guān)的數(shù)據(jù)信息
通過這些路由信息,每個系統(tǒng)就知道發(fā)送消息或者獲取消息去哪臺Broker上去進(jìn)行了,這起到一個把消息路由到一個Broker上的效果,所以一般我們把這種信息叫做路由信息。
7、如果Broker掛了,NameServer是怎么感知到的?
下一個問題,現(xiàn)在一個Broker啟動之后向NameServer注冊了,每個NameServer都知道集群里有這么一臺Broker的存在了,然后各個系統(tǒng)從NameServer那兒也拉取到了Broker信息,也知道集群里有這么一臺Broker
但是如果之后這臺Broker掛了呢?
要解決這個問題,靠的是Broker跟NameServer之間的心跳機(jī)制,Broker會每隔30s給所有的NameServer發(fā)送心跳,告訴每個NameServer自己目前還活著。
小猛說著,打開了一個圖,在里面有一個心跳的概念。
? ? ? ? ? ?

?? ? ? ? ??
每次NameServer收到一個Broker的心跳,就可以更新一下他的最近一次心跳的時間
然后NameServer會每隔10s運(yùn)行一個任務(wù),去檢查一下各個Broker的最近一次心跳時間,如果某個Broker超過120s都沒發(fā)送心跳了,那么就認(rèn)為這個Broker已經(jīng)掛掉了。
小猛說著又打開了一張圖。
? ? ? ? ? ?

?? ? ? ? ? ?
8、Broker掛了,系統(tǒng)是怎么感知到的?
下一個問題,如果Broker掛掉了,那么作為生產(chǎn)者和消費(fèi)者的系統(tǒng)是怎么感知到的呢?難道必須得NameServer發(fā)送請求給所有的系統(tǒng)通知他們嗎?
這個是不現(xiàn)實(shí)的,之前已經(jīng)說過了,NameServer去發(fā)送這個東西非常的不靠譜。
但是如果NameServer沒有及時通知給那些系統(tǒng),那么有沒有可能出現(xiàn)這樣一種情況,剛開始集群里有10個Broker,各個系統(tǒng)從NameServer那里得知,都以為有10個Broker。
結(jié)果此時突然掛了一個Broker,120s沒發(fā)心跳給NameServer,NameServer是知道現(xiàn)在只有9個Broker了。
但是此時其他系統(tǒng)是不知道只有9個Broker的,還以為有10個Broker,此時可能某個系統(tǒng)就會發(fā)送消息到那個已經(jīng)掛掉的Broker上去,此時是絕對不可能成功發(fā)送消息的
小猛說著打開了一張圖。
? ? ? ? ? ?

? ? ? ? ? ??
針對這個情況怎么辦?這個問題要我們以后去分析生產(chǎn)者原理的時候才會具體說他的細(xì)節(jié),現(xiàn)在簡單先提一下思路。
大家可以想一下,如果確實(shí)是那個情況,可以有兩種解決辦法。
首先,你可以考慮不發(fā)送消息到那臺Broker,改成發(fā)到其他Broker上去。
其次,假設(shè)你必須要發(fā)送消息給那臺Broker,那么他掛了,他的Slave機(jī)器是一個備份,可以繼續(xù)使用,你是不是可以考慮等一會兒去跟他的Slave進(jìn)行通信?
總之,這些都是思路,但是現(xiàn)在我們先知道,對于生產(chǎn)者而言,他是有一套容錯機(jī)制的,即使一下子沒感知到某個Broker掛了,他可以有別的方案去應(yīng)對。
而且過一會兒,系統(tǒng)又會重新從NameServer拉取最新的路由信息了,此時就會知道有一個Broker已經(jīng)宕機(jī)了。
OK!今天的技術(shù)分享就到這里了,這就是NameServer的核心工作原理。
大家最主要是知道他的集群化部署、Broker會注冊到所有NameServer去、30s心跳機(jī)制和120s故障感知機(jī)制、生產(chǎn)者和消費(fèi)者的客戶端容錯機(jī)制,這些是最核心的。
大家聽完了小猛的分享之后,不禁一起鼓掌,都覺得小猛研究的確實(shí)不錯,說的通俗易懂,而且讓每個人對NameServer的理解都更深入了。
End
專欄版權(quán)歸公眾號儒猿技術(shù)窩所有
未經(jīng)許可不得傳播,如有侵權(quán)將追究法律責(zé)任