久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

一步一圖,,走進(jìn) Netty 的世界

 瑤疏影 2021-03-18

來(lái)自:Hollis(作者:SessionBest)

原文鏈接(底部鏈接可直達(dá)):

https://cnblogs.com/sessionbest/p/9000727.html

1. Netty簡(jiǎn)介

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é)果。作為當(dāng)前最流行的NIO框架,,Netty在互聯(lián)網(wǎng)領(lǐng)域,、大數(shù)據(jù)分布式計(jì)算領(lǐng)域、游戲行業(yè),、通信行業(yè)等獲得了廣泛的應(yīng)用,,一些業(yè)界著名的開(kāi)源組件也基于Netty的NIO框架構(gòu)建。

2. Netty線程模型

在JAVA NIO方面Selector給Reactor模式提供了基礎(chǔ),,Netty結(jié)合Selector和Reactor模式設(shè)計(jì)了高效的線程模型,。先來(lái)看下Reactor模式:

2.1 Reactor模式

Wikipedia這么解釋Reactor模型:“The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.”。首先Reactor模式首先是事件驅(qū)動(dòng)的,,有一個(gè)或者多個(gè)并發(fā)輸入源,,有一個(gè)Server Handler和多個(gè)Request Handlers,這個(gè)Service Handler會(huì)同步的將輸入的請(qǐng)求多路復(fù)用的分發(fā)給相應(yīng)的Request Handler,??梢匀缦聢D所示:

Image

從結(jié)構(gòu)上有點(diǎn)類似生產(chǎn)者和消費(fèi)者模型,即一個(gè)或多個(gè)生產(chǎn)者將事件放入一個(gè)Queue中,,而一個(gè)或者多個(gè)消費(fèi)者主動(dòng)的從這個(gè)隊(duì)列中poll事件來(lái)處理,;而Reactor模式則沒(méi)有Queue來(lái)做緩沖,每當(dāng)一個(gè)事件輸入到Service Handler之后,,該Service Handler會(huì)主動(dòng)根據(jù)不同的Evnent類型將其分發(fā)給對(duì)應(yīng)的Request Handler來(lái)處理,。

2.2 Reator模式的實(shí)現(xiàn)

關(guān)于Java NIO 構(gòu)造Reator模式,Doug lea在《Scalable IO in Java》中給了很好的闡述,,這里截取PPT對(duì)Reator模式的實(shí)現(xiàn)進(jìn)行說(shuō)明

1.第一種實(shí)現(xiàn)模型如下:Image

這是最簡(jiǎn)單的Reactor單線程模型,,由于Reactor模式使用的是異步非阻塞IO,所有的IO操作都不會(huì)被阻塞,,理論上一個(gè)線程可以獨(dú)立處理所有的IO操作,。這時(shí)Reactor線程是個(gè)多面手,負(fù)責(zé)多路分離套接字,,Accept新連接,,并分發(fā)請(qǐng)求到處理鏈中。

對(duì)于一些小容量應(yīng)用場(chǎng)景,,可以使用到單線程模型,。但對(duì)于高負(fù)載,大并發(fā)的應(yīng)用卻不合適,,主要原因如下:

  1. 當(dāng)一個(gè)NIO線程同時(shí)處理成百上千的鏈路,,性能上無(wú)法支撐,,即使NIO線程的CPU負(fù)荷達(dá)到100%,也無(wú)法完全處理消息
  2. 當(dāng)NIO線程負(fù)載過(guò)重后,,處理速度會(huì)變慢,,會(huì)導(dǎo)致大量客戶端連接超時(shí),超時(shí)之后往往會(huì)重發(fā),,更加重了NIO線程的負(fù)載,。
  3. 可靠性低,一個(gè)線程意外死循環(huán),,會(huì)導(dǎo)致整個(gè)通信系統(tǒng)不可用

為了解決這些問(wèn)題,,出現(xiàn)了Reactor多線程模型。

2.Reactor多線程模型:Image

相比上一種模式,,該模型在處理鏈部分采用了多線程(線程池)。

在絕大多數(shù)場(chǎng)景下,,該模型都能滿足性能需求,。但是,在一些特殊的應(yīng)用場(chǎng)景下,,如服務(wù)器會(huì)對(duì)客戶端的握手消息進(jìn)行安全認(rèn)證,。這類場(chǎng)景下,單獨(dú)的一個(gè)Acceptor線程可能會(huì)存在性能不足的問(wèn)題,。為了解決這些問(wèn)題,,產(chǎn)生了第三種Reactor線程模型

3.Reactor主從模型Image

該模型相比第二種模型,是將Reactor分成兩部分,,mainReactor負(fù)責(zé)監(jiān)聽(tīng)server socket,,accept新連接;并將建立的socket分派給subReactor,。subReactor負(fù)責(zé)多路分離已連接的socket,,讀寫(xiě)網(wǎng)絡(luò)數(shù)據(jù),對(duì)業(yè)務(wù)處理功能,,其扔給worker線程池完成,。通常,subReactor個(gè)數(shù)上可與CPU個(gè)數(shù)等同,。

