Netty的底層原理

擊水三千里發表於2019-03-12

目錄

Netty簡介

I/O複用模型

基於buffer

Netty執行緒模型

事件驅動模型


Netty簡介

Netty是 一個非同步事件驅動的網路應用程式框架,用於快速開發可維護的高效能協議伺服器和客戶端。

JDK原生NIO程式的問題

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

 

  • NIO的類庫和API繁雜,使用麻煩,你需要熟練掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
  • 需要具備其它的額外技能做鋪墊,例如熟悉Java多執行緒程式設計,因為NIO程式設計涉及到Reactor模式,你必須對多執行緒和網路程式設計非常熟悉,才能編寫出高質量的NIO程式
  • 可靠效能力補齊,開發工作量和難度都非常大。例如客戶端面臨斷連重連、網路閃斷、半包讀寫、失敗快取、網路擁塞和異常碼流的處理等等,NIO程式設計的特點是功能開發相對容易,但是可靠效能力補齊工作量和難度都非常大
  • JDK NIO的BUG,例如臭名昭著的epoll bug,它會導致Selector空輪詢,最終導致CPU 100%。官方聲稱在JDK1.6版本的update18修復了該問題,但是直到JDK1.7版本該問題仍舊存在,只不過該bug發生概率降低了一些而已,它並沒有被根本解決

 

Netty主要特點有:

  • 設計優雅
  • 使用方便
  • 高效能
  • 安全
  • 社群活躍,不斷更新

 

I/O複用模型

 

 

 

 

Netty的IO執行緒NioEventLoop由於聚合了多路複用器Selector,可以同時併發處理成百上千個客戶端連線。當執行緒從某客戶端Socket通道進行讀寫資料時,若沒有資料可用時,該執行緒可以進行其他任務。執行緒通常將非阻塞 IO 的空閒時間用於在其他通道上執行 IO 操作,所以單獨的執行緒可以管理多個輸入和輸出通道

 

由於讀寫操作都是非阻塞的,這就可以充分提升IO執行緒的執行效率,避免由於頻繁I/O阻塞導致的執行緒掛起,一個I/O執行緒可以併發處理N個客戶端連線和讀寫操作,這從根本上解決了傳統同步阻塞I/O一連線一執行緒模型,架構的效能、彈性伸縮能力和可靠性都得到了極大的提升。

 

基於buffer

傳統的I/O是面向位元組流或字元流的,以流式的方式順序地從一個Stream 中讀取一個或多個位元組, 因此也就不能隨意改變讀取指標的位置。

在NIO中, 拋棄了傳統的 I/O流, 而是引入了Channel和Buffer的概念. 在NIO中, 只能從Channel中讀取資料到Buffer中或將資料 Buffer 中寫入到 Channel。

基於buffer操作不像傳統IO的順序操作, NIO 中可以隨意地讀取任意位置的資料

 

Netty執行緒模型

Netty主要基於主從Reactors多執行緒模型(如下圖)做了一定的修改,其中主從Reactor多執行緒模型有多個Reactor:MainReactor和SubReactor:

  • MainReactor負責客戶端的連線請求,並將請求轉交給SubReactor
  • SubReactor負責相應通道的IO讀寫請求
  • 非IO請求(具體邏輯處理)的任務則會直接寫入佇列,等待worker threads進行處理

這裡引用Doug Lee大神的Reactor介紹:Scalable IO in Java裡面關於主從Reactor多執行緒模型的圖

 

事件驅動模型

通常,我們設計一個事件處理模型的程式有兩種思路

  • 輪詢方式

執行緒不斷輪詢訪問相關事件發生源有沒有發生事件,有發生事件就呼叫事件處理邏輯。

  • 事件驅動方式

發生事件,主執行緒把事件放入事件佇列,在另外執行緒不斷迴圈消費事件列表中的事件,呼叫事件對應的處理邏輯處理事件。事件驅動方式也被稱為訊息通知方式,其實是設計模式中觀察者模式的思路。

 

 

 

相關文章