Netty 系列之核心組件

一、概念

早期的 Java API 只支持由本地系統套接字庫提供所謂的阻塞函數來支持網絡編程。由於是阻塞 I/O ,要管理多個併發客戶端,需要為每個新的客戶端Socket 創建一個 Thread 。這將導致一系列的問題,第一,在任何時候都可能有大量的線程處於休眠狀態(不可能每時每刻都有對應的併發數);第二,需要為每個線程的調用棧都分配內存;第三,JVM 在線程的上下文切換所帶來的開銷會帶來麻煩。

Java 在 2002 年引入了非阻塞 I/O,位於 JDK 1.4 的 java.nio 包中。class java.nio.channels.Selector 是Java 的非阻塞 I/O 實現的關鍵。它使用了事件通知以確定在一組非阻塞套接字中有哪些已經就緒能夠進行 I/O 相關的操作。因為可以在任何的時間檢查任意的讀操作或者寫操作的完成狀態,所以如圖 1-2 所示,一個單一的線程便可以處理多個併發的連接。

Netty 系列之核心組件

儘管可以直接使用 Java NIO API,但是在高負載下可靠和高效地處理和調度 I/O 操作是一項繁瑣而且容易出錯的任務,最好還是留給高性能的網絡編程專家——Netty。

Netty 是一款異步的事件驅動的網絡應用程序框架,支持快速的開發可維護的高性能的瞄向協議的服務端和客戶端。它駕馭了Java高級API的能力,並將其隱藏在一個易於使用的API之後。首先,它的基於 Java NIO 的異步的和事件驅動的實現,保證了高負載下應用程序性能的最大化和可伸縮性。其次, Netty 也包含了一組設計模式,將應用程序邏輯從網絡層解耦,簡化了開發過程, 同時也最大限度地提高了可測試性、模塊化以及代碼的可重用性。

Netty 系列之核心組件

tips:面向對象的基本概念—> 用較簡單的抽象隱藏底層實現的複雜性。

二、核心組件

  • Channel

Channel是Java NIO的一個基本構造。可以看作是傳入或傳出數據的載體。因此,它可以被打開或關閉,連接或者斷開連接。以下是常用的Channel:

-- EmbeddedChannel

-- LocalServerChannel

-- NioDatagramChannel

-- NioSctpChannel

-- NioSocketChannel

  • 回調

當一個回調被觸發時,相應的事件可以被一個interface-ChannelHandler的實現處理。

  • Future

Netty中所有的I/O操作都是異步的。因為一個操作可能不會立即返回,所以我們需要一種在之後的某個時間點確定其結果的方法。

Future 和 回調 是相互補充的機制,提供了另一種在操作完成時通知應用程序的方式。這個對象可以看作是一個異步操作結果的佔位符;它將在未來的某個時刻完成,並提供對其結果的訪問。

Netty 提供了ChannelFuture,用於在執行異步操作的時候使用。每個Netty的出站I/O操作都會返回一個ChannelFuture。ChannelFuture能夠註冊一個或者多個ChannelFutureListener 實例。監聽器的回調方法operationComplete(),將會在對應的操作完成時被調用。

  • ChannelHandler

Netty 的主要組件是ChannelHandler,它充當了所有處理入站和出站數據的應用程序邏輯的容器。

Netty 使用不同的事件來通知我們狀態的改變或者是操作的狀態,每個事件都可以被分發給ChannelHandler類中某個用戶實現的方法。Netty提供了大量預定義的可以開箱即用的ChannelHandler實現,包括用於各種協議的ChannelHandler。

現在,事件可以被分發給ChannelHandler類中某個用戶實現的方法。那麼,如果 ChannelHandler 處理完成後不直接返回給客戶端,而是傳遞給下一個ChannelHandler 繼續處理呢?那麼就要說到 ChannelPipeline !

ChannelPipeline 提供了 ChannelHandler鏈 的容器,並定義了用於在該鏈上傳播入站和出站事件流的API。使得事件流經 ChannelPipeline 是 ChannelHandler 的工作,它們是在應用程序的初始化或者引導階段被安裝的。這些對象接收事件、執行他們所實現的處理邏輯,並將數據傳遞給鏈中的下一個ChannelHandler:

  1. 一個ChannelInitializer的實現被註冊到了ServerBootstrap中。
  2. 當 ChannelInitializer.initChannel()方法被調用時, ChannelInitializer將在 ChannelPipeline 中安裝一組自定義的 ChannelHandler。
  3. ChannelInitializer 將它自己從 ChannelPipeline 中移除。
Netty 系列之核心組件

  • EventLoop

EventLoop 定義了Netty的核心抽象,用來處理連接的生命週期中所發生的事件,在內部,將會為每個Channel分配一個EventLoop。

EventLoop本身只由一個線程驅動,其處理了一個Channel的所有I/O事件,並且在該EventLoop的整個生命週期內都不會改變。這個簡單而強大的設計消除了你可能有的在ChannelHandler實現中需要進行同步的任何顧慮。

Netty 系列之核心組件

這裡需要說到,EventLoop的管理是通過EventLoopGroup來實現的。還要一點要注意的是,客戶端引導類是 Bootstrap,只需要一個EventLoopGroup。服務端引導類是 ServerBootstrap,通常需要兩個 EventLoopGroup,一個用來接收客戶端連接,一個用來處理 I/O 事件(也可以只使用一個 EventLoopGroup,此時其將在兩個場景下共用同一個 EventLoopGroup)。

Netty 系列之核心組件

  1. 一個 EventLoopGroup 包含一個或者多個 EventLoop
  2. 一個 EventLoop 在它的生命週期內只和一個 Thread 綁定;
  3. 所有由 EventLoop 處理的 I/O 事件都將在它專有的Thread 上被處理;
  4. 一個 Channel 在它的生命週期內只註冊於一個EventLoop;
  5. NIO中,一個 EventLoop 分配給多個 Channel(面對多個Channel,一個 EventLoop 按照事件觸發,順序執行); OIO中,一個 EventLoop 分配給一個 Channel。

tips:Netty 應用程序的一個一般準則:儘可能的重用 EventLoop,以減少線程創建所帶來的開銷。

  • Bootstrap 和 ServerBootstrap

BootStarp 和 ServerBootstrap 被稱為引導類,指對應用程序進行配置,並使他運行起來的過程。Netty處理引導的方式是使你的應用程序和網絡層相隔離。

BootStrap 是客戶端的引導類,Bootstrap 在調用 bind()(連接UDP)和 connect()(連接TCP)方法時,會新創建一個 Channel,僅創建一個單獨的、沒有父 Channel 的 Channel 來實現所有的網絡交換。

Netty 系列之核心組件

ServerBootstrap 是服務端的引導類,ServerBootstarp 在調用 bind() 方法時會創建一個 ServerChannel 來接受來自客戶端的連接,並且該 ServerChannel 管理了多個子 Channel 用於同客戶端之間的通信。

Netty 系列之核心組件


分享到:


相關文章: