當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]RabbitMQ 的新文章總算寫好了。

不好意思,又好多天沒(méi)更文章了……

眼看著離過(guò)年越來(lái)越近了,很多工作都要在年前沖刺、收個(gè)尾。比如:工作總結(jié)、績(jī)效考核、獎(jiǎng)金、確定今年 KPI……

由于我負(fù)責(zé)的部門一百多人,雖然有下面的各位 Leader 幫忙,但是我的工作量還是很大的,每天一腦門子雜七雜八的事情,還有大大小小的各種會(huì)議……真沒(méi)時(shí)間輸出文章。

這不,在我的讀者群里,都被大家催更了。

幾年前,我擼了一套R(shí)abbitMQ的客戶端

幾年前,我擼了一套R(shí)abbitMQ的客戶端

在此感謝:

阿德、enjoy.day、Genos等等(不一一列舉了,我都記在心里了)各位老鐵催更。

RabbitMQ 的新文章總算寫好了。

我在上篇文章說(shuō)過(guò),如果使用 RabbitMQ,盡可能使用框架,而不要去使用 RabbitMQ 提供的 Java 版客戶端。

細(xì)說(shuō)起來(lái),其實(shí)還是因?yàn)?RabbitMQ 客戶端的使用有很多的注意事項(xiàng),稍微不注意,就容易翻車。

我是 2013 年就開始用起了 RabbitMQ,一路使用,一路和它一起成長(zhǎng)。當(dāng)時(shí),由于用的早,市面上也沒(méi)有特別成熟的 RabbitMQ 客戶端框架。所以,不得已之下,只好自己做了一套客戶端。

在這其中,正好也有了許多獨(dú)特的經(jīng)驗(yàn)也和大家分享一下,以免后來(lái)者陷入“后人哀之而不鑒之,亦使后人而復(fù)哀后人也”的套娃中。

一、那么,就先從網(wǎng)絡(luò)連接開始吧

1. 應(yīng)該長(zhǎng)久生存的連接

在 RabbitMQ 中,由于需要客戶端和服務(wù)器端進(jìn)行握手,所以導(dǎo)致客戶端和服務(wù)器端的連接如果要成功創(chuàng)建,需要很高的成本。

每一個(gè)連接的創(chuàng)建至少需要 7 個(gè) TCP 包,這還只是普通連接。如果需要 TLS 的參與,則 TCP 包會(huì)更多。

而且,RabbitMQ 中主要是以 Channel 方式通信,所以,每次創(chuàng)建完 Connection 網(wǎng)絡(luò)連接,還得創(chuàng)建 Channel,這又需要 2 個(gè) TCP 包。

如果,每次用完,再把連接關(guān)閉,首先還要關(guān)閉已經(jīng)創(chuàng)建的 Channel,這也需要 2 個(gè) TCP 包。

然后,再關(guān)閉已經(jīng)建立好的 Connection 連接,又需要 2 個(gè) TCP 包。

咱們算算,如果一個(gè)連接從創(chuàng)建到關(guān)閉,一共需要多少個(gè) TCP 包?

7 + 2 + 2 + 2 = 13

一共需要 13 個(gè)包。這個(gè)成本是很昂貴的。

所以,在 RabbitMQ 中,連接最好緩存起來(lái),重復(fù)使用更好。

2. Channel 還是獨(dú)占好

在 RabbitMQ 自己的客戶端中,Channel 出于性能原因,并不是線程安全的。

而如果咱們?yōu)榱司€程共用,給 Channel 人為的在外部加上鎖,本身就和 RabbitMQ 的 Channel 設(shè)計(jì)意圖是沖突的。

所以,最好的辦法就是一個(gè)線程一個(gè) Channel。

3. Channel 最好也別關(guān)

就像連接應(yīng)該緩存起來(lái)那樣,Channel 的打開和關(guān)閉也需要時(shí)間成本,而且沒(méi)有必要去重新創(chuàng)建 Channel,所以,Channel 也應(yīng)該緩存起來(lái)重用。

4. 別把消費(fèi)和發(fā)送的連接搞在一起

把消費(fèi)和發(fā)送的連接搞在一起,這是個(gè)很容易犯的錯(cuò)誤!

我們用 RabbitMQ 的時(shí)候,我們自己的系統(tǒng)本身大部分都是既要發(fā)消息也要收消息的。對(duì)于這種情況,有很多程序員走了極端:

他們覺(jué)得 RabbitMQ 連接成本高,所以省著用。于是就把發(fā)消息和收消息的連接混在一起,使用同一個(gè) TCP 連接。

