RocketMQ實(shí)戰(zhàn)生產(chǎn)環(huán)境中,autoCreateTopicEnable為什么不能設(shè)置為true

      網(wǎng)友投稿 1471 2022-05-29

      本節(jié)目錄

      1、現(xiàn)象

      2、思考

      3、原理

      3.1 RocketMQ基本路由規(guī)則

      3.2 探究autoCreateTopicEnable機(jī)制

      3.2.1 默認(rèn)Topic路由創(chuàng)建時(shí)機(jī)

      3.2.2 現(xiàn)象分析

      1、現(xiàn)象

      很多網(wǎng)友會問,為什么明明集群中有多臺Broker服務(wù)器,autoCreateTopicEnable設(shè)置為true,表示開啟Topic自動創(chuàng)建,但新創(chuàng)建的Topic的路由信息只包含在其中一臺Broker服務(wù)器上,這是為什么呢?

      期望值:為了消息發(fā)送的高可用,希望新創(chuàng)建的Topic在集群中的每臺Broker上創(chuàng)建對應(yīng)的隊(duì)列,避免Broker的單節(jié)點(diǎn)故障。

      現(xiàn)象截圖如下:

      正如上圖所示,自動創(chuàng)建的topicTest5的路由信息:

      topicTest5只在broker-a服務(wù)器上創(chuàng)建了隊(duì)列,并沒有在broker-b服務(wù)器創(chuàng)建隊(duì)列,不符合期望。

      默認(rèn)讀寫隊(duì)列的個(gè)數(shù)為4。

      我們再來看一下RocketMQ默認(rèn)topic的路由信息截圖如下:

      RocketMQ實(shí)戰(zhàn):生產(chǎn)環(huán)境中,autoCreateTopicEnable為什么不能設(shè)置為true

      從圖中可以默認(rèn)Topic的路由信息為broker-a、broker-b上各8個(gè)隊(duì)列。

      2、思考

      默認(rèn)Topic的路由信息是如何創(chuàng)建的?

      Topic的路由信息是存儲在哪里?Nameserver?broker?

      RocketMQ Topic默認(rèn)隊(duì)列個(gè)數(shù)是多少呢?

      3、原理

      3.1 RocketMQ基本路由規(guī)則

      Broker在啟動時(shí)向Nameserver注冊存儲在該服務(wù)器上的路由信息,并每隔30s向Nameserver發(fā)送心跳包,并更新路由信息。

      Nameserver每隔10s掃描路由表,如果檢測到Broker服務(wù)宕機(jī),則移除對應(yīng)的路由信息。

      消息生產(chǎn)者每隔30s會從Nameserver重新拉取Topic的路由信息并更新本地路由表;在消息發(fā)送之前,如果本地路由表中不存在對應(yīng)主題的路由消息時(shí),會主動向Nameserver拉取該主題的消息。

      回到本文的主題:autoCreateTopicEnable,開啟自動創(chuàng)建主題,試想一下,如果生產(chǎn)者向一個(gè)不存在的主題發(fā)送消息時(shí),上面的任何一個(gè)步驟都無法獲取一個(gè)不存在的主題的路由信息,那該如何處理這種情況呢?

      在RocketMQ中,如果autoCreateTopicEnable設(shè)置為true,消息發(fā)送者向NameServer查詢主題的路由消息返回空時(shí),會嘗試用一個(gè)系統(tǒng)默認(rèn)的主題名稱(MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC),此時(shí)消息發(fā)送者得到的路由信息為:

      但問題就來了,默認(rèn)Topic在集群的每一臺Broker上創(chuàng)建8個(gè)隊(duì)列,那問題來了,為啥新創(chuàng)建的Topic只在一個(gè)Broker上創(chuàng)建4個(gè)隊(duì)列?

      3.2 探究autoCreateTopicEnable機(jī)制

      溫馨提示:本文不會詳細(xì)跟蹤整個(gè)創(chuàng)建過程,只會點(diǎn)出源碼的關(guān)鍵入口點(diǎn),如想詳細(xì)了解NameServer路由消息、消息發(fā)送高可用的實(shí)現(xiàn)原理,建議查閱筆者的書籍《RocketMQ技術(shù)內(nèi)幕》第二、三章。

      Step1:在Broker啟動流程中,會構(gòu)建TopicConfigManager對象,其構(gòu)造方法中首先會判斷是否開啟了允許自動創(chuàng)建主題,如果啟用了自動創(chuàng)建主題,則向topicConfigTable中添加默認(rèn)主題的路由信息。

      TopicConfigManager構(gòu)造方法

      備注:該topicConfigTable中所有的路由信息,會隨著Broker向Nameserver發(fā)送心跳包中,Nameserver收到這些信息后,更新對應(yīng)Topic的路由信息表。

      BrokerConfig的defaultTopicQueueNum默認(rèn)為8。兩臺Broker服務(wù)器都會運(yùn)行上面的過程,故最終Nameserver中關(guān)于默認(rèn)主題的路由信息中,會包含兩個(gè)Broker分別各8個(gè)隊(duì)列信息。

      Step2:生產(chǎn)者尋找路由信息

      生產(chǎn)者首先向NameServer查詢路由信息,由于是一個(gè)不存在的主題,故此時(shí)返回的路由信息為空,RocketMQ會使用默認(rèn)的主題再次尋找,由于開啟了自動創(chuàng)建路由信息,NameServer會向生產(chǎn)者返回默認(rèn)主題的路由信息。然后從返回的路由信息中選擇一個(gè)隊(duì)列(默認(rèn)輪詢)。消息發(fā)送者從Nameserver獲取到默認(rèn)的Topic的隊(duì)列信息后,隊(duì)列的個(gè)數(shù)會改變嗎?答案是會的,其代碼如下:

      MQClientInstance#updateTopicRouteInfoFromNameServer

      溫馨提示:消息發(fā)送者在到默認(rèn)路由信息時(shí),其隊(duì)列數(shù)量,會選擇DefaultMQProducer#defaultTopicQueueNums與Nameserver返回的的隊(duì)列數(shù)取最小值,DefaultMQProducer#defaultTopicQueueNums默認(rèn)值為4,故自動創(chuàng)建的主題,其隊(duì)列數(shù)量默認(rèn)為4。

      Step3:發(fā)送消息

      DefaultMQProducerImpl#sendKernelImpl

      在消息發(fā)送時(shí)的請求報(bào)文中,設(shè)置默認(rèn)topic名稱,消息發(fā)送topic名稱,使用的隊(duì)列數(shù)量為DefaultMQProducer#defaultTopicQueueNums,即默認(rèn)為4。

      Step4:Broker端收到消息后的處理流程

      服務(wù)端收到消息發(fā)送的處理器為:SendMessageProcessor,在處理消息發(fā)送時(shí),會調(diào)用super.msgCheck方法:

      AbstractSendMessageProcessor#msgCheck

      在Broker端,首先會使用TopicConfigManager根據(jù)topic查詢路由信息,如果Broker端不存在該主題的路由配置(路由信息),此時(shí)如果Broker中存在默認(rèn)主題的路由配置信息,則根據(jù)消息發(fā)送請求中的隊(duì)列數(shù)量,在Broker創(chuàng)建新Topic的路由信息。這樣Broker服務(wù)端就會存在主題的路由信息。

      在Broker端的topic配置管理器中存在的路由信息,一會向Nameserver發(fā)送心跳包,匯報(bào)到Nameserver,另一方面會有一個(gè)定時(shí)任務(wù),定時(shí)存儲在broker端,具體路徑為${ROCKET_HOME}/store/config/topics.json中,這樣在Broker關(guān)閉后再重啟,并不會丟失路由信息。

      廣大讀者朋友,跟蹤到這一步的時(shí)候,大家應(yīng)該對啟用自動創(chuàng)建主題機(jī)制時(shí),新主題是的路由信息是如何創(chuàng)建的,為了方便理解,給出創(chuàng)建主題序列圖:

      經(jīng)過上面自動創(chuàng)建路由機(jī)制的創(chuàng)建流程,我們可以比較容易的分析得出如下結(jié)論:

      因?yàn)殚_啟了自動創(chuàng)建路由信息,消息發(fā)送者根據(jù)Topic去NameServer無法得到路由信息,但接下來根據(jù)默認(rèn)Topic從NameServer是能拿到路由信息(在每個(gè)Broker中,存在8個(gè)隊(duì)列),因?yàn)閮蓚€(gè)Broker在啟動時(shí)都會向NameServer匯報(bào)路由信息。此時(shí)消息發(fā)送者緩存的路由信息是2個(gè)Broker,每個(gè)Broker默認(rèn)4個(gè)隊(duì)列(原因見3.2.1:Step2的分析)。消息發(fā)送者然后按照輪詢機(jī)制,發(fā)送第一條消息選擇(broker-a的messageQueue:0),向Broker發(fā)送消息,Broker服務(wù)器在處理消息時(shí),首先會查看自己的路由配置管理器(TopicConfigManager)中的路由信息,此時(shí)不存在對應(yīng)的路由信息,然后嘗試查詢是否存在默認(rèn)Topic的路由信息,如果存在,說明啟用了autoCreateTopicEnable,則在TopicConfigManager中創(chuàng)建新Topic的路由信息,此時(shí)存在與Broker服務(wù)端的內(nèi)存中,然后本次消息發(fā)送結(jié)束。此時(shí),在NameServer中還不存在新創(chuàng)建的Topic的路由信息。

      這里有三個(gè)關(guān)鍵點(diǎn):

      啟用autoCreateTopicEnable創(chuàng)建主題時(shí),在Broker端創(chuàng)建主題的時(shí)機(jī)為,消息生產(chǎn)者往Broker端發(fā)送消息時(shí)才會創(chuàng)建。

      然后Broker端會在一個(gè)心跳包周期內(nèi),將新創(chuàng)建的路由信息發(fā)送到NameServer,于此同時(shí),Broker端還會有一個(gè)定時(shí)任務(wù),定時(shí)將內(nèi)存中的路由信息,持久化到Broker端的磁盤上。

      消息發(fā)送者會每隔30s向NameServer更新路由信息,如果消息發(fā)送端一段時(shí)間內(nèi)未發(fā)送消息,就不會有消息發(fā)送集群內(nèi)的第二臺Broker,那么NameServer中新創(chuàng)建的Topic的路由信息只會包含Broker-a,然后消息發(fā)送者會向NameServer拉取最新的路由信息,此時(shí)就會消息發(fā)送者原本緩存了2個(gè)broker的路由信息,將會變?yōu)橐粋€(gè)Broker的路由信息,則該Topic的消息永遠(yuǎn)不會發(fā)送到另外一個(gè)Broker,就出現(xiàn)了上述現(xiàn)象。

      原因就分析到這里了,現(xiàn)在我們還可以的大膽假設(shè),開啟autoCreateTopicEnable機(jī)制,什么情況會在兩個(gè)Broker上都創(chuàng)建隊(duì)列,其實(shí),我們只需要連續(xù)快速的發(fā)送9條消息,就有可能在2個(gè)Broker上都創(chuàng)建隊(duì)列,驗(yàn)證代碼如下:

      public static void main(String[] args) throws MQClientException, InterruptedException { DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); producer.setNamesrvAddr("127.0.0.1:9876"); producer.start(); for (int i = 0; i < 9; i++) { try { Message msg = new Message("TopicTest10" ,"TagA" , ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)); SendResult sendResult = producer.send(msg); System.out.printf("%s%n", sendResult); } catch (Exception e) { e.printStackTrace(); Thread.sleep(1000); } } producer.shutdown(); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      驗(yàn)證結(jié)果如圖所示:

      見文如面,我是威哥,熱衷于成體系剖析JAVA主流中間件,關(guān)注公眾號『中間件興趣圈』,回復(fù)專欄可獲取成體系專欄導(dǎo)航,回復(fù)資料可以獲取筆者的學(xué)習(xí)思維導(dǎo)圖。

      NAT

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:三步教你編寫一個(gè)Neumorphism風(fēng)格的小時(shí)鐘
      下一篇:Redis持久化之快照(RDB)
      相關(guān)文章
      亚洲AV无码一区二区三区久久精品 | 亚洲精品二区国产综合野狼| 亚洲人成7777| 亚洲AV无码久久久久网站蜜桃 | 亚洲天天在线日亚洲洲精| 久久精品亚洲综合| 亚洲AV无码一区二区乱子伦 | 久久亚洲精品中文字幕无码 | 亚洲AV无码成人精品区狼人影院| xxx毛茸茸的亚洲| 亚洲熟妇无码久久精品| 亚洲永久中文字幕在线| 91亚洲精品自在在线观看| 亚洲一级免费毛片| 亚洲欧美日韩自偷自拍| 亚洲国产av玩弄放荡人妇| 在线精品自拍亚洲第一区| 亚洲av无码天堂一区二区三区| 亚洲av午夜成人片精品电影| 亚洲日韩人妻第一页| 亚洲综合色自拍一区| 日本亚洲成高清一区二区三区| 亚洲成A∨人片在线观看不卡| 亚洲av激情无码专区在线播放| 亚洲尹人九九大色香蕉网站| 亚洲精品亚洲人成在线观看麻豆 | 精品国产亚洲一区二区在线观看| 国产亚洲精品福利在线无卡一| 亚洲宅男天堂在线观看无病毒| 国产∨亚洲V天堂无码久久久 | 亚洲avav天堂av在线网毛片| 午夜在线亚洲男人午在线| 久久久久亚洲精品无码网址 | 亚洲va中文字幕| 亚洲人成电影在线播放| 国产亚洲精品xxx| 亚洲精品第五页中文字幕| 亚洲 日韩 色 图网站| 在线观看国产一区亚洲bd| 国产偷窥女洗浴在线观看亚洲| 亚洲va久久久噜噜噜久久男同|