1. 程式人生 > >Netty 線程模型

Netty 線程模型

容量 引用 over 需求 寫到 ann 情況 err 負責

一、線程模型概述

線程模型表明了代碼的執行方式。從最開始的使用單線程,後來出現了多線程,之後是線程池。當有要執行的任務時,任務會被傳到線程池,從線程池中獲得空閑的線程來執行任務,執行完了後會將線程返回到線程池。

二、Reactor 模型

1.網絡服務基本的步驟:

①讀取請求 → ②解碼請求 → ③處理請求 → ④編碼響應 → ⑤發送響應

2.Reactor模型

(1)single threaded version

技術分享圖片

(圖片摘自Doug Lea的pdf,鏈接參見文末)

在這個模型中,一個線程處理所有I/O相關的操作。acceptor接收來自客戶端的TCP連接請求,建立連接後,通過dispatcher將消息(ByteBuffer)分發到各個handler(新的線程)上進行處理。這個模型無法滿足高容量的需求,不停的穿建了新的線程來處理消息,耗盡系統資源。此外,當NIO線程負載較重之後,處理速度會變慢導致大量客戶端連接超時,重新發送請求,導致CPU很快便會達到100。

(2)Multithreaded pattern

技術分享圖片

(圖片摘自Doug Lea的pdf,鏈接參見文末)

這個版本上的變化,主要體現在分發到各個handler(worker thread)時,使用了線程池,這樣避免創建過多的線程,控制線程數量,提高處理效率。 但是在個別場合,一個NIO線程負責監聽和處理所有客戶端連接(例如百萬客戶端連接)可能會存在性能問題。

(3)Multiple Reactor

技術分享圖片

(圖片摘自Doug Lea的pdf,鏈接參見文末)

在這個模型中,主reactor選擇一個線程作為acceptor線程,用於綁定監聽端口,接收客戶端連接。然後,Acceptor接收客戶端請求後創建新的SocketChannel,註冊到子reactor中進行握手等操作。最後,來到工作線程池,進行業務的操作。

三、Netty線程模型

1.接口EventLoop

1 public interface EventLoop extends OrderedEventExecutor, EventLoopGroup {
2     @Override
3     EventLoopGroup parent(); // 這個方法,返回這個EventLoop所屬的EventLoopGroup的引用
4 }

在Netty中,多個EventLoop會被創建。其中的一個用來服務多個Channnel,另外的其他,會用來優化資源的使用。這句話的意思,聯想代碼部分,我們可以想到下面:

1 EventLoopGroup bossGroup = new
NioEventLoopGroup(1); //負責監聽接口,處理客戶端過來的連接請求 2 EventLoopGroup workerGroup = new NioEventLoopGroup(); //負責連接之後,通道的信息的傳輸

再看一下他的類的層次圖(圖摘自《Netty in action》):

技術分享圖片

2.Netty 4中I/O 和 事件處理

事件多種多樣,事件的本性決定了它本身如何被處理,例如:它可以從網絡往應用裏傳輸,也可相反,或是完全不同的一些事件。但是事件的處理邏輯要廣泛和靈活,以至於可以處理任何的情況。因此,在Netty 4中所有I/O和事件的處理交給 指定到EventLoop上的thread來執行。這點與Netty 3不同。

3.Netty 3中I/O 和 事件處理

只有Inbound事件會被交給EventLoop來執行,而所有Outbound事件會由調用者線程來執行,可能是I/O線程,也可能是其他線程。因此,outbound端需要同步的操作。因為,五法保證多個線程不會同時操作outbound事件。

4.實現的細節

看下面流程,線程的管理:

技術分享圖片

任務執行前會進行判斷,調用的線程是否是指定給EventLoop的線程。如果是同一個的話,直接執行任務;如果不是,將任務放進隊列之中,等EventLoop再次處理它的任務。

這就解釋了為什麽在ChannelHandler中為什麽不需要同步就可以讓線程和Channel直接交互。

就寫到這裏了。。。能力一般,水平有限!希望以後多用到Netty,能更好的認知Netty。

參考資料:

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

《Netty in action》

Netty 線程模型