2.3 Netty模型

2.2中說(shuō)完了Reactor的三種模型,,那么Netty是哪一種呢?其實(shí)Netty的線程模型是Reactor模型的變種,,那就是去掉線程池的第三種形式的變種,,這也是Netty NIO的默認(rèn)模式。Netty中Reactor模式的參與者主要有下面一些組件:

  1. Selector
  2. EventLoopGroup/EventLoop
  3. ChannelPipeline

Selector即為NIO中提供的SelectableChannel多路復(fù)用器,,充當(dāng)著demultiplexer的角色,,這里不再贅述,;下面對(duì)另外兩種功能和其在Netty之Reactor模式中扮演的角色進(jìn)行介紹。

3.EventLoopGroup/EventLoop

當(dāng)系統(tǒng)在運(yùn)行過(guò)程中,,如果頻繁的進(jìn)行線程上下文切換,,會(huì)帶來(lái)額外的性能損耗。多線程并發(fā)執(zhí)行某個(gè)業(yè)務(wù)流程,,業(yè)務(wù)開(kāi)發(fā)者還需要時(shí)刻對(duì)線程安全保持警惕,,哪些數(shù)據(jù)可能會(huì)被并發(fā)修改,如何保護(hù),?這不僅降低了開(kāi)發(fā)效率,,也會(huì)帶來(lái)額外的性能損耗。

為了解決上述問(wèn)題,,Netty采用了串行化設(shè)計(jì)理念,,從消息的讀取、編碼以及后續(xù)Handler的執(zhí)行,,始終都由IO線程EventLoop負(fù)責(zé),,這就意外著整個(gè)流程不會(huì)進(jìn)行線程上下文的切換,數(shù)據(jù)也不會(huì)面臨被并發(fā)修改的風(fēng)險(xiǎn),。這也解釋了為什么Netty線程模型去掉了Reactor主從模型中線程池,。

EventLoopGroup是一組EventLoop的抽象,EventLoopGroup提供next接口,,可以總一組EventLoop里面按照一定規(guī)則獲取其中一個(gè)EventLoop來(lái)處理任務(wù),,對(duì)于EventLoopGroup這里需要了解的是在Netty中,在Netty服務(wù)器編程中我們需要BossEventLoopGroup和WorkerEventLoopGroup兩個(gè)EventLoopGroup來(lái)進(jìn)行工作,。通常一個(gè)服務(wù)端口即一個(gè)ServerSocketChannel對(duì)應(yīng)一個(gè)Selector和一個(gè)EventLoop線程,,也就是說(shuō)BossEventLoopGroup的線程數(shù)參數(shù)為1。BossEventLoop負(fù)責(zé)接收客戶端的連接并將SocketChannel交給WorkerEventLoopGroup來(lái)進(jìn)行IO處理,。

EventLoop的實(shí)現(xiàn)充當(dāng)Reactor模式中的分發(fā)(Dispatcher)的角色,。

4.ChannelPipeline

ChannelPipeline其實(shí)是擔(dān)任著Reactor模式中的請(qǐng)求處理器這個(gè)角色。

ChannelPipeline的默認(rèn)實(shí)現(xiàn)是DefaultChannelPipeline,,DefaultChannelPipeline本身維護(hù)著一個(gè)用戶不可見(jiàn)的tail和head的ChannelHandler,,他們分別位于鏈表隊(duì)列的頭部和尾部。tail在更上層的部分,,而head在靠近網(wǎng)絡(luò)層的方向,。在Netty中關(guān)于ChannelHandler有兩個(gè)重要的接口,ChannelInBoundHandler和ChannelOutBoundHandler,。inbound可以理解為網(wǎng)絡(luò)數(shù)據(jù)從外部流向系統(tǒng)內(nèi)部,,而outbound可以理解為網(wǎng)絡(luò)數(shù)據(jù)從系統(tǒng)內(nèi)部流向系統(tǒng)外部。用戶實(shí)現(xiàn)的ChannelHandler可以根據(jù)需要實(shí)現(xiàn)其中一個(gè)或多個(gè)接口,,將其放入Pipeline中的鏈表隊(duì)列中,,ChannelPipeline會(huì)根據(jù)不同的IO事件類型來(lái)找到相應(yīng)的Handler來(lái)處理,,同時(shí)鏈表隊(duì)列是責(zé)任鏈模式的一種變種,自上而下或自下而上所有滿足事件關(guān)聯(lián)的Handler都會(huì)對(duì)事件進(jìn)行處理,。

