netty實戰之一 認識netty

洛城鐵匠發表於2018-07-21

一.netty是啥?

百度百科簡介:

Netty是由JBOSS提供的一個java開源框架。Netty提供非同步的、事件驅動的網路應用程式框架和工具,用以快速開發高效能、高可靠性的網路伺服器和客戶端程式。

也就是說,Netty 是一個基於NIO的客戶、伺服器端程式設計框架,使用Netty 可以確保你快速和簡單的開發出一個網路應用,例如實現了某種協議的客戶、服務端應用。Netty相當於簡化和流線化了網路應用的程式設計開發過程,例如:基於TCP和UDP的socket服務開發。

“快速”和“簡單”並不用產生維護性或效能上的問題。Netty 是一個吸收了多種協議(包括FTP、SMTP、HTTP等各種二進位制文字協議)的實現經驗,並經過相當精心設計的專案。最終,Netty 成功的找到了一種方式,在保證易於開發的同時還保證了其應用的效能,穩定性和伸縮性。

簡單來說就是netty是JBoss做的一個Jar包,為了快速開發高效能、高可靠性的網路伺服器和客戶端程式,可以提供非同步的、事件驅動的網路應用程式框架和工具

netty組成(後續文章會詳細介紹)

 我們可以先從總體上認識一下Netty用到的元件及它們在整個Netty架構中是怎麼協調工作的。Netty應用中必不可少的元件:

  1. Bootstrap or ServerBootstrap
  2. EventLoop
  3. EventLoopGroup
  4. ChannelPipeline
  5. Channel
  6. Future or ChannelFuture
  7. ChannelInitializer
  8. ChannelHandler

     Bootstrap,一個Netty應用通常由一個Bootstrap開始,它主要作用是配置整個Netty程式,串聯起各個元件。

     Handler,為了支援各種協議和處理資料的方式,便誕生了Handler元件。Handler主要用來處理各種事件,這裡的事件很廣泛,比如可以是連線、資料接收、異常、資料轉換等。

     ChannelInboundHandler,一個最常用的Handler。這個Handler的作用就是處理接收到資料時的事件,也就是說,我們的業務邏輯一般就是寫在這個Handler裡面的,ChannelInboundHandler就是用來處理我們的核心業務邏輯。

     ChannelInitializer,當一個連結建立時,我們需要知道怎麼來接收或者傳送資料,當然,我們有各種各樣的Handler實現來處理它,那麼ChannelInitializer便是用來配置這些Handler,它會提供一個ChannelPipeline,並把Handler加入到ChannelPipeline。

     ChannelPipeline,一個Netty應用基於ChannelPipeline機制,這種機制需要依賴於EventLoop和EventLoopGroup,因為它們三個都和事件或者事件處理相關。

     EventLoops的目的是為Channel處理IO操作,一個EventLoop可以為多個Channel服務。

     EventLoopGroup會包含多個EventLoop。

     Channel代表了一個Socket連結,或者其它和IO操作相關的元件,它和EventLoop一起用來參與IO處理。

     Future,在Netty中所有的IO操作都是非同步的,因此,你不能立刻得知訊息是否被正確處理,但是我們可以過一會等它執行完成或者直接註冊一個監聽,具體的實現就是通過Future和ChannelFutures,他們可以註冊一個監聽,當操作執行成功或失敗時監聽會自動觸發。總之,所有的操作都會返回一個ChannelFuture。

2.1netty重要元件的關係圖解

  • 2.1.1.ServerBootstrap及Bootstrap的類繼承結構圖

  • 2.1.2.下圖是Channel、EventLoop、Thread、EventLoopGroup之間的關係(摘自《Netty In Action》):

  • 2.1.2 下圖顯示了ServerBootstrap的兩個EventLoopGroup

二.netty能幹嘛?

