Netty 原理+高性能

Netty 原理

Netty 是一個(gè)高性能捞奕、異步事件驅(qū)動(dòng)的NIO 框架唯蝶,基于JAVA NIO 提供的API 實(shí)現(xiàn)操软。它提供了對(duì)TCP雏胃、UDP 和文件傳輸?shù)闹С痔卟剑鳛橐粋€(gè)異步NIO 框架,Netty 的所有IO 操作都是異步非阻塞的丑掺,通過Future-Listener 機(jī)制获印,用戶可以方便的主動(dòng)獲取或者通過通知機(jī)制獲得IO 操作結(jié)果。

Netty 高性能

在IO 編程過程中街州,當(dāng)需要同時(shí)處理多個(gè)客戶端接入請(qǐng)求時(shí)兼丰,可以利用多線程或者IO 多路復(fù)用技術(shù)進(jìn)行處理。IO 多路復(fù)用技術(shù)通過把多個(gè)IO 的阻塞復(fù)用到同一個(gè)select 的阻塞上唆缴,從而使得系統(tǒng)在單線程的情況下可以同時(shí)處理多個(gè)客戶端請(qǐng)求鳍征。與傳統(tǒng)的多線程/多進(jìn)程模型比,I/O 多路復(fù)用的最大優(yōu)勢(shì)是系統(tǒng)開銷小面徽,系統(tǒng)不需要?jiǎng)?chuàng)建新的額外進(jìn)程或者線程艳丛,也不需要維護(hù)這些進(jìn)程和線程的運(yùn)行,降低了系統(tǒng)的維護(hù)工作量趟紊,節(jié)省了系統(tǒng)資源氮双。

與Socket 類和ServerSocket 類相對(duì)應(yīng),NIO也提供了SocketChannel 和ServerSocketChannel兩種不同的套接字通道實(shí)現(xiàn)霎匈。

多路復(fù)用的通訊方式

Netty 架構(gòu)按照Reactor 模式設(shè)計(jì)和實(shí)現(xiàn)戴差,它的服務(wù)端通信序列圖如下:

image.png

客戶端通信序列圖如下:

image.png

Netty 的IO 線程N(yùn)ioEventLoop 由于聚合了多路復(fù)用器Selector,可以同時(shí)并發(fā)處理成百上千個(gè)客戶端Channel铛嘱,由于讀寫操作都是非阻塞的暖释,這就可以充分提升IO 線程的運(yùn)行效率,避免由于頻繁IO 阻塞導(dǎo)致的線程掛起墨吓。

異步通信 NIO

由于Netty 采用了異步通信模式球匕,一個(gè)IO 線程可以并發(fā)處理N 個(gè)客戶端連接和讀寫操作,這從根本上解決了傳統(tǒng)同步阻塞IO 一連接一線程模型帖烘,架構(gòu)的性能亮曹、彈性伸縮能力和可靠性都得到了極大的提升。

零拷貝DIRECT BUFFERS (使用堆外直接內(nèi)存)

  1. Netty 的接收和發(fā)送ByteBuffer 采用DIRECT BUFFERS,使用堆外直接內(nèi)存進(jìn)行Socket 讀寫乾忱,不需要進(jìn)行字節(jié)緩沖區(qū)的二次拷貝讥珍。如果使用傳統(tǒng)的堆內(nèi)存(HEAP BUFFERS)進(jìn)行Socket 讀寫,JVM 會(huì)將堆內(nèi)存Buffer 拷貝一份到直接內(nèi)存中窄瘟,然后才寫入Socket 中衷佃。相比于堆外直接內(nèi)存,消息在發(fā)送過程中多了一次緩沖區(qū)的內(nèi)存拷貝蹄葱。
  2. Netty 提供了組合Buffer 對(duì)象氏义,可以聚合多個(gè)ByteBuffer 對(duì)象,用戶可以像操作一個(gè)Buffer 那樣方便的對(duì)組合Buffer 進(jìn)行操作图云,避免了傳統(tǒng)通過內(nèi)存拷貝的方式將幾個(gè)小Buffer 合并成一個(gè)大的Buffer惯悠。
  3. Netty 的文件傳輸采用了transferTo方法,它可以直接將文件緩沖區(qū)的數(shù)據(jù)發(fā)送到目標(biāo)Channel竣况,避免了傳統(tǒng)通過循環(huán)write 方式導(dǎo)致的內(nèi)存拷貝問題