ChannelInBoundHandler對(duì)從客戶端發(fā)往服務(wù)器的報(bào)文進(jìn)行處理,,一般用來(lái)執(zhí)行半包/粘包,解碼,,讀取數(shù)據(jù),,業(yè)務(wù)處理等;ChannelOutBoundHandler對(duì)從服務(wù)器發(fā)往客戶端的報(bào)文進(jìn)行處理,,一般用來(lái)進(jìn)行編碼,,發(fā)送報(bào)文到客戶端。

下圖是對(duì)ChannelPipeline執(zhí)行過(guò)程的說(shuō)明:Image

關(guān)于Pipeline的更多知識(shí)可參考:[淺談管道模型(Pipeline)](http://blog.csdn.net/yanghua_kobe/article/details/7561016 淺談管道模型(Pipeline))

5.Buffer

Netty提供的經(jīng)過(guò)擴(kuò)展的Buffer相對(duì)NIO中的有個(gè)許多優(yōu)勢(shì),,作為數(shù)據(jù)存取非常重要的一塊,,我們來(lái)看看Netty中的Buffer有什么特點(diǎn)。

1.ByteBuf讀寫(xiě)指針

  • 在ByteBuffer中,,讀寫(xiě)指針都是position,,而在ByteBuf中,讀寫(xiě)指針?lè)謩e為readerIndex和writerIndex,,直觀看上去ByteBuffer僅用了一個(gè)指針就實(shí)現(xiàn)了兩個(gè)指針的功能,,節(jié)省了變量,,但是當(dāng)對(duì)于ByteBuffer的讀寫(xiě)狀態(tài)切換的時(shí)候必須要調(diào)用flip方法,,而當(dāng)下一次寫(xiě)之前,必須要將Buffe中的內(nèi)容讀完,,再調(diào)用clear方法,。每次讀之前調(diào)用flip,寫(xiě)之前調(diào)用clear,,這樣無(wú)疑給開(kāi)發(fā)帶來(lái)了繁瑣的步驟,,而且內(nèi)容沒(méi)有讀完是不能寫(xiě)的,這樣非常不靈活,。相比之下我們看看ByteBuf,,讀的時(shí)候僅僅依賴readerIndex指針,寫(xiě)的時(shí)候僅僅依賴writerIndex指針,,不需每次讀寫(xiě)之前調(diào)用對(duì)應(yīng)的方法,,而且沒(méi)有必須一次讀完的限制。

2.零拷貝

  • 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)存拷貝,。
  • Netty提供了組合Buffer對(duì)象,,可以聚合多個(gè)ByteBuffer對(duì)象,用戶可以像操作一個(gè)Buffer那樣方便的對(duì)組合Buffer進(jìn)行操作,,避免了傳統(tǒng)通過(guò)內(nèi)存拷貝的方式將幾個(gè)小Buffer合并成一個(gè)大的Buffer,。
  • Netty的文件傳輸采用了transferTo方法,它可以直接將文件緩沖區(qū)的數(shù)據(jù)發(fā)送到目標(biāo)Channel,,避免了傳統(tǒng)通過(guò)循環(huán)write方式導(dǎo)致的內(nèi)存拷貝問(wèn)題,。

3.引用計(jì)數(shù)與池化技術(shù)

  • 在Netty中,每個(gè)被申請(qǐng)的Buffer對(duì)于Netty來(lái)說(shuō)都可能是很寶貴的資源,,因此為了獲得對(duì)于內(nèi)存的申請(qǐng)與回收更多的控制權(quán),,Netty自己根據(jù)引用計(jì)數(shù)法去實(shí)現(xiàn)了內(nèi)存的管理。Netty對(duì)于Buffer的使用都是基于直接內(nèi)存(DirectBuffer)實(shí)現(xiàn)的,,大大提高I/O操作的效率,,然而DirectBuffer和HeapBuffer相比之下除了I/O操作效率高之外還有一個(gè)天生的缺點(diǎn),即對(duì)于DirectBuffer的申請(qǐng)相比HeapBuffer效率更低,,因此Netty結(jié)合引用計(jì)數(shù)實(shí)現(xiàn)了PolledBuffer,,即池化的用法,當(dāng)引用計(jì)數(shù)等于0的時(shí)候,,Netty將Buffer回收致池中,,在下一次申請(qǐng)Buffer的沒(méi)某個(gè)時(shí)刻會(huì)被復(fù)用。

總結(jié)

Netty其實(shí)本質(zhì)上就是Reactor模式的實(shí)現(xiàn),,Selector作為多路復(fù)用器,,EventLoop作為轉(zhuǎn)發(fā)器,Pipeline作為事件處理器,。但是和一般的Reactor不同的是,,Netty使用串行化實(shí)現(xiàn),并在Pipeline中使用了責(zé)任鏈模式,。

Netty中的buffer相對(duì)有NIO中的buffer又做了一些優(yōu)化,,大大提高了性能。

了不起的程序員
了不起的程序員
The Great Developer
17篇原創(chuàng)內(nèi)容
Official Account

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多