1. 程式人生 > >005——Netty之EventLoop與EventLoopGroup

005——Netty之EventLoop與EventLoopGroup

Netty解決的事情

Netty主要解決兩個相應關注領域。(1)非同步和事件驅動的實現。(2)一組設計模式,將應用邏輯與網路層解耦。

EventLoop介面

用於處理連線的生命週期中所發生的事件。

  • 一個EventLoopGroup包含一個或者多個EventLoop
  • 一個EventLoop在它的生命週期內只和一個Thread繫結
  • 所有由EventLoop處理的I/O事件都將在它專有的Thread上被處理
  • 一個Channel在它的生命週期內只註冊於一個EventLoop
  • 一個EventLoop可能會被分配給一個或者多個Channel

Netty NIO 客戶端

// 建立一個 EventLoopGroup 物件
EventLoopGroup group = new NioEventLoopGroup();
// 建立 Bootstrap 物件
Bootstrap b = new Bootstrap();
// 設定使用的 EventLoopGroup
b.group(group);
  • Netty只建立一個EventLoop
  • 一個EventLoop可以對應一個Reactor
  • 一個 Bootstrap 的啟動,只能發起對一個遠端的地址。所以只會使用一個 NIO Selector ,也就是說僅使用一個 Reactor 。即使,我們在宣告使用一個 EventLoopGroup ,該 EventLoopGroup 也只會分配一個 EventLoop 對 IO 事件進行處理。

Netty NIO 服務端

// 建立兩個 EventLoopGroup 物件
EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 建立 boss 執行緒組 用於服務端接受客戶端的連線
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 建立 worker 執行緒組 用於進行 SocketChannel 的資料讀寫
// 建立 ServerBootstrap 物件
ServerBootstrap b = new ServerBootstrap();
// 設定使用的 EventLoopGroup
b.group(bossGroup, workerGroup);
  • bossGroup 對應 Reactor 模式的 mainReactor ,用於服務端接受客戶端的連線。比較特殊的是,傳入了方法引數 nThreads = 1 ,表示只使用一個 EventLoop ,即只使用一個 Reactor 。這個也符合我們上面提到的,“通常,mainReactor 只需要一個,因為它一個執行緒就可以處理”。
  • workerGroup 對應 Reactor 模式的 subReactor ,用於進行 SocketChannel 的資料讀寫。對於 EventLoopGroup ,如果未傳遞方法引數 nThreads ,表示使用 CPU 個數 Reactor 。這個也符合我們上面提到的,“通常,subReactor 的個數和 CPU 個數相等,每個 subReactor 獨佔一個執行緒來處理”。

Netty中的Reactor模型
image

image

  • 處理鏈中的處理方法是序列化執行的
  • 一個客戶端連線只註冊到一個NioEventLoop上,避免了多個IO執行緒併發操作

流程:
① 註冊一個Acceptor事件處理器到mainReactor中,Acceptor事件處理器所關注的事件是ACCEPT事件,這樣mainReactor會監聽客戶端向伺服器端發起的連線請求事件(ACCEPT事件)。啟動mainReactor的事件迴圈。
② 客戶端向伺服器端發起一個連線請求,mainReactor監聽到了該ACCEPT事件並將該ACCEPT事件派發給Acceptor處理器來進行處理。Acceptor處理器通過accept()方法得到與這個客戶端對應的連線(SocketChannel),然後將這個SocketChannel傳遞給subReactor執行緒池。
③ subReactor執行緒池分配一個subReactor執行緒給這個SocketChannel,即,將SocketChannel關注的READ事件以及對應的READ事件處理器註冊到subReactor執行緒中。當然你也註冊WRITE事件以及WRITE事件處理器到subReactor執行緒中以完成I/O寫操作。Reactor執行緒池中的每一Reactor執行緒都會有自己的Selector、執行緒和分發的迴圈邏輯。
④ 當有I/O事件就緒時,相關的subReactor就將事件派發給響應的處理器處理。注意,這裡subReactor執行緒只負責完成I/O的read()操作,在讀取到資料後將業務邏輯的處理放入到執行緒池中完成,若完成業務邏輯後需要返回資料給客戶端,則相關的I/O的write操作還是會被提交回subReactor執行緒來完成。

Netty 與 Reactor模式
Netty的執行緒模式就是一個實現了Reactor模式的經典模式。

結構對應:
NioEventLoop ———— Initiation Dispatcher
Synchronous EventDemultiplexer ———— Selector
Evnet Handler ———— ChannelHandler
ConcreteEventHandler ———— 具體的ChannelHandler的實現

模式對應:
Netty服務端使用了“多Reactor執行緒模式”
mainReactor ———— bossGroup(NioEventLoopGroup) 中的某個NioEventLoop
subReactor ———— workerGroup(NioEventLoopGroup) 中的某個NioEventLoop
acceptor ———— ServerBootstrapAcceptor
ThreadPool ———— 使用者自定義執行緒池

參考:

https://www.cnblogs.com/winner-0715/p/8733787.html
http://svip.iocoder.cn/Netty/EventLoop-1-Reactor-Model