Netty4詳解一:理解Netty的設計理念NIO
一、初步了解Netty
Netty是一個NIO的編程框架,Netty是非常容易和快速開發出網絡應用程序的,它提供了一種全新的形式來方便你編寫網絡應用:它提供了對一些對複雜問題的抽象,提供了一套非常容易使用的api來把我們的業務邏輯和純粹處理網絡的代碼分離開來。因為Betty是基於NIO,因此它的整個API都是異步的。




![]()
Netty簡化了基於TCP和UDP的編程,但是你仍可以用它的底層的API做一些底層處理,因為Netty提供了一係列高抽象的API。
Netty有一係列豐富的特性,讓我們來看一下它的強大之處:
Netty有一係列豐富的特性,讓我們來看一下它的強大之處:
- 有一套統一的API來處理異步和同步編程模式
- 使用非常靈活
- 簡單但卻強大的線程機製
- 業務組件分離方便重用
- 極小的縮減不必要的Memory Copy
Netty開始-理解Netty的設計理念NIONetty開始-理解Netty的設計理念NIO

二、異步編程模式設計
一般來說網絡編程都會麵臨著並發問題,那麼我們就來看一下為何異步編程模式會很好的解決這個問題,其實這也就詮釋了netty背後的設計思想。
在現在,瓶頸總是在IO處理上,異步的處理方式就是你可以不用一直等待任務(IO)處理完成,而是在任務進行的時候還可以做其它事情。那麼如何實現這個呢?讓我們來認識一下實現異步的兩種處理方式:
CallBack:回調是異步處理經常用到的編程模式,回調函數通常被綁定到一個方法上,並且在方法完成之後才執行,這種處理方式在javascript當中得到了充分的運用。回調給我們帶來的難題是當一個問題處理過程中涉及很多回調時,代碼是很難讀的。
Futures:Futures是一種抽象,它代表一個事情的執行過程中的一些關鍵點,我們通過Future就可以知道任務的執行情況,比如當任務沒完成時我們可以做一些其它事情。它給我們帶來的難題是我們需要去判斷future的值來確定任務的執行狀態。
其實這兩者很難界定那個好或壞,其實Netty中這兩者都有用到。
異步模式(NIO)和非異步模式(BIO)(N可以理解為non-blocking或new)
Block IO會對每個連接創建一個線程,因此這極大限製了JVM創建線程的數量(當然線程池可緩解這個問題,但是也僅僅是緩解),如圖所示:

NIO會通過專門的Selector來管理請求,然後可由一個線程來處理請求,如圖所示:

在NIO中,不得不提到的是關於抽象的數據容器ByteBuffer,ByteBuffer允許相同的數據在不同ByteBuffer之間共享而不需要再拷貝一次來處理。Slicing-ByteBuffer允許創建一個新的ByteBuffer通過暴露一個子邊界的形式共享原ByteBuffer的數據,這就大大減少了在數據處理過程中內存的copy(Zero-copy)。ByteBuffer通過一些索引來記錄讀寫的信息,當你向其中寫數據時,它會自動跟蹤你寫到ByteBuffer的位置,類似,他也會自動跟蹤你讀的位置。而且ByteBuffer還提供了很多方法讓你切換讀寫模式(flip)或者清空(clear)或者壓縮(compact)等。
關於Selectors,NIOAPI通過selector來處理網絡事件和數據。一個Channel代表一個網絡連接。Selector的作用就是來決定這些Channel是否已準備好讀或者寫操作,一個selector可以處理很多連接請求,這就解決了為一個連接創建一個線程的問題。要想用一個selector需要以下步驟:
1.創建一個或多個selector用來給打開的channels注冊。
2.當一個channel注冊後,就需要來確定哪種事件需要你監聽,通常有四種事件:
OP_ACCEPT
OP_CONNECT
OP_READ
OP_WRITE
3.當channels被注冊後,你需要調用Selector.select()方法來阻塞直到上述事件發生。
4.當方法沒有阻塞時,你會獲得所有SelectionKey實例,這些實例包含了已注冊channel的引用和其狀態,這樣你就可以做你的操作了。
三、Netty VS JavaNIO
1.跨平台性和通用型
NIO某些底層的操作依賴於操作係統,因此,你寫的NIO程序有可能在windows上運行良好,但到了Linux可能會出現問題。 Java6和Java7對NIO提供了不同的解決方案,兩個API是不通用的。
2.拓展了ByteBuffer
Netty提供了對ByteBuffer的封裝類ByteBuf,拓展了JDK中ByteBuffer的功能,增強了易用性。
3. 數據拆分和聚集
很多時候我們想把數據分割成獨立的Bytebuffer來處理,比如Http協議Header放到一個buffer中,而Body放到另一個buffer中。很不幸,對於這種處理方式直到Java7才出現,而且如果處理不當,會極易造成OutOfMemoryError。
Scattering And Gathering:


4.解決了著名的epoll bug
關於Java NIO,請參考我的另外兩篇文章:
最後更新:2017-04-03 12:56:08