摘要:故事中的下屬們,就是消息生產(chǎn)者角色,屋子右面墻根那塊地就是消息持久化,呂秀才就是消息調(diào)度中心,而你就是消息消費(fèi)者角色。下屬們匯報(bào)的消息,應(yīng)該疊放在哪里,這個(gè)消息又應(yīng)該在哪里才能找到,全靠呂秀才的驚人記憶力,才可以讓消息準(zhǔn)確的被投放以及消費(fèi)。
微信公眾號(hào):IT一刻鐘序
大型現(xiàn)實(shí)非嚴(yán)肅主義現(xiàn)場(chǎng)
一刻鐘與你分享優(yōu)質(zhì)技術(shù)架構(gòu)與見聞,做一個(gè)有劇情的程序員
關(guān)注可了解更多精彩內(nèi)容。問(wèn)題或建議,請(qǐng)公眾號(hào)留言。
在很久很久以前,人們之間的通信方式就是面對(duì)面交談,你說(shuō)一句,我聽一句,雖然簡(jiǎn)單可靠,但是弊端也很大。
比如,當(dāng)你成為一個(gè)軍隊(duì)的首領(lǐng),每個(gè)屬下一有情況就立刻向你匯報(bào),一個(gè)還好,但當(dāng)你的屬下有幾十個(gè)幾百個(gè)的時(shí)候,他們每天不分時(shí)間不看場(chǎng)合,都在嘰嘰喳喳和你匯報(bào)情況,那你可能什么都聽不到,而且腦袋都要炸掉了。這個(gè)時(shí)候,你說(shuō)停,都給我停下,要匯報(bào)情況的,去門口排隊(duì),一個(gè)一個(gè)的來(lái),這個(gè)就叫做流量削峰,一群人不要一擁而上,都乖乖給我排隊(duì)去。
然后你就一個(gè)接一個(gè)的聽,聽了整整24個(gè)小時(shí),實(shí)在困的不行,尋思著這樣不行呀,如此下去可能就要天妒英才了,于是你又說(shuō),來(lái)人,發(fā)筆和紙,都把要匯報(bào)的消息寫在紙上,寫完后告訴呂秀才,然后聽呂秀才的指示,沿著屋里右面墻根,按照指示的位置疊放整齊,匯報(bào)的人就可以退下該做啥做啥去吧,等我休息一下,再來(lái)看你們的匯報(bào)內(nèi)容,這就叫做異步處理,你終于可以由自己掌控消息獲取的進(jìn)度了,美滋滋的去睡覺了。
而匯報(bào)的人把內(nèi)容寫在紙上,疊放好,就可以退下自己做自己該做的事情,而不是一直在門口等待匯報(bào),這個(gè)就叫做解耦。
削峰,異步,解耦。這就是消息隊(duì)列最常用的三大場(chǎng)景。
故事中的下屬們,就是消息生產(chǎn)者角色,屋子右面墻根那塊地就是消息持久化,呂秀才就是消息調(diào)度中心,而你就是消息消費(fèi)者角色。下屬們匯報(bào)的消息,應(yīng)該疊放在哪里,這個(gè)消息又應(yīng)該在哪里才能找到,全靠呂秀才的驚人記憶力,才可以讓消息準(zhǔn)確的被投放以及消費(fèi)。
在RocketMQ里,就有一個(gè)角色和呂秀才的作用一樣,叫做NameServer,它是整個(gè)分布式消息調(diào)度的總控制,是RocketMQ的靈魂之所在,倘如沒有了它,RocketMQ會(huì)分崩離析無(wú)法工作。
那么,它是怎么工作的呢?
我們先來(lái)看一張RocketMQ物理架構(gòu)圖:
亂如蜘蛛絲?不要害怕,換句話說(shuō),先忘掉這張圖吧。
我們來(lái)類比一下現(xiàn)實(shí)生活,有一個(gè)人想要給另外一個(gè)人寄快件,那么就需要先由這個(gè)人在網(wǎng)上查詢有哪些郵局,然后選擇其中一個(gè)郵局,把快件投遞給它,再由郵局配送到目標(biāo)人。
需要完成這一整個(gè)業(yè)務(wù)流程,首先需要將郵局自身的信息注冊(cè)到衛(wèi)星網(wǎng)絡(luò)上,衛(wèi)星負(fù)責(zé)信息的調(diào)度,這樣發(fā)件人就知道有哪些郵局可以選擇,收件人通過(guò)衛(wèi)星網(wǎng)絡(luò)知道快件到了哪個(gè)郵局,可以聯(lián)系郵局溝通適合的配送時(shí)間,而郵局則負(fù)責(zé)接收配送存儲(chǔ)快件。
類比RocketMQ簡(jiǎn)線圖就是如下:
Producer:消息?產(chǎn)者,?于向消息服務(wù)器發(fā)送消息,就是圖中的寄件人。
NameServer:路由注冊(cè)中?,就是圖中的衛(wèi)星。
Broker:消息存儲(chǔ)服務(wù)器,就是圖中的郵局。
Consumer:消息消費(fèi)者,不是今天的重點(diǎn),圖中未標(biāo)出,就是收件人。
由此可見,NameServer作為分布式消息隊(duì)列的協(xié)調(diào)者,具有信息路由注冊(cè)與發(fā)現(xiàn)的作用。
路由注冊(cè)郵局在竣工后,需要與衛(wèi)星聯(lián)網(wǎng),將自己納入衛(wèi)星網(wǎng)絡(luò)管理中,這樣就相當(dāng)于對(duì)外宣布,我這個(gè)郵局開始運(yùn)營(yíng)了,可以收發(fā)郵件快遞了。
郵局并網(wǎng)之后,如何讓衛(wèi)星持續(xù)并及時(shí)感知這個(gè)郵局在線以及郵局自身信息的調(diào)整,使衛(wèi)星可以隨時(shí)協(xié)調(diào)這個(gè)郵局呢?這個(gè)時(shí)候就需要郵局定時(shí)向衛(wèi)星發(fā)一條信息:
“嗶嗶嗶————我是郵局C,編號(hào)SHC,地址XXXXX,歸屬中國(guó)上海集群,在線,此時(shí)此刻2019年3月15日13點(diǎn)21秒”
衛(wèi)星接收到消息后,拿個(gè)小本本記錄下來(lái):
“郵局B,BJB,北京,2019年3月15日13點(diǎn)10秒,活著...”
“郵局A,BJA,北京,2019年3月15日13點(diǎn)15秒,活著...”
“郵局C,SHC,上海,2019年3月15日13點(diǎn)21秒,活著...”
......
上面這個(gè)故事,就講述了NameServer路由注冊(cè)的基本原理。
NameServer就相當(dāng)于衛(wèi)星,內(nèi)部會(huì)維護(hù)一個(gè)Broker表,用來(lái)動(dòng)態(tài)存儲(chǔ)Broker的信息。
而Broker就相當(dāng)于郵局,在啟動(dòng)的時(shí)候,會(huì)先遍歷NameServer列表,依次發(fā)起注冊(cè)請(qǐng)求,保持長(zhǎng)連接,然后每隔30秒向NameServer發(fā)送心跳包,心跳包中包含BrokerId、Broker地址、Broker名稱、Broker所屬集群名稱等等,然后NameServer接收到心跳包后,會(huì)更新時(shí)間戳,記錄這個(gè)Broker的最新存活時(shí)間。
NameServer在處理心跳包的時(shí)候,存在多個(gè)Broker同時(shí)操作一張Broker表,為了防止并發(fā)修改Broker表導(dǎo)致不安全,路由注冊(cè)操作引入了ReadWriteLock讀寫鎖,這個(gè)設(shè)計(jì)亮點(diǎn)允許多個(gè)消息生產(chǎn)者并發(fā)讀,保證了消息發(fā)送時(shí)的高并發(fā),但是同一時(shí)刻N(yùn)ameServer只能處理一個(gè)Broker心跳包,多個(gè)心跳包串行處理。這也是讀寫鎖的經(jīng)典使用場(chǎng)景,即讀多寫少。
忽然有一天,郵局C的機(jī)房進(jìn)老鼠了,咬斷電源線宕機(jī)了,而衛(wèi)星不知道郵局C業(yè)務(wù)故障了,依舊將帶有郵局C的郵局表信息傳給寄件人(生產(chǎn)者),寄件人聯(lián)系郵局C發(fā)送快件,但是郵局C機(jī)房宕機(jī),業(yè)務(wù)暫停,處于癱瘓狀態(tài),自然也就無(wú)法接收快件了。
另一方面,因?yàn)榭旒茨鼙秽]局C收入,也就無(wú)法將快件轉(zhuǎn)交給收件人,顧客們久久等不到自己的快件,紛紛投訴,為此郵局C的管理層備受責(zé)難。
于是郵政總局技術(shù)部開始研究討論,怎么讓衛(wèi)星可以感知到郵局“失聯(lián)了”,從而自動(dòng)排除故障郵局,將其負(fù)責(zé)的業(yè)務(wù)交付給其他正常的郵局處理,這樣就不會(huì)因?yàn)槟骋粋€(gè)郵局出現(xiàn)問(wèn)題,而導(dǎo)致這個(gè)郵局所管轄的部分業(yè)務(wù)無(wú)法處理。
大家眾說(shuō)紛紜,最后敲定了一個(gè)方案,讓衛(wèi)星每隔一段時(shí)間掃描郵局信息表,如果發(fā)現(xiàn)某個(gè)郵局上報(bào)信息時(shí)間與當(dāng)時(shí)掃描時(shí)間之間的差值超過(guò)了某個(gè)預(yù)設(shè)的閾值,就判定這個(gè)郵局“失聯(lián)了”,將此郵局信息從郵局表中剔除。這樣寄件人查詢到的郵局表里都是正常營(yíng)業(yè)的郵局信息。
新功能上線運(yùn)營(yíng)后,效果不錯(cuò),大家再也不用擔(dān)心因?yàn)槟硞€(gè)郵局故障而導(dǎo)致業(yè)務(wù)停滯,又過(guò)上了泡茶報(bào)紙的生活。
這個(gè)故事同樣在RocketMQ中上演。
正常情況下,如果Broker關(guān)閉,則會(huì)與NameServer斷開長(zhǎng)連接,Netty的通道關(guān)閉監(jiān)聽器會(huì)監(jiān)聽到連接斷開事件,然后會(huì)將這個(gè)Broker信息剔除掉。
異常情況下,NameServer中有一個(gè)定時(shí)任務(wù),每隔10秒掃描一下Broker表,如果某個(gè)Broker的心跳包最新時(shí)間戳距離當(dāng)前時(shí)間超多120秒,也會(huì)判定Broker失效并將其移除。
細(xì)心的人會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,NameServer在清除失活Broker之后,并沒有主動(dòng)通知生產(chǎn)者,生產(chǎn)者每隔30秒會(huì)請(qǐng)求NameServer并獲取最新的路由表,那么就意味著,消息生產(chǎn)者總會(huì)有30秒的延時(shí),無(wú)法實(shí)時(shí)感知Broker服務(wù)器的宕機(jī)。所以在這個(gè)30秒里,生產(chǎn)者依舊會(huì)向失活Broker發(fā)送消息,那么消息發(fā)送的高可用性如何保證呢?
要解決這個(gè)問(wèn)題得首先談一談Broker的負(fù)載策略,消息發(fā)送隊(duì)列默認(rèn)采用輪詢機(jī)制,消息發(fā)送時(shí)默認(rèn)選擇異常重試機(jī)制來(lái)保證消息發(fā)送的高可用。當(dāng)Broker宕機(jī)后,雖然消息發(fā)送者無(wú)法第一時(shí)間感知Broker 宕機(jī),但是當(dāng)消息生產(chǎn)者向Broker發(fā)送消息返回異常后,消息生產(chǎn)者會(huì)選擇另外一個(gè)Broker上的消息隊(duì)列,這樣就規(guī)避了發(fā)生故障的Broker,結(jié)合重試機(jī)制,巧妙實(shí)現(xiàn)消息發(fā)送的高可用,同時(shí)由于不需要NameServer通知眾多不固定的生產(chǎn)者,也降低了NameServer實(shí)現(xiàn)的復(fù)雜性。
在降低NameServer實(shí)現(xiàn)復(fù)雜性方面,還有一個(gè)設(shè)計(jì)亮點(diǎn)就是NameServer之間是彼此獨(dú)立無(wú)交流的,也就是說(shuō)NameServer服務(wù)器之間在某個(gè)時(shí)刻的數(shù)據(jù)并不會(huì)完全相同,但是異常重試機(jī)制使得這種差異不會(huì)造成任何影響。
路由發(fā)現(xiàn)天上的衛(wèi)星是有限的,不易變的,而地上的寄件人是繁多的,易變的。所以寄件人想要知道有哪些郵局,很明顯最適合的方式是向衛(wèi)星發(fā)請(qǐng)求,拉取郵局表信息,而不是等衛(wèi)星給每個(gè)人推送。
所以在RocketMQ中,NameServer是不主動(dòng)推送會(huì)客戶端的,而是由客戶端拉取主題的最新路由信息。
NameServer作為注冊(cè)和發(fā)現(xiàn)中心,是整個(gè)分布式消息隊(duì)列調(diào)度的靈魂,談及到分布式,就逃不開CAP理論,C是Consistency,A是Availability,P是Partiton Tolerance,對(duì)于分布式架構(gòu),網(wǎng)絡(luò)條件不可控,出現(xiàn)網(wǎng)絡(luò)分區(qū)是不可避免的,因此必須具備分區(qū)容錯(cuò)性,那么NameServer就是在AP還是CP中選擇了,由于NameServer之間相互獨(dú)立,很明顯,是一個(gè)AP設(shè)計(jì)。
之所以替換掉ZookeeperZooKeeper為分布式應(yīng)用程序提供協(xié)調(diào)服務(wù)。那為什么RocketMQ要自己造輪子,開發(fā)集群的管理程序呢?因?yàn)閆ooKeeper的功能很強(qiáng)大,包括自動(dòng)Master選舉等,RocketMQ的架構(gòu)設(shè)計(jì)決定了它不需要進(jìn)行Master選舉,用不到這些復(fù)雜的功能,只需要一個(gè)輕量級(jí)的元數(shù)據(jù)服務(wù)器就足夠了。
中間件對(duì)穩(wěn)定性要求很高,RocketMQ的NameServer只有很少的代碼,容易維護(hù),所以不需要再依賴另一個(gè)中間件,從而減少整體維護(hù)成本。
1.長(zhǎng)連接編程模型??跳的實(shí)現(xiàn)原理
2.多線程編程中讀寫鎖的經(jīng)典使??式
3.追求簡(jiǎn)單?效?可靠的實(shí)現(xiàn)?式
想要研究NameServer源代碼的,請(qǐng)點(diǎn)擊鏈接:https://github.com/MrChiu/Roc...
里面附有我標(biāo)注的注釋,易于通讀代碼
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/36013.html
摘要:故事中的下屬們,就是消息生產(chǎn)者角色,屋子右面墻根那塊地就是消息持久化,呂秀才就是消息調(diào)度中心,而你就是消息消費(fèi)者角色。下屬們匯報(bào)的消息,應(yīng)該疊放在哪里,這個(gè)消息又應(yīng)該在哪里才能找到,全靠呂秀才的驚人記憶力,才可以讓消息準(zhǔn)確的被投放以及消費(fèi)。 微信公眾號(hào):IT一刻鐘大型現(xiàn)實(shí)非嚴(yán)肅主義現(xiàn)場(chǎng)一刻鐘與你分享優(yōu)質(zhì)技術(shù)架構(gòu)與見聞,做一個(gè)有劇情的程序員關(guān)注可了解更多精彩內(nèi)容。問(wèn)題或建議,請(qǐng)公眾號(hào)留言...
摘要:所以基于目前的設(shè)計(jì),建議關(guān)閉自動(dòng)創(chuàng)建的功能,然后根據(jù)消息量的大小,手動(dòng)創(chuàng)建。如果發(fā)送消息,返回結(jié)果超時(shí),這種超時(shí)不會(huì)進(jìn)行重試了如果是方法本身耗時(shí)超過(guò),還未來(lái)得及調(diào)用發(fā)送消息,此時(shí)的超時(shí)也不會(huì)重試。 先來(lái)看下producer核心的類設(shè)計(jì),如下圖: showImg(http://pbdqyl9hh.bkt.clouddn.com/rocketmq/producer%E7%B1%BB%E5%...
摘要:它是阿里巴巴于年開源的第三代分布式消息中間件。是一個(gè)分布式消息中間件,具有低延遲高性能和可靠性萬(wàn)億級(jí)別的容量和靈活的可擴(kuò)展性,它是阿里巴巴于年開源的第三代分布式消息中間件。上篇文章消息隊(duì)列那么多,為什么建議深入了解下RabbitMQ?我們講到了消息隊(duì)列的發(fā)展史:并且詳細(xì)介紹了RabbitMQ,其功能也是挺強(qiáng)大的,那么,為啥又要搞一個(gè)RocketMQ出來(lái)呢?是重復(fù)造輪子嗎?本文我們就帶大家來(lái)詳...
摘要:當(dāng)接收到消息后,會(huì)在方法中調(diào)用方法,將的信息塞進(jìn)緩存中,并且會(huì)定時(shí)發(fā)送心跳將發(fā)送給進(jìn)行注冊(cè)。這也說(shuō)明了當(dāng)用集群模式去創(chuàng)建時(shí),集群里面每個(gè)的的數(shù)量相同,當(dāng)用單個(gè)模式去創(chuàng)建時(shí),每個(gè)的數(shù)量可以不一致。 微信公眾號(hào)「后端進(jìn)階」,專注后端技術(shù)分享:Java、Golang、WEB框架、分布式中間件、服務(wù)治理等等。 老司機(jī)傾囊相授,帶你一路進(jìn)階,來(lái)不及解釋了快上車! 我還記得第一次使用rocket...
摘要:前提通過(guò)前面兩篇文章可以簡(jiǎn)單的了解和安裝,今天就將和整合起來(lái)使用。然后我運(yùn)行之前的整合項(xiàng)目,查看監(jiān)控信息如下總結(jié)整篇文章講述了與整合和監(jiān)控平臺(tái)的搭建。 showImg(https://segmentfault.com/img/remote/1460000013232432?w=1920&h=1277); 前提 通過(guò)前面兩篇文章可以簡(jiǎn)單的了解 RocketMQ 和 安裝 RocketMQ...
閱讀 2494·2021-11-22 15:35
閱讀 3790·2021-11-04 16:14
閱讀 2720·2021-10-20 13:47
閱讀 2524·2021-10-13 09:49
閱讀 2094·2019-08-30 14:09
閱讀 2424·2019-08-26 13:49
閱讀 913·2019-08-26 10:45
閱讀 2799·2019-08-23 17:54