內(nèi)存池(基于內(nèi)存池的緩沖區(qū)重用機(jī)制)

隨著JVM 虛擬機(jī)和JIT 即時(shí)編譯技術(shù)的發(fā)展克婶,對(duì)象的分配和回收是個(gè)非常輕量級(jí)的工作。但是對(duì)于緩沖區(qū)Buffer丹泉,情況卻稍有不同情萤,特別是對(duì)于堆外直接內(nèi)存的分配和回收,是一件耗時(shí)的操作摹恨。為了盡量重用緩沖區(qū)筋岛,Netty 提供了基于內(nèi)存池的緩沖區(qū)重用機(jī)制。

高效的 Reactor線程模型

常用的Reactor 線程模型有三種晒哄,Reactor 單線程模型, Reactor 多線程模型, 主從Reactor 多線程模型睁宰。

Reactor 單線程模型:
Reactor 單線程模型,指的是所有的IO 操作都在同一個(gè)NIO 線程上面完成寝凌,NIO 線程的職責(zé)如下:

  1. 作為NIO 服務(wù)端柒傻,接收客戶端的TCP 連接;
  2. 作為NIO 客戶端硫兰,向服務(wù)端發(fā)起TCP 連接诅愚;
  3. 讀取通信對(duì)端的請(qǐng)求或者應(yīng)答消息;
  4. 向通信對(duì)端發(fā)送消息請(qǐng)求或者應(yīng)答消息劫映。


    image.png

由于Reactor 模式使用的是異步非阻塞IO,所有的IO 操作都不會(huì)導(dǎo)致阻塞刹前,理論上一個(gè)線程可以獨(dú)立處理所有IO 相關(guān)的操作泳赋。從架構(gòu)層面看,一個(gè)NIO 線程確實(shí)可以完成其承擔(dān)的職責(zé)喇喉。例如祖今,通過Acceptor 接收客戶端的TCP 連接請(qǐng)求消息,鏈路建立成功之后,通過Dispatch 將對(duì)應(yīng)的ByteBuffer派發(fā)到指定的Handler 上進(jìn)行消息解碼千诬。用戶Handler 可以通過NIO 線程將消息發(fā)送給客戶端耍目。

Reactor 多線程模型
Rector 多線程模型與單線程模型最大的區(qū)別就是有一組NIO 線程處理IO 操作。 有專門一個(gè)NIO 線程-Acceptor 線程用于監(jiān)聽服務(wù)端徐绑,接收客戶端的TCP 連接請(qǐng)求邪驮; 網(wǎng)絡(luò)IO 操作-讀、寫等由一個(gè)NIO 線程池負(fù)責(zé)傲茄,線程池可以采用標(biāo)準(zhǔn)的JDK 線程池實(shí)現(xiàn)毅访,它包含一個(gè)任務(wù)隊(duì)列和N個(gè)可用的線程,由這些NIO 線程負(fù)責(zé)消息的讀取盘榨、解碼喻粹、編碼和發(fā)送;

image.png

主從Reactor多線程模型
服務(wù)端用于接收客戶端連接的不再是個(gè)1 個(gè)單獨(dú)的NIO 線程草巡,而是一個(gè)獨(dú)立的NIO 線程池守呜。
Acceptor 接收到客戶端TCP 連接請(qǐng)求處理完成后(可能包含接入認(rèn)證等),將新創(chuàng)建的
SocketChannel 注冊(cè)到IO 線程池(sub reactor 線程池)的某個(gè)IO 線程上山憨,由它負(fù)責(zé)
SocketChannel 的讀寫和編解碼工作弛饭。Acceptor 線程池僅僅只用于客戶端的登陸、握手和安全認(rèn)證萍歉,一旦鏈路建立成功侣颂,就將鏈路注冊(cè)到后端subReactor 線程池的IO 線程上,由IO 線程負(fù)責(zé)后續(xù)的IO 操作枪孩。


image.png

無鎖設(shè)計(jì)憔晒、線程鎖定

