netty研究一架構

寸金難買寸光陰

Netty是⼀個⾼性能的、異步的、基於事件驅動的⽹絡應⽤框架

同步異步

如下是同步,同步異步是針對與一個請求本身來說的,如果需要給出相應,不給就的 等待,知道獲取相應,叫同步。

如下異步:

netty 基於java的nio,netty對各種傳輸類型,協議實現API進行了統一的封裝,實現了阻塞和非阻塞的Socket

⽐如:阿⾥巴巴的分佈式服務治理框架Dubbo,底層就是使⽤Netty作爲通信組件。

gRPC,是Google提供的⾼性能RPC框架,底層也使⽤了Netty。

Flink、Spark、Elasticsearch也採⽤了Netty作爲通信組件

RPC調用基本示意圖

基於此來實現電商系統中的訂單模塊的業務

這個通知是服務提供者在註冊中心註冊過了,告知調用者一下子

IO模型

BIO模型  NIO模型,AIO模型

java中的BIO是blocking I/O的簡稱,它是同步阻塞型IO,其相關的類和接⼝在java.io下。

BIO模型簡單來講,就是服務端爲每⼀個請求都分配⼀個線程進⾏處理

這種模式存在的問題:

客戶端的併發數與後端的線程數成1:1的⽐例,線程的創建、銷燬是⾮常消耗系統資源的,隨着併發量增⼤,服務端性能將顯著下降,甚⾄會發⽣線程堆棧溢出等錯誤。

當連接創建後,如果該線程沒有操作時,會進⾏阻塞操作,這樣極⼤的浪費了服務器資源。

NIO模型

non-block IO (⾮阻塞IO)

NIO相關的代碼都放在了java.nio包下,其三⼤核⼼組件:

Buffer(緩衝區)、Channel(通道)、Selector(選擇器/多路復⽤器)

 

Buffer

         在NIO中,所有的讀寫操作都是基於緩衝區完成的,底層是通過數組實現的,常⽤的緩衝區是ByteBuffer,每⼀種java基本類型都有對應的緩衝區對象(除了Boolean類型),如:CharBuffer、IntBuffer、LongBuffer等。

Channel(和流對比,流單向,Channel雙向)

          l在BIO中是基於Stream實現,⽽在NIO中是基於通道實現,與流不同的是,通道是雙向的,既可以讀也可以寫。

Selector

          Selector是多路復⽤器,它會不斷的輪詢註冊在其上的Channel,如果某個Channel上發⽣讀或寫事件,這個Channel就處於就緒狀態,會被Selector輪詢出來,然後通過SelectionKey獲取就緒Channel的集合,進⾏IO的讀寫操作。

如下圖是NIO模型圖

 

解釋:chanel 是和server直接連的,單獨開了個線程Selector 來輪詢channel的變化

有變化,就selectorKey感知變化,進而處理請求。

可以看出,NIO模型要優於BIO模型,主要是:

通過多路復⽤器就可以實現⼀個線程處理多個通道,避免了多線程之間的上下⽂切換導致系統開銷過⼤。

NIO⽆需爲每⼀個連接開⼀個線程處理,並且只有通道真正有有事件時,才進⾏讀寫操作,這樣⼤⼤的減少了系統開銷。

AIO模型

在NIO中,Selector多路復⽤器在做輪詢時,如果沒有事件發⽣,也會進⾏阻塞

AIO是asynchronous I/O的簡稱,是異步IO,該異步IO是需要依賴於操作系統底層的異步IO實現。

AIO的基本流程是:⽤戶線程通過系統調⽤,告知kernel內核啓動某個IO操作,⽤戶線程返回。kernel內核在整個IO操作(包括數據準備、數據複製)完成後,通知⽤戶程序,⽤戶執⾏後續的業務操作。

發現還是回調,內核kernel 執行完成後,回調,告知用戶線程,完成了

輪詢優於回調的嚐盡個還有futuretask 和completablefuture 

 

kernel的數據準備

           將數據從⽹絡物理設備(⽹卡)讀取到內核緩衝區。

kernel的數據複製

           將數據從內核緩衝區拷⻉到⽤戶程序空間的緩衝區。

