RocketMQ消息發(fā)送常見錯誤與解決方案

本文將結(jié)合自己使用RocketMQ的經(jīng)驗掀泳,對消息發(fā)送常見的問題進行分享况既,基本會遵循出現(xiàn)問題阅嘶,分析問題属瓣、解決問題载迄。

1、No route info of this topic

無法找到路由信息抡蛙,其完整的錯誤堆棧信息如下:

而且很多讀者朋友會說Broker端開啟了自動創(chuàng)建主題也會出現(xiàn)上述問題护昧。

RocketMQ的路由尋找流程如下圖所示:

上面的核心關(guān)鍵點如下:

如果Broker開啟了自動創(chuàng)建Topic,在啟動的時候會默認創(chuàng)建主題:TBW102粗截,并會隨著Broker發(fā)送到Nameserver的心跳包匯報給Nameserver惋耙,繼而從Nameserver查詢路由信息時能返回路由信息。

消息發(fā)送者在消息發(fā)送時首先會查本地緩存熊昌,如果本地緩存中存在绽榛,直接返回路由信息。

如果緩存不存在婿屹,則向Nameserver查詢路由信息灭美,如果Nameserver存在該路由信息,就直接返回昂利。

如果Nameserver不存在該topic的路由信息届腐,如果沒有開啟自動創(chuàng)建主題,則拋出 No route info of this topic蜂奸。

如果開啟了自動創(chuàng)建主題犁苏,則使用默認主題向Nameserver查詢路由信息,并使用默認Topic的路由信息為自己的路由信息窝撵,將不會拋出 No route info of this topic傀顾。

通常情況下 No route info of this topic 這個錯誤一般是在剛搭建RocketMQ,剛?cè)腴T RocketMQ遇到的比較多碌奉,通常的排查思路如下:

可以通過rocketmq-console查詢路由信息是否存在短曾,或使用如下命令查詢路由信息:

cd${ROCKETMQ_HOME}/binsh ./mqadmin topicRoute -n127.0.0.1:9876-t dw_test_0003

其輸出結(jié)果如下所示:

如果通過命令無法查詢到路由信息,則查看Broker是否開啟了自動創(chuàng)建topic赐劣,參數(shù)為:autoCreateTopicEnable,該參數(shù)默認為true嫉拐。但在生產(chǎn)環(huán)境不建議開啟。

如果開啟了自動創(chuàng)建路由信息魁兼,但還是拋出這個錯誤婉徘,這個時候請檢查客戶端(Producer)連接的Nameserver地址是否與Broker中配置的nameserver地址是否一致。

經(jīng)過上面的步驟咐汞,基本就能解決該錯誤盖呼。

2、消息發(fā)送超時

消息發(fā)送超時化撕,通臣肝睿客戶端的日志如下:

客戶端報消息發(fā)送超時,通常第一懷疑的對象是RocketMQ服務(wù)器植阴,是不是Broker性能出現(xiàn)了抖動蟹瘾,無法抗住當前的量圾浅。

那我們?nèi)绾蝸砼挪镽ocketMQ當前是否有性能瓶頸呢?

首先我們執(zhí)行如下命令查看RocketMQ 消息寫入的耗時分布情況:

cd/${USER.HOME}/logs/rocketmqlogs/grep -n'PAGECACHERT'store.log | more

輸出結(jié)果如下所示:

RocketMQ會每一分鐘打印前一分鐘內(nèi)消息發(fā)送的耗時情況分布憾朴,我們從這里就能窺探RocketMQ消息寫入是否存在明細的性能瓶頸狸捕,其區(qū)間如下:

[<=0ms] 小于0ms,即微妙級別的众雷。

[0~10ms] 小于10ms的個數(shù)灸拍。

[10~50ms] 大于10ms小

于50ms的個數(shù)

其他區(qū)間顯示,絕大多數(shù)會落在微妙級別完成砾省,按照筆者的經(jīng)驗如果100-200ms及以上的區(qū)間超過20個后株搔,說明Broker確實存在一定的瓶頸,如果只是少數(shù)幾個纯蛾,說明這個是內(nèi)存或pagecache的抖動,問題不大纵隔。

通常情況下超時通常與Broker端的處理能力關(guān)系不大翻诉,還有另外一個佐證,在RocketMQ broker中還存在快速失敗機制捌刮,即當Broker收到客戶端的請求后會將消息先放入隊列碰煌,然后順序執(zhí)行,如果一條消息隊列中等待超過200ms就會啟動快速失敗绅作,向客戶端返回[TIMEOUT_CLEAN_QUEUE]broker busy芦圾,這個在本文的第3部分會詳細介紹。

在RocketMQ客戶端遇到網(wǎng)絡(luò)超時俄认,通掣錾伲可以考慮一些應(yīng)用本身的垃圾回收,是否由于GC的停頓時間導(dǎo)致的消息發(fā)送超時眯杏,這個我在測試環(huán)境進行壓力測試時遇到過夜焦,但生產(chǎn)環(huán)境暫時沒有遇到過,大家稍微留意一下岂贩。