Netty 在哪些行業得到了應用?網際網路行業:隨著網站規模的不斷擴大,系統併發訪問量也越來越高,傳統基於 Tomcat 等 Web 容器的垂直架構已經無法滿足需求,需要拆分應用進行服務化,以提高開發和維護效率。從組網情況看,垂直的架構拆分之後,系統採用分散式部署,各個節點之間需要遠端服務呼叫,高效能的 RPC 框架必不可少,Netty 作為非同步高效能的通訊框架,往往作為基礎通訊元件被這些 RPC 框架使用。典型的應用有:阿里分散式服務框架 Dubbo 的 RPC 框架使用 Dubbo 協議進行節點間通訊,Dubbo 協議預設使用 Netty 作為基礎通訊元件,用於實現各程式節點之間的內部通訊

其中,服務提供者和服務消費者之間,服務提供者、服務消費者和效能統計節點之間使用 Netty 進行非同步/同步通訊。除了 Dubbo 之外,淘寶的訊息中介軟體 RocketMQ 的訊息生產者和訊息消費者之間,也採用 Netty 進行高效能、非同步通訊。除了阿里系和淘寶系之外,很多其它的大型網際網路公司或者電商內部也已經大量使用 Netty 構建高效能、分散式的網路伺服器。遊戲行業:無論是手遊服務端、還是大型的網路遊戲,Java 語言得到了越來越廣泛的應用。Netty 作為高效能的基礎通訊元件,它本身提供了 TCP/UDP 和 HTTP 協議棧,非常方便定製和開發私有協議棧。賬號登陸伺服器、地圖伺服器之間可以方便的通過 Netty 進行高效能的通訊。

Netty 在遊戲伺服器架構中的應用大資料領域:經典的 Hadoop 的高效能通訊和序列化元件 Avro 的 RPC 框架,預設採用 Netty 進行跨節點通訊,它的 Netty Service 基於 Netty 框架二次封裝實現。大資料計算往往採用多個計算節點和一個/N個彙總節點進行分散式部署,各節點之間存在海量的資料交換。由於 Netty 的綜合效能是目前各個成熟 NIO 框架中最高的,因此,往往會被選中用作大資料各節點間的通訊。企業軟體:企業和 IT 整合需要 ESB,Netty 對多協議支援、私有協議定製的簡潔性和高效能是 ESB RPC 框架的首選通訊元件。事實上,很多企業匯流排廠商會選擇 Netty 作為基礎通訊元件,用於企業的 IT 整合。通訊行業:Netty 的非同步高效能、高可靠性和高成熟度的優點,使它在通訊行業得到了大量的應用

三.netty其他特點

設計

  • 統一的 API,適用於不同的協議(阻塞和非阻塞)

  • 基於靈活、可擴充套件的事件驅動模型

  • 高度可定製的執行緒模型

  • 可靠的無連線資料 Socket 支援(UDP)

效能

  • 更好的吞吐量,低延遲

  • 更省資源

  • 儘量減少不必要的記憶體拷貝

安全

  • 完整的 SSL/TLS 和 STARTTLS 的支援

易用

  • 完善的 Java doc,使用者指南和樣例,社群很活躍

  • 簡潔簡單

  • 僅依賴於 JDK1.5

Netty框架

 

核心部分

  • 零拷貝

    “Zero-copy” describes computer operations in which the CPU does not perform the task of copying data from one memory area to another.

    上面是 wiki 的一描述,它通常是指計算機在網路上傳送檔案時,不需要將檔案內容拷貝到使用者空間(User Space)而直接在核心空間(Kernel Space)中傳輸到網路的方式,所謂的兩個空間只是說明兩個不一樣的記憶體區域,通過減少不同記憶體區域的拷貝,減低 CPU 的消耗。下面有兩張對比圖:

    1、非零拷貝模式

 

       2、零拷貝模式

 