這很可能會(huì)埋一個(gè)大雷。

因?yàn)椋?dāng)我們發(fā)消息很頻繁的時(shí)候,我們收消息也是走的同一個(gè) TCP 通道,收完了消息,客戶端還要給 RabbitMQ 服務(wù)器端一個(gè) ACK。

RabbitMQ 服務(wù)器端,對(duì)于每個(gè) TCP 連接都會(huì)分配專門的進(jìn)程,如果遇到這個(gè)進(jìn)程繁忙,這個(gè) ACK 很可能被丟棄,又或者等待處理的時(shí)間過(guò)長(zhǎng)。而這種情況又會(huì)導(dǎo)致 RabbitMQ 中的未確認(rèn)消息會(huì)被堆積的越來(lái)越多,影響到整套系統(tǒng)。

所以,消費(fèi)和發(fā)送的連接必須分開,各干各的事情。

5. 別搞太多連接和 Channel,RabbitMQ 的 Web 受不了

RabbitMQ 的 Web 插件會(huì)收集很多連接,和其對(duì)應(yīng) Channel 的相關(guān)數(shù)據(jù)。

如果連接和 Channel 堆積太多了,整個(gè) Web 打開會(huì)非常慢,幾乎無(wú)法對(duì) RabbitMQ 進(jìn)行管理。所以,要注意限制連接和 Channel 的數(shù)量。

二、消息很寶貴,千萬(wàn)別亂拋棄哦

用來(lái)通信的消息是很寶貴的。

因?yàn)槊織l消息都可能攜帶了關(guān)鍵的數(shù)據(jù)和信息。所以,保證消息不丟失,需要根據(jù)消息的重要性,采取很多的措施。

1. 小心,Queue 存在再發(fā)消息

一條消息,在 RabbitMQ 中會(huì)先發(fā)到 Exchange,再由 Exchange 交給對(duì)應(yīng)的 Queue。

而當(dāng) Queue 不存在,或者沒(méi)匹配到合適的 Queue 的時(shí)候,默認(rèn)就會(huì)把消息發(fā)到系統(tǒng)中的 /dev/null 中。

而且還不會(huì)報(bào)錯(cuò)。

這個(gè)坑當(dāng)年把我坑慘了!我猜這個(gè)坑無(wú)數(shù)人踩過(guò)吧。

所以,在發(fā)送消息的時(shí)候,最好通過(guò) declare passive 這種方法去探測(cè)下隊(duì)列是否存在,保證消息發(fā)送不會(huì)丟的莫名其妙。

2. 收到消息請(qǐng)告訴我

在使用 RabbitMQ 客戶端的時(shí)候,發(fā)送消息,一定要考慮使用 confirm 機(jī)制。

這個(gè)機(jī)制就是當(dāng)消息收到了,RabbitMQ 會(huì)往客戶端發(fā)送一個(gè)通知,客戶端收到這個(gè)通知后,如果存在一個(gè) confirm 處理器,那么就會(huì)回調(diào)這個(gè)處理器處理。這時(shí)候,我們就能確保消息是被中間件收到了。

所以,一定要考慮使用 confirm 處理器去確保消息被 RabbitMQ 服務(wù)器收到。

3. 有時(shí)候消息出了問(wèn)題我也需要知道

在某些業(yè)務(wù)里,可能需要知道消息發(fā)送失敗的場(chǎng)景,以便執(zhí)行失敗的處理邏輯。這時(shí)候,就要考慮 RabbitMQ 客戶端的 return 機(jī)制。

這個(gè)機(jī)制就是當(dāng)消息在服務(wù)器端路由的時(shí)候出現(xiàn)了錯(cuò)誤,比如沒(méi)有 Exchange、或者 RoutingKey 不存在,則 RabbitMQ 會(huì)返回一個(gè)響應(yīng)給客戶端。客戶端收到后會(huì)回調(diào) return 的處理器。這時(shí)候,客戶端所在系統(tǒng)就能感知到這種錯(cuò)誤了,從而進(jìn)行對(duì)應(yīng)的處理。

4. 為了一定不丟消息我也是拼了

還有的時(shí)候,消息需要處理強(qiáng)一致性這種事務(wù)性質(zhì)的業(yè)務(wù)。這時(shí)候,就必須開啟 RabbitMQ 的事務(wù)模式。但是,這個(gè)模式會(huì)導(dǎo)致整體 RabbitMQ 的性能下降 250 倍。

一般沒(méi)有必要,不建議開啟。

5. 把消息寫到磁盤上