在RocketMQ中通常遇到網(wǎng)絡(luò)超時茫经,通常與網(wǎng)絡(luò)的抖動有關(guān)系,但由于我對網(wǎng)絡(luò)不是特別擅長萎津,故暫時無法找到直接證據(jù)卸伞,但能找到一些間接證據(jù),例如在一個應(yīng)用中同時連接了kafka锉屈、RocketMQ集群荤傲,發(fā)現(xiàn)在出現(xiàn)超時的同一時間發(fā)現(xiàn)連接到RocketMQ集群內(nèi)所有Broker,連接到kafka集群都出現(xiàn)了超時部念。

但出現(xiàn)網(wǎng)絡(luò)超時弃酌,我們總得解決氨菇,那有什么解決方案嗎?

我們對消息中間件的最低期望就是高并發(fā)低延遲妓湘,從上面的消息發(fā)送耗時分布情況也可以看出RocketMQ確實符合我們的期望查蓉,絕大部分請求都是在微妙級別內(nèi),故我給出的方案時榜贴,減少消息發(fā)送的超時時間,增加重試次數(shù)唬党,并增加快速失敗的最大等待時長鹃共。具體措施如下:

增加Broker端快速失敗的時長,建議為1000驶拱,在broker的配置文件中增加如下配置:

maxWaitTimeMillsInQueue=1000

主要原因是在當前的RocketMQ版本中霜浴,快速失敗導(dǎo)致的錯誤為SYSTEM_BUSY,并不會觸發(fā)重試蓝纲,適當增大該值阴孟,盡可能避免觸發(fā)該機制,詳情可以參考本文第3部分內(nèi)容税迷,會重點介紹system_busy永丝、broker_busy。

如果RocketMQ的客戶端版本為4.3.0以下版本(不含4.3.0)

將超時時間設(shè)置消息發(fā)送的超時時間為500ms箭养,并將重試次數(shù)設(shè)置為6次(這個可以適當進行調(diào)整慕嚷,盡量大于3),其背后的哲學(xué)是盡快超時毕泌,并進行重試喝检,因為發(fā)現(xiàn)局域網(wǎng)內(nèi)的網(wǎng)絡(luò)抖動是瞬時的,下次重試的是就能恢復(fù)懈词,并且RocketMQ有故障規(guī)避機制蛇耀,重試的時候會盡量選擇不同的Broker,相關(guān)的代碼如下:

DefaultMQProducer producer =newDefaultMQProducer("dw_test_producer_group");producer.setNamesrvAddr("127.0.0.1:9876");producer.setRetryTimesWhenSendFailed(5);// 同步發(fā)送模式:重試次數(shù)producer.setRetryTimesWhenSendAsyncFailed(5);// 異步發(fā)送模式:重試次數(shù)producer.start();producer.send(msg,500);//消息發(fā)送超時時間

如果RocketMQ的客戶端版本為4.3.0及以上版本

如果客戶端版本為4.3.0及其以上版本坎弯,由于其設(shè)置的消息發(fā)送超時時間為所有重試的總的超時時間纺涤,故不能直接通過設(shè)置RocketMQ的發(fā)送API的超時時間,而是需要對其API進行包裝抠忘,重試需要在外層收到進行撩炊,例如示例代碼如下:

publicstaticSendResultsend(DefaultMQProducer producer, Message msg,intretryCount){? Throwable e =null;for(inti =0; i < retryCount; i ++ ) {try{returnproducer.send(msg,500);//設(shè)置超時時間,為500ms崎脉,內(nèi)部有重試機制}catch(Throwable e2) {? ? ? ? ? e = e2;? ? ? }? }thrownewRuntimeException("消息發(fā)送異常",e);}

3拧咳、System busy、Broker busy

在使用RocketMQ中囚灼,如果RocketMQ集群達到1W/tps的壓力負載水平骆膝,System busy祭衩、Broker busy就會是大家經(jīng)常會遇到的問題。例如如下圖所示的異常棧阅签。

縱觀RocketMQ與system busy掐暮、broker busy相關(guān)的錯誤關(guān)鍵字,總共包含如下5個:

[REJECTREQUEST]system busy

too many requests and system thread pool busy

[PC_SYNCHRONIZED]broker busy

[PCBUSY_CLEAN_QUEUE]broker busy

[TIMEOUT_CLEAN_QUEUE]broker busy

3.1 原理分析

我們先用一張圖來闡述一下在消息發(fā)送的全生命周期中分別在什么時候會拋出上述錯誤政钟。

根據(jù)上述5類錯誤日志路克,其觸發(fā)的原有可以歸納為如下3種。

pagecache壓力較大

其中如下三類錯誤屬于此種情況

[REJECTREQUEST]system busy

[PC_SYNCHRONIZED]broker busy

[PCBUSY_CLEAN_QUEUE]broker busy

判斷pagecache是否忙的依據(jù)就是在寫入消息時养交,在向內(nèi)存追加消息時加鎖的時間精算,默認的判斷標準是加鎖時間超過1s,就認為是pagecache壓力大碎连,向客戶端拋出相關(guān)的錯誤日志灰羽。

發(fā)送線程池擠壓的拒絕策略

在RocketMQ中處理消息發(fā)送的是一個只有一個線程的線程池,內(nèi)部會維護一個有界隊列鱼辙,默認長度為1W谦趣,如果當前隊列中擠壓的數(shù)量超過1w,執(zhí)行線程池的拒絕策略座每,從而拋出[too many requests and system thread pool busy]錯誤。

Broker端快速失敗

默認情況下Broker端開啟了快速失敗機制摘悴,就是在Broker端還未發(fā)生pagecache繁忙(加鎖超過1s)的情況峭梳,但存在一些請求在消息發(fā)送隊列中等待200ms的情況,RocketMQ會不再繼續(xù)排隊蹂喻,直接向客戶端返回system busy葱椭,但由于rocketmq客戶端目前對該錯誤沒有進行重試處理,所以在解決這類問題的時候需要額外處理口四。

3.2 PageCache繁忙解決方案

一旦消息服務(wù)器出現(xiàn)大量pagecache繁忙(在向內(nèi)存追加數(shù)據(jù)加鎖超過1s)的情況孵运,這個是比較嚴重的問題,需要人為進行干預(yù)解決蔓彩,解決的問題思路如下:

transientStorePoolEnable

開啟transientStorePoolEnable機制治笨,即在broker中配置文件中增加如下配置:

transientStorePoolEnable=true

transientStorePoolEnable的原理如下圖所示:

引入transientStorePoolEnable能緩解pagecache的壓力背后關(guān)鍵如下:

消息先寫入到堆外內(nèi)存中,該內(nèi)存由于啟用了內(nèi)存鎖定機制赤嚼,故消息的寫入是接近直接操作內(nèi)存旷赖,性能能得到保證。

消息進入到堆外內(nèi)存后更卒,后臺會啟動一個線程等孵,一批一批將消息提交到pagecache,即寫消息時對pagecache的寫操作由單條寫入變成了批量寫入蹂空,降低了對pagecache的壓力俯萌。

引入transientStorePoolEnable會增加數(shù)據(jù)丟失的可能性果录,如果Broker JVM進程異常退出,提交到PageCache中的消息是不會丟失的咐熙,但存在堆外內(nèi)存(DirectByteBuffer)中但還未提交到PageCache中的這部分消息弱恒,將會丟失。但通常情況下糖声,RocketMQ進程退出的可能性不大斤彼,通常情況下,如果啟用了transientStorePoolEnable蘸泻,消息發(fā)送端需要有重新推送機制(補償思想)琉苇。

擴容

如果在開啟了transientStorePoolEnable后,還會出現(xiàn)pagecache級別的繁忙悦施,那需要集群進行擴容并扇,或者對集群中的topic進行拆分,即將一部分topic遷移到其他集群中抡诞,降低集群的負載穷蛹。

溫馨提示:在RocketMQ出現(xiàn)pagecache繁忙造成的broker busy,RocketMQ Client會有重試機制昼汗。

3.3 TIMEOUT_CLEAN_QUEUE 解決方案

由于如果出現(xiàn)TIMEOUT_CLEAN_QUEUE的錯誤肴熏,客戶端暫時不會對其進行重試,故現(xiàn)階段的建議是適當增加快速失敗的判斷標準顷窒,即在broker的配置文件中增加如下配置:

#該值默認為200蛙吏,表示200ms

waitTimeMillsInSendQueue=1000

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鞋吉,隨后出現(xiàn)的幾起案子鸦做,更是在濱河造成了極大的恐慌,老刑警劉巖谓着,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泼诱,死亡現(xiàn)場離奇詭異,居然都是意外死亡赊锚,警方通過查閱死者的電腦和手機治筒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舷蒲,“玉大人矢炼,你說我怎么就攤上這事“⑾耍” “怎么了句灌?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我胰锌,道長骗绕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任资昧,我火速辦了婚禮酬土,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘格带。我一直安慰自己撤缴,他們只是感情好,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布叽唱。 她就那樣靜靜地躺著屈呕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棺亭。 梳的紋絲不亂的頭發(fā)上虎眨,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音镶摘,去河邊找鬼嗽桩。 笑死,一個胖子當著我的面吹牛凄敢,可吹牛的內(nèi)容都是我干的碌冶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涝缝,長吁一口氣:“原來是場噩夢啊……” “哼种樱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起俊卤,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎害幅,沒想到半個月后消恍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡以现,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年狠怨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邑遏。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡佣赖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出记盒,到底是詐尸還是另有隱情憎蛤,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站俩檬,受9級特大地震影響萎胰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棚辽,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一技竟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屈藐,春花似錦榔组、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至遣妥,卻和暖如春擅编,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箫踩。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工爱态, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人境钟。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓锦担,卻偏偏與公主長得像,于是被迫代替她去往敵國和親慨削。 傳聞我的和親對象是個殘疾皇子洞渔,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容