詳盡Netty(一):初探netty

如果大家對java架構相關感興趣,可以關注下面公衆號,會持續更新java基礎面試題, netty, spring boot,spring cloud等系列文章,一系列乾貨隨時送達, 超神之路從此展開, BTAJ不再是夢想!

架構殿堂

概念

​ Netty 是一個高性能、異步事件驅動的 NIO 框架,它提供了對 TCP、UDP 和文件傳輸的支持,作爲一個異步 NIO 框架,Netty 的所有 IO 操作都是異步非阻塞的,通過 Future-Listener 機制,用戶可以方便的主動獲取或者通過通知機制獲得 IO 操作結果。

作爲當前最流行的 NIO 框架,Netty 在互聯網領域、大數據分佈式計算領域、遊戲行業、通信行業等獲得了廣泛的應用,一些業界著名的開源組件也基於 Netty 的 NIO 框架構建。

本系列學習基於 Netty 4.1 展開介紹相關理論模型,使用場景,基本組件、整體架構,知其然且知其所以然,希望給大家在實際開發實踐、學習開源項目方面提供參考。

JDK 原生 NIO 程序的問題

JDK 原生也有一套網絡應用程序 API,但是存在一系列問題,主要如下:

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

2)需要具備其他的額外技能做鋪墊:例如熟悉 Java 多線程編程,因爲 NIO 編程涉及到 Reactor 模式,你必須對多線程和網路編程非常熟悉,才能編寫出高質量的 NIO 程序。

3)可靠性能力補齊,開發工作量和難度都非常大:例如客戶端面臨斷連重連、網絡閃斷、半包讀寫、失敗緩存、網絡擁塞和異常碼流的處理等等。NIO 編程的特點是功能開發相對容易,但是可靠性能力補齊工作量和難度都非常大。

4)JDK NIO 的 Bug:例如臭名昭著的 Epoll Bug,它會導致 Selector 空輪詢,最終導致 CPU 100%。官方聲稱在 JDK 1.6 版本的 update 18 修復了該問題,但是直到 JDK 1.7 版本該問題仍舊存在,只不過該 Bug 發生概率降低了一些而已,它並沒有被根本解決。

Netty 的特點

Netty 對 JDK 自帶的 NIO 的 API 進行了封裝,解決了上述問題。

Netty的主要特點有:

設計:

​ 針對多種傳輸類型的同一接口-阻塞和非阻塞;

​ 簡單但更強大的線程模型;

​ 真正的無連接的數據報套接字支持;

​ 連接邏輯支持複用。

易用性:

​ 大量的javadoc和代碼實例;

​ 除了在JDK1.6+額外的限制。

性能:

​ 比核心Java API更好的吞吐量,較低的延時;

​ 資源消耗更少,這個得益於於共享池和重用;

​ 減少內存拷貝。

健壯性:

​ 消除由於慢、快、活重載連接產生的OutOfMemoryError;

​ 消除經常發現在NIO在告訴網絡中的應用中的不公平的讀/寫比。

安全:

​ 完整的SSL/TLS和StartTLS的支持;

​ 運行在受限的環境例如Applet活OSGI。

社區:

​ 發佈的更早和更頻繁;

​ 社區驅動。

各種io介紹

BIO

同步阻塞IO,阻塞整個步驟,如果連接少,他的延遲是最低的,因爲一個線程只處理一個連接,適用於少連接且延遲低的場景,比如說數據庫連接。

NIO

同步非阻塞IO,阻塞業務處理但不阻塞數據接收,適用於高併發且處理簡單的場景,比如聊天軟件。

多路複用IO

他的兩個步驟處理是分開的,也就是說,一個連接可能他的數據接收是線程a完成的,數據處理是線程b完成的,他比BIO能處理更多請求。

信號驅動IO

這種IO模型主要用在嵌入式開發,不參與討論。

異步IO

他的數據請求和數據處理都是異步的,數據請求一次返回一次,適用於長連接的業務場景。

Netty中幾個主要組件

  • Channel:代表了一個鏈接,與EventLoop一起用來參與IO處理。
  • ChannelHandler:爲了支持各種協議和處理數據的方式,便誕生了Handler組件。Handler主要用來處理各種事件,這裏的事件很廣泛,比如可以是連接、數據接收、異常、數據轉換等。
  • ChannelHandlerContext,用於傳輸業務數據。
  • ChannelPipeline:提供了 ChannelHandler 鏈的容器,並定義了用於在該鏈上傳播入站
    和出站事件流的 API。 用於保存處理過程需要用到的ChannelHandler和ChannelHandlerContext。
  • EventLoop:Channel處理IO操作,一個EventLoop可以爲多個Channel服務。
  • EventLoopGroup:會包含多個EventLoop。

Netty中核心部分

  • Channels
  • Buffers
  • Selectors

Channel 和 Buffer

