深入理解Spring中RabbitMQ的Channel
概述
在 AMQP 協(xié)議中,有 channel 的概念,在 RabbitMq 中, channel 表示邏輯連接或者叫虛擬連接,是棣屬于 TCP 連接的。
一個(gè) TCP 連接里可以創(chuàng)建多個(gè) channel ,在 Rabbit MQ 里,消息的發(fā)送和接收都是基于 channel 的。
有了 TCP 連接后,還需要 channel 的原因如下:
- 創(chuàng)建和銷毀TCP連接很耗時(shí);
- 打開太多TCP連接,耗操作系統(tǒng)資源,并發(fā)量大到一定程度,系統(tǒng)的吞吐量會(huì)降低;
- 使用一個(gè)connection多channel的方式,可以提升連接的利用率。
因此采用多個(gè) channel 多路復(fù)用一個(gè) TCP 連接的方式才比較合理。
channel線程不安全
channel 不是線程安全的,線程并發(fā)的去訪問同一個(gè) channel 會(huì)出問題。
這里有幾種處理方式:
- 全局公用一個(gè)channel且使用全局鎖,讓操作channel排隊(duì).這種明顯性能是不行的;
- 一個(gè)線程對(duì)應(yīng)創(chuàng)建一個(gè)新的channel,但是要處理好一個(gè)連接能支撐的最大channel數(shù)量;
- 一個(gè)線程對(duì)應(yīng)一個(gè)channel,但是是從channel池子拿的,不是每次都創(chuàng)建新的.一旦一個(gè)線程完成了一個(gè)channel的使用,它將返回到池中,從而使該channel可用于另一個(gè)線程。
量不大的話,使用第二種方式就可以了。量大的話,建議使用第三種方式,畢竟創(chuàng)建和銷毀 channel 也是耗時(shí)耗資源的.在 spring amqp 中,提供了一個(gè)緩存 channel 的方案。
可以在創(chuàng)建 CachingConnectionFactory 時(shí)指定緩存的模式。
connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL); connectionFactory.setChannelCacheSize(25);
上面的兩行代碼,表示 channel 共用唯一的一個(gè)連接,且緩存了25個(gè) channel ,注意這里的25個(gè)并不是說,這個(gè)連接里只能最多創(chuàng)建25個(gè) channel ,而是說最多緩存25個(gè) channel 。舉個(gè)例子,假設(shè)并發(fā)發(fā)送100條消息,在 CachingConnectionFactory.CacheMode.CHANNEL 模式下,瞬間會(huì)創(chuàng)建100個(gè) channel 的,然后往緩存里放25個(gè) channel ,當(dāng)流量下去了,剛剛創(chuàng)建的多余的 channel 會(huì)自動(dòng)關(guān)閉掉的,緩存里只保留25個(gè)。
使用這種方式的話,要注意緩存的 channel 數(shù)量,不能太小,不然流量一大,仍然會(huì)造成頻繁關(guān)閉 channel 的情況。當(dāng)然我們也不能說有多少并發(fā),就創(chuàng)建多少個(gè) channel ,還是要限制一下,這個(gè)時(shí)候可以使用:
connectionFactory.setChannelCheckoutTimeout(1000);
當(dāng) ChannelCheckoutTimeout 的值大于0的時(shí)候, ChannelCacheSize 的值就是最大的 channel 數(shù)量了,一旦從緩存中獲取不到 channel ,等待 ChannelCheckoutTimeout 毫秒后,如果還是獲取不到的,就會(huì)拋 AmqpTimeoutException 了。
我們也可以自己實(shí)現(xiàn) channel pool ,但是不太建議怎么做,畢竟 spring amqp 還是相當(dāng)成熟的,直接使用就可以了。
CacheMode.CHANNEL模式性能
如上文所述,采用了 CacheMode.CHANNEL 的模式的話,就是一線程一 channel 形式,且這些 channel 共享了同一個(gè)連接,也即是共享同一個(gè) socket
當(dāng)并發(fā)量一大的時(shí)候,可能導(dǎo)致同一時(shí)刻,多個(gè)線程都想往這個(gè) socket 上寫數(shù)據(jù)。
為了避免這種情況,只能加鎖,讓拿不到鎖的線程 block 住。做了壓力測試,并發(fā)10個(gè)線程發(fā)送1000000條消息,結(jié)果線程被 block 住了,如下圖:
作者也提到,當(dāng)流量很大的時(shí)候,使用 CacheMode.CONNECTION 的模式,可以提高發(fā)送效率。
channel的監(jiān)控
RabbitMQ Admin UI 提供了一個(gè)監(jiān)控 channel 的界面,我們主要關(guān)注兩點(diǎn):
channel有沒有可能泄露,打開了channel,卻沒有關(guān)閉channel;打開channel和關(guān)閉channel的速率。
如果通道打開操作的速率始終高于通道關(guān)閉操作的速率,那就可能發(fā)生 channel 泄露了。
如下圖:
如果打開和關(guān)閉 channel 的速率都很高,也值得觀察一下。因?yàn)榭赡苁菦]有緩存 channel 了。
當(dāng)流量繼續(xù)增大的時(shí)候,可能會(huì)出現(xiàn)吞吐量上不去的情況,如下圖:
到此這篇關(guān)于深入理解Spring中RabbitMQ的Channel的文章就介紹到這了,更多相關(guān)RabbitMQ的Channel內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)特定范圍的完數(shù)輸出算法示例
這篇文章主要介紹了Java實(shí)現(xiàn)特定范圍的完數(shù)輸出算法,簡單說明了完數(shù)的概念、計(jì)算原理并結(jié)合實(shí)例形式分析了java針對(duì)給定范圍內(nèi)的完數(shù)輸出操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-12-12java對(duì)xml節(jié)點(diǎn)屬性的增刪改查實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava對(duì)xml節(jié)點(diǎn)屬性的增刪改查實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-10-10在已有spring的基礎(chǔ)上集成hibernate的實(shí)例講解
下面小編就為大家?guī)硪黄谝延衧pring的基礎(chǔ)上集成hibernate的實(shí)例講解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11java開發(fā)CPU流水線與指令亂序執(zhí)行詳解
這篇文章主要為大家介紹了java開發(fā)CPU流水線與指令亂序執(zhí)行詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09