Netty 的零拷貝與實際定義還是有點出入,Java 是基於虛擬機器的,其實都是使用者空間,Netty 中的零拷貝,更多的是一種資料的優化操作,比如多包合併處理上,Netty是將各個包的地址記錄下來,在邏輯上合成一個整體,實際儲存還是獨立的,這樣減少記憶體拷貝,降低 CPU 消耗。

 

  • 統一通訊 API

    Netty 提供了命名為 channel 統一非同步 IO 介面,主要是為了解決 Java OIO , NIO API 不相容,簡化業務層的工作。

  • 可擴充套件的事件模型

    Netty has a well-defined event model focused on I/O. It also allows you to implement your own event type without breaking the existing code because each event type is distinguished from another by a strict type hierarchy. This is another differentiator against other frameworks.

Netty 是通過 ChannelEvent 作為事件流載體,通過 ChannelHander 來做事件邏輯處理,channelHander 又可分為 INBoundHandler 和 OUTBoundHandler 分別處理流入資料和流出資料,Event 則通過 sendDownStream 和 sendUpStream 在每個 handler 中流轉,ChannelPipeline 作為 handler 的容器,使用者自定義的 handler 只要新增到   pipe,就可以擷取資料流做業務處理。

 

所有的資料流轉,和執行過程都是在一個執行緒(EventLoop)上執行的,這種序列化的處理方式,讓 Netty 無鎖化,無需處理資料競爭問題,提高了執行效率。

高階元件

  • 編解碼框架

    Netty 提供裡提供一套 EncodeHandler 和 DecodeHandler,將業務邏輯從編解碼分離,大家可以瞭解一下,有時間會對這塊仔細說明

  • SSL/TLS Support

    在 Netty 中使用 SSL 也是很方便的,使用 SSLEngine,SslHandler 就可以

 

  • Http/WebSocket 支援

Netty執行緒模型

Netty 支援三種執行緒模型,分別是單執行緒模型,多執行緒模型,以及主從執行緒模型,重點會介紹主從多執行緒模型

  • 單執行緒模型

 

從 accpet 連線到分發到 handler 處理業務,都在單執行緒中完成,模型簡單,適合簡單場景,不適合大併發場景。

  • 多執行緒模型

 

  1. Acceptor 單獨執行緒接受 accpet 連線請求,建立 Channel,並移交給 IO 執行緒池

  2. IO 執行緒池分配執行緒讀取 Channel 資料,並分發 handler 處理相關業務

  3. Accpetor 是單執行緒,如果期間執行鑑權,登陸等操作,出現擁堵,會有單點問題。

  • 主從多執行緒模型

 

  1. Acceptor 執行緒池(NioEventLoopGroup)分配一個 NioEventLoop 接受連線請求,並建立 Channel,並將 Channel 移交給 IO 執行緒池

  2. I/O 執行緒池((NioEventLoopGroup)分配一個 NioEventLoop 處理 Channel 資料,從 Channel 讀資料,並將資料交給 handler 處理,handler 處理完後,向 Channel 寫資料

  3. I/O 執行緒池還可以處理定時任務,和系統任務。

這邊多次提到 NioEventLoop,許多個 NioEventLoop 構成 NioEventLoopGroup,其主要的職能如下:

  1. 作為 Acceptor 執行緒,負責處理客戶端的請求接入

  2. 作為 Connecor 執行緒,負責註冊監聽連線操作位,用於判斷非同步連線結果

  3. 作為 IO 執行緒,監聽網路讀操作位,負責從 SocketChannel 中讀取寫報文

這張圖很好的說明 NioEventLoop 的作用,以及 Netty 序列化的處理鏈。

  • 一個客戶端 Channel 只能由一個 NioEventLoop 處理,避免併發資源競爭問題。

  • NioEventLoop 的事件是分發給 Netty 的事件模型,這個模型可以參考上面的說明。

總結

本文主要介紹了 Netty 的原理,重點對 Netty 的序列化處理鏈,執行緒模型,資料模型做了說明,繞過了細節,希望對大家在大層面去理解 Netty 有幫助,更多的實踐,以及細節,留在後續文章再說。

 

相關文章