基本上,所有的 IO 在NIO 中都從一個Channel 開始。Channel 有點象流。 數據可以從Channel讀到Buffer中,也可以從Buffer 寫到Channel中。這裏有個圖示:
在這裏插入圖片描述
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-awIrSz35-1592151833560)(E:\技術帖子\筆記\netty\圖片資源\netty介紹1.png)]

Channel和Buffer有好幾種類型。下面是JAVA NIO中的一些主要Channel的實現:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

正如你所看到的,這些通道涵蓋了UDP 和 TCP 網絡IO,以及文件IO。

與這些類一起的有一些有趣的接口,但爲簡單起見,我儘量在概述中不提到它們。本教程其它章節與它們相關的地方我會進行解釋。

以下是Java NIO裏關鍵的Buffer實現:

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

這些Buffer覆蓋了你能通過IO發送的基本數據類型:byte, short, int, long, float, double 和 char。

Java NIO 還有個 MappedByteBuffer,用於表示內存映射文件, 我也不打算在概述中說明。

Selector

Selector允許單線程處理多個 Channel。如果你的應用打開了多個連接(通道),但每個連接的流量都很低,使用Selector就會很方便。例如,在一個聊天服務器中。

這是在一個單線程中使用一個Selector處理3個Channel的圖示:
在這裏插入圖片描述
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WXSWWVXC-1592151833562)(E:\技術帖子\筆記\netty\圖片資源\netty介紹2.png)]

要使用Selector,得向Selector註冊Channel,然後調用它的select()方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,線程就可以處理這些事件,事件的例子有如新連接進來,數據接收等。

Netty異步和事件驅動

所有的網絡應用程序需要被設計爲可擴展性,可以被界定爲“一個系統,網絡能力,或過程中能夠處理越來越多的工作方式或可擴大到容納增長的能力”,Netty 利用非阻塞 I/O 完成這一目標,通常稱爲“異步 I/O”

爲什麼Netty受歡迎?

  1. 併發高

  2. 傳輸快

  3. 封裝好

Netty爲什麼併發高?

Selector, 當一個Socket建立好之後,Thread並不會阻塞去接受這個Socket,而是將這個請求交給Selector,Selector會不斷的去遍歷所有的Socket,一旦有一個Socket建立完成,他會通知Thread,然後Thread處理完數據再返回給客戶端——這個過程是不阻塞的,這樣就能讓一個Thread處理更多的請求了。

Netty爲什麼傳輸快?

零拷貝,當它需要接收數據的時候,它會在堆內存之外開闢一塊內存,數據就直接從IO讀到了那塊內存中去,在netty裏面通過ByteBuf可以直接對這些數據進行直接操作,從而加快了傳輸速度。

Netty和Tomcat有什麼區別?

Netty和Tomcat最大的區別就在於通信協議,Tomcat是基於Http協議的,他的實質是一個基於http協議的web容器,但是Netty不一樣,他能通過編程自定義各種協議,因爲netty能夠通過codec自己來編碼/解碼字節流,完成類似redis訪問的功能,這就是netty和tomcat最大的不同。

有人說netty的性能就一定比tomcat性能高,其實不然,tomcat從6.x開始就支持了nio模式,並且後續還有APR模式——一種通過jni調用apache網絡庫的模式,相比於舊的bio模式,併發性能得到了很大提高,特別是APR模式,而netty是否比tomcat性能更高,則要取決於netty程序作者的技術實力了。

Netty 常見使用場景

1)**互聯網行業:**在分佈式系統中,各個節點之間需要遠程服務調用,高性能的 RPC 框架必不可少,Netty 作爲異步高性能的通信框架,往往作爲基礎通信組件被這些 RPC 框架使用。典型的應用有:阿里分佈式服務框架 Dubbo 的 RPC 框架使用 Dubbo 協議進行節點間通信,Dubbo 協議默認使用 Netty 作爲基礎通信組件,用於實現各進程節點之間的內部通信。

2)**遊戲行業:**無論是手遊服務端還是大型的網絡遊戲,Java 語言得到了越來越廣泛的應用。Netty 作爲高性能的基礎通信組件,它本身提供了 TCP/UDP 和 HTTP 協議棧。

非常方便定製和開發私有協議棧,賬號登錄服務器,地圖服務器之間可以方便的通過 Netty 進行高性能的通信。

3)**大數據領域:**經典的 Hadoop 的高性能通信和序列化組件 Avro 的 RPC 框架,默認採用 Netty 進行跨界點通信,它的 Netty Service 基於 Netty 框架二次封裝實現。

如果大家對java架構相關感興趣,可以關注下面公衆號,會持續更新java基礎面試題, netty, spring boot,spring cloud等系列文章,一系列乾貨隨時送達, 超神之路從此展開, BTAJ不再是夢想!

架構殿堂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章