Netty出现的原因以及多种Reactor模式
一、原生NIO存在的問(wèn)題
NIO的類庫(kù)與API繁雜,需要熟練掌握Selector、ServerSocketChannel、SocketChannel、Bytebuffer等要求熟悉Java多線程編程和網(wǎng)絡(luò)編程開(kāi)發(fā)工作量和難度大,例如客戶端面臨斷連重連、網(wǎng)絡(luò)閃斷、半包讀寫、失敗緩存、網(wǎng)絡(luò)擁塞和異常流的處理等。JDK NIO的BUG:例如Epoll Bug,它會(huì)導(dǎo)致Selector空輪詢,最終導(dǎo)致CPU占用100%,到JDK1.7還未被有效解決
二、Netty說(shuō)明
Netty是由JBOSS提供的一個(gè)Java開(kāi)源框架。Netty提供異步的、基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,用以快速開(kāi)發(fā)高性能、高可靠的網(wǎng)絡(luò)IO程序。Netty可以幫助你快速、簡(jiǎn)單的開(kāi)發(fā)一個(gè)網(wǎng)絡(luò)應(yīng)用,相當(dāng)于簡(jiǎn)化和流程化了NIO的開(kāi)發(fā)過(guò)程。Netty是目前最流行的NIO框架,在互聯(lián)網(wǎng)領(lǐng)域、大數(shù)據(jù)分布式計(jì)算領(lǐng)域、游戲行業(yè)、通信行業(yè)等獲得了廣泛的應(yīng)用,Elasticsearch、Dubbo框架內(nèi)部都采用了Netty
三、Netty線程模型介紹
- 傳統(tǒng)阻塞I/O服務(wù)模型;
- Reactor模式(反應(yīng)器模型)
-
1)單Reactor單線程
-
2)單Reactor多線程
-
3)主從Reactor多線程
- 傳統(tǒng)阻塞IO服務(wù)模型
- 1、模型特點(diǎn)
采用阻塞IO獲取輸入的數(shù)據(jù) 每個(gè)連接都需要獨(dú)立的線程完成數(shù)據(jù)的輸入、業(yè)務(wù)處理、數(shù)據(jù)返回
- 2、問(wèn)題分析
當(dāng)并發(fā)數(shù)很大時(shí),會(huì)創(chuàng)建大量的線程,占用很大的系統(tǒng)資源,連接創(chuàng)建后,如果當(dāng)前線程暫時(shí)沒(méi)有數(shù)據(jù)可讀,該線程會(huì)阻塞在read操作上,造成線程資源浪費(fèi)
- 3、解決方案
基于IO復(fù)用模型:多個(gè)連接共用一個(gè)阻塞對(duì)象,應(yīng)用程序只需要在一個(gè)阻塞對(duì)象等待,無(wú)需阻塞所有連接,當(dāng)某個(gè)連接有新的數(shù)據(jù)可以處理時(shí),操作系統(tǒng)通知應(yīng)用程序,線程從阻塞狀態(tài)返回,開(kāi)始進(jìn)行業(yè)務(wù)處理?;诰€程池復(fù)用線程資源:不必為每一個(gè)連接創(chuàng)建線程,將連接完成后的業(yè)務(wù)處理任務(wù)分配給線程進(jìn)行處理,一個(gè)線程可以處理多個(gè)連接的業(yè)務(wù)
- Reactor模式(反應(yīng)器、分發(fā)者、通知者模式)
- 1、工作原理及說(shuō)明
Reactor模式,通過(guò)一個(gè)或多個(gè)輸入同時(shí)傳遞給服務(wù)器處理的模式(基于事件驅(qū)動(dòng)),服務(wù)器端程序處理傳入的多個(gè)請(qǐng)求,并將它們同步分派到相應(yīng)的處理線程。 Reactor模式使用了IO復(fù)用監(jiān)聽(tīng)事件,受到事件后分發(fā)給某個(gè)線程(進(jìn)程),網(wǎng)絡(luò)服務(wù)高并發(fā)處理的關(guān)鍵
-
2、核心組成
-
Reactor:在一個(gè)單獨(dú)的線程中運(yùn)行,負(fù)責(zé)監(jiān)聽(tīng)和分發(fā)事件,分發(fā)給適當(dāng)?shù)奶幚沓绦驅(qū)O事件作出反應(yīng)
-
Handlers:處理程序執(zhí)行IO事件要完成的實(shí)際事件。Reactor通過(guò)調(diào)用適當(dāng)?shù)奶幚沓绦騺?lái)響應(yīng)IO事件,處理程序非阻塞操作。
-
單Reactor單線程
1、工作原理及說(shuō)明
- Select是前面IO復(fù)用模型介紹的標(biāo)準(zhǔn)網(wǎng)絡(luò)編程API,可以實(shí)現(xiàn)應(yīng)用程序通過(guò)一個(gè)阻塞對(duì)象監(jiān)聽(tīng)多路連接請(qǐng)求;
- Reactor對(duì)象通過(guò)Select監(jiān)控客戶端請(qǐng)求事件,收到事件后通過(guò)Dispatch進(jìn)行分發(fā);
- 如果建立連接請(qǐng)求事件,則由Acceptor通過(guò)Accept處理連接請(qǐng)求,然后創(chuàng)建一個(gè)Handler對(duì)象處理連接完成后的后續(xù)業(yè)務(wù)處理;
- 如果不是建立連接事件,則Reactor會(huì)分發(fā)給調(diào)用連接對(duì)應(yīng)的Handler來(lái)響應(yīng);
- Handler會(huì)完成Read—>業(yè)務(wù)處理—>Send的完整業(yè)務(wù)流程;
2、優(yōu)缺點(diǎn)分析
- 優(yōu)點(diǎn):模型簡(jiǎn)單,無(wú)多線程、進(jìn)程通信、競(jìng)爭(zhēng)的問(wèn)題,全部由一個(gè)線程完成;
- 缺點(diǎn):性能問(wèn)題,只有一個(gè)線程無(wú)法發(fā)揮出多核CPU的性能,Handler在處理某連接業(yè)務(wù)時(shí),整個(gè)進(jìn)程無(wú)法處理其他連接事件,容易導(dǎo)致性能瓶頸;可靠性問(wèn)題,線程意外中止,或者進(jìn)入死循環(huán),會(huì)導(dǎo)致整個(gè)系統(tǒng)通信模塊不可用,不能接收和處理外部信息,節(jié)點(diǎn)故障;
- 使用場(chǎng)景:客戶端數(shù)量有限,業(yè)務(wù)處理快捷(例如 Redis在業(yè)務(wù)處理的時(shí)間復(fù)雜度為O(1)的情況)
-
單Reactor多線程
1、工作原理及說(shuō)明
- Reactor通過(guò)Select監(jiān)控客戶端請(qǐng)求事件,收到事件后,通過(guò)dispatch進(jìn)行分發(fā);
- 如果是建立連接的請(qǐng)求,則由Acceptor通過(guò)accept處理連接請(qǐng)求,同時(shí)創(chuàng)建一個(gè)handler處理完成連接后的后續(xù)請(qǐng)求;
- 如果不是連接請(qǐng)求,則由Reactor分發(fā)調(diào)用連接對(duì)應(yīng)的handler來(lái)處理;
Handler只負(fù)責(zé)響應(yīng)事件,不做具體的業(yè)務(wù)處理,通過(guò)read讀取數(shù)據(jù)后,會(huì)分發(fā)給后面的worker線程池中的某個(gè)線程處理業(yè)務(wù),Worker線程池會(huì)分配獨(dú)立的線程處理真正的業(yè)務(wù),并將結(jié)果返回給Handler。Handler收到響應(yīng)后,通過(guò)send方法將結(jié)果反饋給client
2、優(yōu)缺點(diǎn)分析
- 優(yōu)點(diǎn):可以充分的利用多核CPU的處理能力;
- 缺點(diǎn):多線程數(shù)據(jù)共享、訪問(wèn)操作比較復(fù)雜,reactor處理所有的事件的監(jiān)聽(tīng)和響應(yīng),在單線程運(yùn)行,在高并發(fā)場(chǎng)景容易出現(xiàn)性能瓶頸
-
主從Reactor多線程
1、工作原理及說(shuō)明
- Reactor主線程MainReactor對(duì)象通過(guò)select監(jiān)聽(tīng)連接事件,收到事件后,通過(guò)Acceptor處理連接事件;
- 當(dāng)Acceptor處理連接事件后,MainReactor將創(chuàng)建好的連接分配給SubReactor;
- SubReactor將連接加入到連接隊(duì)列進(jìn)行監(jiān)聽(tīng),并創(chuàng)建Handler進(jìn)行各種事件處理;
- 當(dāng)有新事件發(fā)生時(shí),SubReactor調(diào)用對(duì)應(yīng)的Handler進(jìn)行處理
- Handler通過(guò)read讀取數(shù)據(jù),分發(fā)給后面的Worker線程池處理
- Worker線程池會(huì)分配獨(dú)立的Worker線程進(jìn)行業(yè)務(wù)處理,并將結(jié)果返回
- Handler收到響應(yīng)結(jié)果后,通過(guò)send方法將結(jié)果返回給client
2、優(yōu)缺點(diǎn)分析
- 優(yōu)點(diǎn):父線程和子線程的職責(zé)明確,父線程只需要接收新連接,子線程完成后續(xù)業(yè)務(wù)處理;
- 優(yōu)點(diǎn):父線程與子線程的數(shù)據(jù)交互簡(jiǎn)單,Reactor主線程是需要把新連接傳給子線程,子線程無(wú)需返回?cái)?shù)據(jù)
- 缺點(diǎn):編程復(fù)雜度較高
-
Reactor模式小結(jié)
- 響應(yīng)快,雖然Reactor本身是同步的,但不必為單個(gè)同步事件所阻塞 最大程度的避免了復(fù)雜的多線程及同步問(wèn)題,避免了多線程/進(jìn)程的切換開(kāi)銷
- 擴(kuò)展性好,可以方便的通過(guò)增加Reactor勢(shì)力個(gè)數(shù)充分利用CPU資源
- 復(fù)用性好,Reactor模型本身與具體事件處理邏輯無(wú)關(guān),具有很高的復(fù)用性
四、Netty模型
- 工作原理及說(shuō)明
Netty抽象出兩組線程池:
- BossGroup專門負(fù)責(zé)接收客戶端的連接;
- WorkerGroup專門負(fù)責(zé)網(wǎng)絡(luò)的讀寫
BossGroup和WorkerGroup的類型都是NioEventLoopGroup
NioEventLoopGroup相當(dāng)于一個(gè)事件循環(huán)組,組中含有多個(gè)事件循環(huán),每一個(gè)事件循環(huán)是NioEventLoop。NioEventLoop表示一個(gè)不斷循環(huán)的執(zhí)行任務(wù)的過(guò)程,每個(gè)NioEventLoop都有一個(gè)selector,用于監(jiān)聽(tīng)綁定在其上的socket的網(wǎng)絡(luò)通信。NioEventLoopGroup可以含有多個(gè)線程,即可以含有多個(gè)NioEventLoop
每個(gè)boss NioEventLoop執(zhí)行的步驟有3步
-
【1】輪詢accept事件
-
【2】處理accept事件,與client建立連接,生成NioSocketChannel,并將其注冊(cè)到某個(gè)worker的NioEventLoop上的selector
-
【3】處理任務(wù)隊(duì)列的任務(wù),即runAllTasks
每個(gè)worker的NioEventLoop循環(huán)執(zhí)行的步驟:
-
【1】輪詢r(jià)ead,write事件
-
【2】處理IO事件,在對(duì)應(yīng)的NioSocketChannel處理
-
【3】處理任務(wù)隊(duì)列的任務(wù),即runAllTasks
每個(gè)worker NioEventLoop處理業(yè)務(wù)時(shí),會(huì)使用PipeLine(管道),pipeline中包含了channel,即通過(guò)pipeline可以獲取對(duì)應(yīng)通道,通道中維護(hù)了很多處理器
- 案例分析
Netty服務(wù)器在6668端口監(jiān)聽(tīng),客戶端能發(fā)送消息給服務(wù)器“hello,服務(wù)器”|| 服務(wù)器可以回復(fù)消息給客戶端“hello,客戶端”
在項(xiàng)目中導(dǎo)入Netty開(kāi)發(fā)需要的包:netty-all-xxx.Final.jar
編寫服務(wù)器端及服務(wù)器業(yè)務(wù)處理器
五、Netty模型小結(jié)
Netty抽象出兩組線程池:
- BossGroup專門負(fù)責(zé)接收客戶端的連接;
- WorkerGroup專門負(fù)責(zé)網(wǎng)絡(luò)的讀寫;
NioEventLoop表示一個(gè)不斷循環(huán)的執(zhí)行任務(wù)的線程,每個(gè)NioEventLoop都有一個(gè)selector,用于監(jiān)聽(tīng)綁定在其上的socket的網(wǎng)絡(luò)通道;NioEventLoop內(nèi)部采用串行化設(shè)計(jì),從消息讀取->處理->編碼->發(fā)送始終由IO線程N(yùn)ioEventLoop負(fù)責(zé)。NioEventLoopGroup下包含多個(gè)NioEventLoop,每個(gè)NioEventLoop中包含一個(gè)Selector,一個(gè)taskQueue
- 每個(gè)NioEventLoop的Selector可以注冊(cè)監(jiān)聽(tīng)多個(gè)NioChannel
- 每個(gè)NioChannel只會(huì)綁定唯一的NioEventLoop
- 每個(gè)NioChannel都會(huì)綁定一個(gè)自己的ChannelPipeLine
文章轉(zhuǎn)自
總結(jié)
以上是生活随笔為你收集整理的Netty出现的原因以及多种Reactor模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 互联网晚报 | 1月26日 星期三 |
- 下一篇: 互联网晚报 | 8月26日 星期四 |