溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少

發(fā)布時(shí)間:2020-05-30 07:33:33 來(lái)源:網(wǎng)絡(luò) 閱讀:418 作者:颯拉阿依醬 欄目:編程語(yǔ)言

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

Netty 高性能
在 IO 編程過(guò)程中,當(dāng)需要同時(shí)處理多個(gè)客戶端接入請(qǐng)求時(shí),可以利用多線程或者 IO 多路復(fù)用技術(shù)進(jìn)行處理。IO 多路復(fù)用技術(shù)通過(guò)把多個(gè) IO 的阻塞復(fù)用到同一個(gè) select 的阻塞上,從而使得系統(tǒng)在單線程的情況下可以同時(shí)處理多個(gè)客戶端請(qǐng)求。與傳統(tǒng)的多線程/多進(jìn)程模型比,I/O 多路復(fù)用的最大優(yōu)勢(shì)是系統(tǒng)開(kāi)銷小,系統(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ù)端通信序列圖如下:

那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少
客戶端通信序列圖如下:
那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少
Netty 的 IO 線程 NioEventLoop 由于聚合了多路復(fù)用器 Selector,可以同時(shí)并發(fā)處理成百上千個(gè)客戶端 Channel,由于讀寫(xiě)操作都是非阻塞的,這就可以充分提升 IO 線程的運(yùn)行效率,避免由于頻繁 IO 阻塞導(dǎo)致的線程掛起。

異步通訊 NIO

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

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

  1. Netty 的接收和發(fā)送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接內(nèi)存進(jìn)行 Socket 讀寫(xiě),不需要進(jìn)行字節(jié)緩沖區(qū)的二次拷貝。如果使用傳統(tǒng)的堆內(nèi)存(HEAP BUFFERS)進(jìn)行 Socket 讀寫(xiě),JVM 會(huì)將堆內(nèi)存 Buffer 拷貝一份到直接內(nèi)存中,然后才寫(xiě)入 Socket 中。相比于堆外直接內(nèi)存,消息在發(fā)送過(guò)程中多了一次緩沖區(qū)的內(nèi)存拷貝。

  2. Netty 提供了組合 Buffer 對(duì)象,可以聚合多個(gè) ByteBuffer 對(duì)象,用戶可以像操作一個(gè) Buffer 那樣方便的對(duì)組合 Buffer 進(jìn)行操作,避免了傳統(tǒng)通過(guò)內(nèi)存拷貝的方式將幾個(gè)小 Buffer 合并成一個(gè)大的Buffer。

  3. Netty的文件傳輸采用了transferTo方法,它可以直接將文件緩沖區(qū)的數(shù)據(jù)發(fā)送到目標(biāo)Channel,避免了傳統(tǒng)通過(guò)循環(huán) write 方式導(dǎo)致的內(nèi)存拷貝問(wèn)題內(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)答消息。

那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少

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

Reactor 多線程模型

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

那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少
主從 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 的讀寫(xiě)和編解碼工作。Acceptor 線程池僅僅只用于客戶端的登陸、握手和安全認(rèn)證,一旦鏈路建立成功,就將鏈路注冊(cè)到后端 subReactor 線程池的 IO 線程上,由 IO 線程負(fù)責(zé)后續(xù)的 IO 操作。
那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少

無(wú)鎖設(shè)計(jì)、線程綁定

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

那些與Netty有關(guān)的知識(shí)點(diǎn),你知道多少
Netty 的 NioEventLoop 讀取到消息之后,直接調(diào)用 ChannelPipeline 的fireChannelRead(Object msg),只要用戶不主動(dòng)切換線程,一直會(huì)由 NioEventLoop 調(diào)用到用戶的 Handler,期間不進(jìn)行線程切換,這種串行化處理方式避免了多線程操作導(dǎo)致的鎖的競(jìng)爭(zhēng),從性能角度看是最優(yōu)的。

高性能的序列化框架

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

  1. SO_RCVBUF 和 SO_SNDBUF:通常建議值為 128K 或者 256K。

小包封大包,防止網(wǎng)絡(luò)阻塞

  1. SO_TCPNODELAY:NAGLE 算法通過(guò)將緩沖區(qū)內(nèi)的小封包自動(dòng)相連,組成較大的封包,阻止大量小封包的發(fā)送阻塞網(wǎng)絡(luò),從而提高網(wǎng)絡(luò)應(yīng)用效率。但是對(duì)于時(shí)延敏感的應(yīng)用場(chǎng)景需要關(guān)閉該優(yōu)化算法。

軟中斷 Hash 值和 CPU 綁定

  1. 軟中斷:開(kāi)啟 RPS 后可以實(shí)現(xiàn)軟中斷,提升網(wǎng)絡(luò)吞吐量。RPS 根據(jù)數(shù)據(jù)包的源地址,目的地址以及目的和源端口,計(jì)算出一個(gè) hash 值,然后根據(jù)這個(gè) hash 值來(lái)選擇軟中斷運(yùn)行的 cpu,從上層來(lái)看,也就是說(shuō)將每個(gè)連接和 cpu 綁定,并通過(guò)這個(gè) hash 值,來(lái)均衡軟中斷在多個(gè) cpu 上,提升網(wǎng)絡(luò)并行處理性能。

持續(xù)更新中…………

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI