Netty

1.Java1.4以前的早期版本的 I/O的問題:前端

  a,沒有數據緩衝區,I/O性能存在問題java

  b,沒有C或者C++中的channel概念,只有輸入流和輸出流正則表達式

  c,同步阻塞式 I/O 通訊(BIO),一般會致使通訊線程被長時間阻塞編程

  d,支持的字符集有限,硬件可移植性很差。後端

2.Java1.4新增了java.nio包,提供了不少進行異步 I/O 開發的API和類庫,主要的類和接口以下:數組

  a,進行異步I/O操做的緩衝區ByteBuffer等緩存

  b,進行異步I/O操做的管道Pipe服務器

  c,進行各類I/O操做(異步或者同步)的Channel,包括ServerSocketChannel 和SocketChannel;網絡

  d,多種字符集的編碼能力和解碼能力多線程

  e,基於流行的Perl實現的正則表達式類庫

  f,文件通道FileChannel

可是它仍然有不完善的地方,特別是對文件系統的處理能力仍顯不足,主要問題以下:

  a,沒有統一的文件屬性

  b,API能力比較弱,例如目錄的級聯建立和遞歸遍歷,每每須要本身實現

  c,底層存儲系統的一些高級API沒法使用

  d,全部的文件操做都是同步阻塞調用,不支持異步文件的讀寫操做

2011年JDK1.7發佈,將原來的NIO類庫進行了升級,被稱爲NIO2.0,提供了下面三個改進

  a,提供可以批量獲取文件屬性的API,這些API具備平臺無關性,不與特性的文件系統相耦合,另外還提供了標準文件系統的SPI,供各個服務提供商擴展實現

  b,提供AIO功能,支持基於文件的異步I/O操做和針對網絡套接字的異步操做

  c,完成JSR-51定義的通道功能,包括對配置和多播數據報的支持等。

 

BIO只要的問題在於每當有一個新的客戶端接入時,服務端必須建立一個新的線程處理新接入的客戶端鏈路,一個線程只能處理一個客戶端鏈接,在高性能的服務器應用領域,每每須要面對成千上萬個客戶端的鏈接,這種模型顯然沒法知足高性能,高併發接入的場景。

僞異步BIO編程:

  爲了解決同步阻塞I/O面臨的一個鏈路須要一個線程初拉力的問題,後來有人對它的線程模型進行了優化-----後端經過一個線程池來處理多個客戶端的請求接入,造成客戶端個數M,線程池最大線程數N的比例關係,其中M能夠遠遠大於N,經過線程池能夠靈活的調配線程資源,設置線程的最大值,防止因爲海量併發接入致使線程資源耗盡。

  InputStream  的read(byte b[]) 方法註釋中有這麼一段話:

  This Method blocks until input data is available ,end of file is detected,or an exception is thrown。

  即當對Socket的輸入流進行讀取操做的過後,它會一直阻塞下去,直到發生以下三種事件:

  1.有數據可讀

  2.可用數據已經讀取完畢

  3.發生空指針或者I/O異常

 這意味着當對方發送請求或者應答消息比較緩慢,或者網絡傳輸較慢時,讀取輸入流一方的通訊線程將會被長時間阻塞,若是對方要60s纔可以將數據發送完成,讀取一方的I/O線程也將會同步阻塞60s,在此期間,其餘接入消息只能在消息隊列中排隊。

outputStream的 write(byte b[]) 寫操做也是同步阻塞的,阻塞的時間取決於對方I/O線程的處理速度和網絡I/O的傳輸速度。本質上來講咱們沒法保證生產環境的網絡情況和對端的應用程序能足夠快,若是咱們的應用程序依賴對方的處理速度,它的可靠性就會很是差。面對惡劣的網絡環境和參差不齊的第三方系統,問題就會如火山同樣噴發。

僞異步I/O其實是對以前I/O模型的一個簡單優化,它沒法從根本上解決同步I/O致使的通訊線程阻塞問題,下面是通訊對方返回應答時間過長會引發的級聯故障:

  1.服務端處理緩慢,返回應答消息耗費60s,平均只須要10ms。

  2.採用僞異步I/O的線程正在讀取故障服務節點的響應,因爲讀取輸入流是阻塞的,它將會同步阻塞60s

  3.假如全部的可用線程都被故障服務器阻塞,那後續的I/O消息都將在隊列中排隊

  4.因爲線程池採用阻塞隊列排隊,當隊列積滿以後,後續入隊列的操做都將被阻塞

  5.因爲前端只有一個Accept線程接收客戶端的接入,它被阻塞在線程池的同步阻塞隊列以後,新的客戶端請求都將被拒絕,客戶端會發生大量的鏈接超時。

  6.因爲幾乎全部的鏈接都超時,調用者會認爲系統已經奔潰,沒法接收新的請求消息。

 

NIO編程:

  NIO非阻塞I/O (Non-block I/O)

  1.緩衝區Buffer

  Buffer是一個對象,它包含一些要寫入或者讀出的數據。在NIO庫中,全部數據都是用緩衝區來處理的。在讀取數據時,它是直接讀到緩衝區中的;在寫入數據時,寫入到緩衝區中。任什麼時候候訪問NIO中的數據,都是經過緩衝區進行操做。

  緩衝區實質上是一個數組。一般它是字節數組(ByteBuffer)是最經常使用的緩衝區,一個ByteBuffer提供了一組功能用於操做Byte數組,每一種Java基本類型(除了Boolean)都對應一種緩衝區,ByteBuffer 字節緩衝區,CharBuffer 字符緩衝區,ShortBuffer 短整型緩衝區,IntBuffer 整型緩衝區,LongBuffer 長整型緩衝區,FloatBuffer 浮點型緩衝區,DoubleBuffer 雙精度浮點型緩衝區。

  2.通道Channel

  Channel是一個通道,網絡數據經過Channel讀取和寫入。通道與流的不一樣之處在於通道是雙向的,流只在一個方向上移動(一個流必須是InputStream或者OutputStream的子類)而通道能夠用於讀、寫或者兩者同時進行。

  由於Channel是全雙工的,因此它能夠比流更好地映射底層操做系統的API。特別是在Unix網絡模型中,底層操做系統的通道都是全雙工的,同時支持讀寫操做。

  實際上Channel分爲兩類:用於網絡讀寫的SelectableChannel和用於文件操做的FileChannel。ServerSocketChannel和SocketChannel都是SelectableChannel的子類。

  3.多路複用器Selector

  它是Java NIO編程的基礎。熟練的掌握Selector對於NIO編程相當重要。多路複用器提供選擇已經就緒的任務的能力。簡單來說,Selector會不斷地輪詢註冊在其上的Channel,若是某個Channel上面發生讀或者寫事件,這個Channel就處於就緒狀態,會被Selector輪詢出來,而後經過SelectionKey能夠獲取就緒Channel的集合,進行後續的I/O操做。

  一個多路複用器能夠同事輪詢多個Channel,因爲JDK使用了epoll來代替傳統的select實現,因此它並無最大鏈接句柄1024/2048的限制。這也就意味着只須要一個線程負責Selector的輪詢,就能夠接入成千上萬的客戶端,這確實是個很是巨大的進步。

  NIO服務端序列圖:

  

 

   NIO客戶端序列圖:

  

 

 

 AIO:

  TODO

 

不選擇Java原生NIO編程的緣由:

  一、NIO的類庫和API繁雜,使用麻煩,你須要熟練掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。

  二、須要具有其餘的額外技能作鋪墊,例如熟悉Java多線程編程。這是由於NIO編程涉及到Reactor模式,你必須對多線程和網絡編程很是熟悉,才能編寫出高質量的NIO程序。

  三、可靠性能力補齊,工做量和難度都很是大。例如客戶端面臨斷連重連、網絡閃斷、半包讀寫、失敗緩存、網絡擁塞和異常碼流等問題,NIO編程的特色是功能開發想對容易,可是可靠性和能力補齊的工做量和難度都很是大。

  四、JDK NIO的BUG,例如臭名昭著的epoll bug,它會致使Selecor空輪詢,最終致使CPU 100%。一直沒獲得根本解決。

 

  爲何選擇Netty:

  一、API使用簡單,開發門檻低

  二、功能強大,預置了多種編解碼功能個,支持多種主流協議

  三、定製能力強,能夠經過ChannelHandler對通訊框架進行靈活的擴展

  四、性能高,經過與其餘業界主流的NIO框架對比,Netty的綜合性能最優

  五、成熟、穩定,Netty修復了已經發現的全部JDK NIO BUG,業務開發人員不須要再爲NIO的BUG而煩惱

  六、社區活躍,版本迭代週期短,發現的BUG能夠及時被修復,同時,更多的新功能會加入。

  七、經歷了大規模的商業應用考驗,質量獲得驗證。Netty在互聯網、大數據、網絡遊戲、企業應用、電信軟件等衆多行業已經獲得了成功商用,證實它是已經徹底可以知足不一樣行業的商業應用了。

相關文章
相關標籤/搜索