一. Netty做了什么梳玫?
1.Netty實現(xiàn)了對Java NIO的封裝导梆,提供了更方便使用的接口贩绕;
2.Netty利用責(zé)任鏈模式實現(xiàn)了ChannelPipeline這一概念艳汽,基于ChannelPipeline嗤无,我們可以 優(yōu)雅的實現(xiàn)網(wǎng)絡(luò)消息的處理(可插拔震束,解耦);
3.Netty的Reactor線程模型当犯,利用無鎖化提高了系統(tǒng)的性能垢村;
4.Netty實現(xiàn)了ByteBuf用于對字節(jié)進(jìn)行緩存和操作,相比JDK的ByteBuffer嚎卫,它更易用嘉栓,同時還提供了Buffer池的功能,對于UnpooledDirectByteBuf和PooledByteBuf,Netty還對其內(nèi)存使用進(jìn)行了跟蹤侵佃,發(fā)現(xiàn)內(nèi)存泄漏時會給出報警麻昼;
二.Netty對JDK NIO的封裝
JDK NIO有ServerSocketChannel、SocketChannel趣钱、Selector涌献、SelectionKey幾個核心概念。
Netty提供了一個Channel接口統(tǒng)一了對網(wǎng)絡(luò)的IO操作首有,其底層的IO通信是交給Unsafe接口實現(xiàn)燕垃,而Channel主要負(fù)責(zé)更高層次的read、write井联、flush卜壕、和ChannelPipeline、Eventloop等組件的交互烙常,以及一些狀態(tài)的展示轴捎;做到了職責(zé)的清晰劃分,對使用者是很友好的蚕脏,規(guī)避了JDK NIO中一些比較繁瑣復(fù)雜的概念和流程侦副。
Channel、Unsafe繼承UML圖
Channel和Unsafe是分多級別實現(xiàn)的驼鞭,不同級別的Channel和Unsafe對應(yīng)了不同級別的實現(xiàn)秦驯,也是“職責(zé)單一原則”的體現(xiàn)。
三.ChannelPipeline責(zé)任鏈模型
借用網(wǎng)上的一張圖表示Channel挣棕、ChannelPipeline译隘、ChannelHandlerContext和ChannelHandler之間的關(guān)系。
每個Channel都持有一個ChannelPipeline洛心,通過Channel的讀寫等IO操作實際上是交由ChannelPipeline處理的固耘,而ChannelPipeline會持有一個ChannelHandlerContext鏈表,每個Context內(nèi)部又包含一個ChannelHandler词身,使用者在Pipeline上添加handler負(fù)責(zé)邏輯處理厅目,ChannelHandlerContext負(fù)責(zé)事件的傳遞流轉(zhuǎn)。每個ChannelPipeline都會持有2個特殊的ChannelHandlerContext——head和tail法严,他們分別是Context鏈表的頭和尾璧瞬。
ChannelPipeline上的事件,分為Inbound事件和Outbound事件2種渐夸,Inbound事件從headContext讀入,在Context鏈上的InboundHandler上正向依次流動渔欢;Outbound事件從Channel(即ChannelPipeline)上觸發(fā)墓塌,則從tailContext上出發(fā),在Context鏈上的OutboundHandler上反向依次流動,若從某一個Context上觸發(fā)苫幢,則從這個Context之后的下一個OutboundContext開始執(zhí)行访诱。headContext利用Unsafe完成實際的IO操作。
我們在使用Netty的時候韩肝,業(yè)務(wù)邏輯其實基本都存在于ChannelHandler触菜;Netty也為我們提供了很多通用的Handler,如一些常用的編解碼Handler哀峻,常見應(yīng)用層協(xié)議的Handler涡相,整流、心跳剩蟀、日志等常用功能的Handler催蝗,合理使用這些Handler能迅速提高我們開發(fā)的效率。
四.Reactor線程模型
Reactor模型是一種常見的并發(fā)編程模型育特,關(guān)于React模型可以參考這篇文章Reactor模型丙号,React模型改變了Thread Per Connection的模式,它將一個網(wǎng)絡(luò)IO操作分為2部分:連接的建立缰冤,網(wǎng)絡(luò)通信及消息處理犬缨;這兩部分分別用單獨(dú)的線程池去處理(一般情況下,連接的建立用單獨(dú)的一個線程就足夠了)棉浸,這樣做的好處如下:功能解耦怀薛、利于維護(hù)、利于組件化復(fù)用涮拗、方便細(xì)粒度的并發(fā)控制乾戏,另外可以通過減少線程數(shù),避免大量的線程切換三热。其模型圖如下:
簡單的說鼓择,一個Reactor線程(池)負(fù)責(zé)接收所有的連接請求,然后將連接產(chǎn)生的Channel賦給Work線程池中的線程就漾,接下來的通信操作都交給Work線程執(zhí)行呐能。
Netty結(jié)合NIO的特點合理的使用了Reactor模型,具體地說抑堡,Netty的Reactor線程接收到一個連接請求后摆出,會創(chuàng)建一個Channel,并為這個Channel分配一個EventLoop首妖,每個EventLoop對應(yīng)一個線程偎漫,Channel上的IO操作將在EventLoop上執(zhí)行,一個Channel僅綁定在一個EventLoop上有缆,一個EventLoop可以對應(yīng)多個Channel象踊,這樣就避免了同步温亲,也提高了線程的使用效率。
實際上杯矩,EventLoop中的線程除了執(zhí)行IO操作栈虚,還會執(zhí)行ChannelPipeline上的handler的責(zé)任鏈方法,這樣做是為了避免頻換切換線程帶來的損耗史隆,所以handler中一般不可以放置耗時的任務(wù)魂务,如果有耗時的任務(wù),可以將任務(wù)放入自定義的線程池中執(zhí)行泌射。
五.ByteBuf
Java的NIO給我們提供了緩沖區(qū)的實現(xiàn)ByteBuffer粘姜,但是它的易用性較差(讀寫模式需要切換等問題),所以魄幕,Netty自己重新實現(xiàn)了緩沖區(qū)ByteBuf相艇,ByteBuf的API更易用、并且提供了內(nèi)存池的功能纯陨,對于池化的ByteBuf和直接內(nèi)存的ByteBuf坛芽,Netty還提供了對內(nèi)存泄漏的監(jiān)控(并且設(shè)置了各種性能級別),另外ByteBuf還提供了對ByteBuffer的兼容翼抠。