一般來(lái)說(shuō),為了防止消息丟失,需要在 RabbitMQ 服務(wù)器收到消息的時(shí)候,先持久化消息到磁盤上,防止服務(wù)器狀態(tài)出現(xiàn)問(wèn)題,消息丟失。

但是,持久化消息,必須先持久化隊(duì)列,持久化隊(duì)列完還不行,還必須把消息的 delivery mode 設(shè)置為 2,這樣才能把消息存到磁盤。但是,這種行為會(huì)讓整個(gè) RabbitMQ 的性能下降 60%。

這種可以根據(jù)實(shí)際情況進(jìn)行抉擇。

三、對(duì)于收消息這件事,別由著性子來(lái)

1. 能一次拿多個(gè)干嘛要一次只拿一個(gè)

很多時(shí)候,一些 RabbitMQ 的新手,覺(jué)得如果在一個(gè) mainloop 類似的無(wú)限循環(huán)里,去主動(dòng)獲取消息,會(huì)更加及時(shí)的獲取到消息,也會(huì)擁有更加出色的性能。所以,他們會(huì)使用 get 這種行為去取代 consume 這種行為。

這時(shí)候,他們其實(shí)已經(jīng)踩進(jìn)了大坑。

為了能主動(dòng) get 服務(wù)器消息,很多新手會(huì)去寫一個(gè)無(wú)限循環(huán),然后不斷嘗試去 RabbitMQ 服務(wù)器端獲取消息。但是,get 方法,其實(shí)是只去獲取了隊(duì)列中的第一條消息。

而采用 consume 方式呢,它的默認(rèn)方式是只要有消息,就會(huì)批量的拿,直到拿光所有還沒(méi)消費(fèi)過(guò)的消息。

一個(gè)是一條條拿,一個(gè)是批量拿,哪個(gè)效率更高一目了然。

所以,盡量采用 consume 方式獲取消息。

2. 拿消息也要講方法論的

消費(fèi)消息的時(shí)候,其實(shí)最難掌握的就是:

一次我們到底要取多少條消息?

對(duì)于 RabbitMQ 來(lái)講,如果我們不對(duì)消費(fèi)行為做限制,他會(huì)有多少消息就獲取多少消息。這就造成了一個(gè)問(wèn)題:

如果消息過(guò)多,我們一次性把消息讀取到內(nèi)存,很可能就會(huì)把應(yīng)用的內(nèi)存擠崩掉。

所以,我們要對(duì)這種情況做一些限制。

這時(shí)候,需要限制一次獲取消息的數(shù)量,一般來(lái)講,當(dāng)我們的業(yè)務(wù)是異步發(fā)送,異步消費(fèi),不需要實(shí)時(shí)給回響應(yīng)的時(shí)候,經(jīng)驗(yàn)數(shù)據(jù)是一次獲取 1000 條。

當(dāng)然,系統(tǒng)和系統(tǒng)不一樣,硬件條件也不一樣,大家可以根據(jù)實(shí)際的情況來(lái)設(shè)置一次性獲取的消息數(shù)量。

重點(diǎn)要說(shuō)說(shuō)同步。

在很多時(shí)候,我們需要通過(guò) RabbitMQ 傳送消息,并能通過(guò)臨時(shí)隊(duì)列等技巧去實(shí)時(shí)返回處理結(jié)果。這時(shí)候,就沒(méi)辦法一次抓多條數(shù)據(jù)進(jìn)行處理了,因?yàn)椋邪l(fā)送端在等處理結(jié)果,依次處理,再依次返回,黃花菜都涼了。

而且大部分時(shí)候,這種同步等待響應(yīng)的業(yè)務(wù)是有順序要求的。所以,也不能并行同時(shí)抓出多條信息處理。那么,彼時(shí),設(shè)置每次只消費(fèi)一條消息就是理所應(yīng)當(dāng)?shù)牧恕?/span>

最后

從上面的內(nèi)容中,你也看到了,RabbitMQ 客戶端如果要使用,對(duì)新手是多可惡的一件事情,各種坑,各種復(fù)雜性。

所以,如果你覺(jué)得 Spring 之類的 AMQP 客戶端框架合你心意,那么你就使用它。

但是,Spring 的東西有個(gè)毛病,如果你要用它,你的應(yīng)用必須也都要用 Spring。有些時(shí)候,也沒(méi)有這種必要。這時(shí)候,你就可以根據(jù)我說(shuō)的這些注意事項(xiàng)和經(jīng)驗(yàn),自己開發(fā)一套 RabbitMQ 的封裝框架,去降低 RabbitMQ 的使用門檻。


免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