Netty 采用了串行無鎖化設(shè)計(jì),在IO 線程內(nèi)部進(jìn)行串行操作蔑舞,避免多線程競爭導(dǎo)致的性能下降拒担。表面上看,串行化設(shè)計(jì)似乎CPU 利用率不高攻询,并發(fā)程度不夠从撼。但是,通過調(diào)整NIO 線程池的線程參數(shù)钧栖,可以同時(shí)啟動(dòng)多個(gè)串行化的線程并行運(yùn)行低零,這種局部無鎖化的串行線程設(shè)計(jì)相比一個(gè)隊(duì)列-多個(gè)工作線程模型性能更優(yōu)。

image.png

Netty 的NioEventLoop 讀取到消息之后拯杠,直接調(diào)用ChannelPipeline 的fireChannelRead(Object msg)掏婶,只要用戶不主動(dòng)切換線程,一直會(huì)由NioEventLoop 調(diào)用到用戶的Handler潭陪,期間不進(jìn)行線程切換雄妥,這種串行化處理方式避免了多線程操作導(dǎo)致的鎖的競爭最蕾,從性能角度看是最優(yōu)的。

高性能的序列化框架

Netty 默認(rèn)提供了對(duì)Google Protobuf 的支持老厌,通過擴(kuò)展Netty 的編解碼接口瘟则,用戶可以實(shí)現(xiàn)其它的高性能序列化框架,例如Thrift 的壓縮二進(jìn)制編解碼框架枝秤。

  1. SO_RCVBUF 和SO_SNDBUF:通常建議值為128K 或者256K醋拧。
    小包封大包,防止網(wǎng)絡(luò)阻塞
  2. SO_TCPNODELAY:NAGLE 算法通過將緩沖區(qū)內(nèi)的小封包自動(dòng)相連宿百,組成較大的封包趁仙,阻止大量小封包的發(fā)送阻塞網(wǎng)絡(luò),從而提高網(wǎng)絡(luò)應(yīng)用效率垦页。但是對(duì)于時(shí)延敏感的應(yīng)用場景需要關(guān)閉該優(yōu)化算法雀费。
    軟中斷 Hash 值和 CPU 綁定
  3. 軟中斷:開啟RPS 后可以實(shí)現(xiàn)軟中斷,提升網(wǎng)絡(luò)吞吐量痊焊。RPS 根據(jù)數(shù)據(jù)包的源地址盏袄,目的地址以及目的和源端口,計(jì)算出一個(gè)hash 值薄啥,然后根據(jù)這個(gè)hash 值來選擇軟中斷運(yùn)行的cpu辕羽,從上層來看,也就是說將每個(gè)連接和cpu 綁定垄惧,并通過這個(gè)hash 值刁愿,來均衡軟中斷在多個(gè)cpu 上,提升網(wǎng)絡(luò)并行處理性能到逊。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铣口,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子觉壶,更是在濱河造成了極大的恐慌脑题,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铜靶,死亡現(xiàn)場離奇詭異叔遂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)争剿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門已艰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秒梅,你說我怎么就攤上這事旗芬。” “怎么了捆蜀?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我辆它,道長誊薄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任锰茉,我火速辦了婚禮呢蔫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘飒筑。我一直安慰自己片吊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布协屡。 她就那樣靜靜地躺著俏脊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肤晓。 梳的紋絲不亂的頭發(fā)上爷贫,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音补憾,去河邊找鬼漫萄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盈匾,可吹牛的內(nèi)容都是我干的腾务。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼削饵,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼岩瘦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起葵孤,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤担钮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后尤仍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箫津,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年宰啦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苏遥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赡模,死狀恐怖田炭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漓柑,我是刑警寧澤教硫,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布叨吮,位于F島的核電站,受9級(jí)特大地震影響瞬矩,放射性物質(zhì)發(fā)生泄漏茶鉴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一景用、第九天 我趴在偏房一處隱蔽的房頂上張望涵叮。 院中可真熱鬧,春花似錦伞插、人聲如沸割粮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舀瓢。三九已至,卻和暖如春杠步,著一層夾襖步出監(jiān)牢的瞬間氢伟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國打工幽歼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朵锣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓甸私,卻偏偏與公主長得像诚些,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皇型,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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