這個有點像volatile 關鍵字,主存和線程內存關係,需要傳遞

⽬前AIO模型存在的不⾜:

需要完成事件的註冊與傳遞,這⾥邊需要底層操作系統提供⼤量的⽀持,去做⼤量的⼯作。

Windows 系統下通過 IOCP 實現了真正的異步 I/O。但是,就⽬前的業界形式來說,Windows 系統,很少作爲百萬級以上或者說⾼併發應⽤的服務器操作系統來使⽤。

⽽在 Linux 系統下,異步IO模型在2.6版本才引⼊,⽬前並不完善。所以,這也是在 Linux 下,實現⾼併發⽹絡編程時都是以 NIO 多路復⽤模型模式爲主。

Reactor線程模型 

是⼀種併發編程模型,是⼀種思想

Netty就是結合了NIO的特點,應⽤了Reactor線程模型所實現的。

Reactor模型中定義的三種⻆⾊:

Reactor:負責監聽和分配事件,將I/O事件分派給對應的Handler。新的事件包含連接建⽴就緒、讀就緒、寫就緒等。

Acceptor:處理客戶端新連接,並分派請求到處理器鏈中。

Handler:將⾃身與事件綁定,執⾏⾮阻塞讀/寫任務,完成channel的讀⼊,完成處理業務邏輯後,負責將結果寫出channel。

常⻅的Reactor線程模型有三種,如下:

Reactor單線程模型

Reactor多線程模型

主從Reactor多線程模型

 

說明:

Reactor充當多路復⽤器⻆⾊,監聽多路連接的請求,由單線程完成

Reactor收到客戶端發來的請求時,如果是新建連接通過Acceptor完成,其他的請求由Handler完成。

Handler完成業務邏輯的處理,基本的流程是:Read --> 業務處理 --> Send 。

這種模型的優缺點:

優點

結構簡單,由單線程完成,沒有多線程、進程通信等問題。

適合⽤在⼀些業務邏輯⽐較簡單、對於性能要求不⾼的應⽤場景。

缺點

由於是單線程操作,不能充分發揮多核CPU的性能。

當Reactor線程負載過重之後,處理速度將變慢,這會導致⼤量客戶端連接超時,超時之後往往會進⾏重發,這更加重Reactor線程的負載,最終會導致⼤量消息積壓和處理超時,成爲系統的性能瓶頸。

可靠性差,如果該線程進⼊死循環或意外終⽌,就會導致整個通信系統不可⽤,容易造成單點故障。

單Reactor多線程模型

 

說明:

在Reactor多線程模型相⽐較單線程模型⽽⾔,不同點在於,Handler不會處理業務邏輯,只是負責響應⽤戶請求,真正的業務邏輯,在另外的線程中完成。

這樣可以降低Reactor的性能開銷,充分利⽤CPU資源,從⽽更專注的做事件分發⼯作了,提升整個應⽤的吞吐。

但是這個模型存在的問題:

多線程數據共享和訪問⽐較複雜。如果⼦線程完成業務處理後,把結果傳遞給主線程Reactor進⾏發送,就會涉及共享數據的互斥和保護機制。

Reactor承擔所有事件的監聽和響應,只在主線程中運⾏,可能會存在性能問題。例如併發百萬客戶端連接,或者服務端需要對客戶端握⼿進⾏安全認證,但是認證本身⾮常損耗性能。

爲了解決性能問題,產⽣了第三種主從Reactor多線程模型。

主從Reactor多線程模型

在主從模型中,將Reactor分成2部分:

MainReactor負責監聽server socket,⽤來處理⽹絡IO連接建⽴操作,將建⽴的socketChannel指定註冊給SubReactor。

SubReactor主要完成和建⽴起來的socket的數據交互和事件業務處理操作。

該模型的優點:

響應快,不必爲單個同步事件所阻塞,雖然Reactor本身依然是同步的。

可擴展性強,可以⽅便地通過增加SubReactor實例個數來充分利⽤CPU資源。

可復⽤性⾼,Reactor模型本身與具體事件處理邏輯⽆關,具有很⾼的復⽤性。

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