Netty 執行緒模型
Reactor 執行緒模型
由於傳統 的阻塞 IO 對於響應時間不是很好,因此引入了 Reactor
的非同步事件模型來提高響應時間。
主要存在以下三種方式:
-
單執行緒
Reactor
內部通過selector
來監聽連線事件,收到事件之後通過dispatcher
來進行分發。如果是連線建立的事件,則由acceptor
進行處理,acceptor
通過接受到連線,建立一個 Handler 來處理後續的事件。 該模型的缺點:由於是使用單執行緒的方式來處理每個連線事件,因此無法有效地利用 CPU 提供的資源
-
多執行緒
為了充分利用 CPU 提供的資源,因此使用多執行緒的方式來對工作集合進行處理。
在主執行緒中,
Reactor
物件通過selector
來監控連線事件,收到事件之後通過dispatch
進行分發,如果是連線事件,則由acceptor
進行處理,acceptor
通過接收到連線,建立一個Handler
來處理後續的事件。在這個執行緒模型中,該Handler
只是負責響應事件,不進行任何業務操作,所有的業務操作都放線上程池中進行處理。 該模型存在的缺點:在同時接受大量的連線請求時,由於所有的連線請求都是通過單個的
Reactor
物件來進行處理的,因此這是很可能會造成連線超時的情況。 -
主從多執行緒
由於使用單獨的 Reactor
來處理連線在處理大量連線是可能會導致連線連線超時的情況,因此在這個執行緒模型中採用了 “主—從” Reactor
Reactor
物件,它負責將接收到的請求分發到某個 “從” Reactor
物件,“從” Reactor
物件將會將得到的請求按照 “多執行緒模型” 的方式對任務進行處理。“從” Reactor
物件的數量由具體的硬體環境來決定。
Netty 執行緒模型
Netty 通過 NioEventLoopGroup
來實現上文提及的幾種 Reactor
模型
-
單執行緒模型
單執行緒模型就是隻指定一個執行緒執行客戶端的連線和讀取操作,即將所有的請求和任務的處理都放在一個執行緒中執行,只要將
NioEventLoopGroup
NioEventLoopGroup group = new NioEventLoopGroup(1); // 設定 NioEventLoopGroup 執行緒數為1,將當前的 Reactor 執行緒模型設定為單執行緒模型 ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(group) .channel(NioServerSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) // 開啟 Nagle 演算法 .option(ChannelOption.SO_BACKLOG, 1024) // 最大連線等待佇列的長度 .childHandler(new SimpleChannelInboundHandler<SocketChannel>() { @Override protected void channelRead0( ChannelHandlerContext ctx, SocketChannel msg ) throws Exception { /* TODO */ } });
大致的工作流程:
-
多執行緒模型
多執行緒模型就是在一個
Reactor
物件中對客戶端的連線進行處理,然後將業務交給執行緒池進行處理。程式碼如下所示:NioEventLoopGroup group = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(group) .channel(NioServerSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new SimpleChannelInboundHandler<SocketChannel>() { @Override protected void channelRead0( ChannelHandlerContext ctx, SocketChannel msg) throws Exception { /* TODO */ } });
值得注意的是,這種模型的實現原理就是將“主”
Reactor
物件和 “從”Reactor
物件設定為同一個NioEventLoopGroup
物件來實現的具體工作流程:
-
主從多執行緒模型
只要將 “主”
Reactor
物件和 “從”Reactor
物件設定為不同的NioEventLoopGroup
即可達到對應的效果。具體程式碼如下所示:
NioEventLoopGroup mainGroup = new NioEventLoopGroup(); NioEventLoopGroup minorGroup = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(mainGroup, minorGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new SimpleChannelInboundHandler<SocketChannel>() { @Override protected void channelRead0( ChannelHandlerContext ctx, SocketChannel msg ) throws Exception { /* TODO */ } });
工作流程如下所示:
在 Netty 中,“主”
Reactor
實際上依舊只是隨機選擇一個執行緒用於處理客戶端的連線。與此同時,NioServerSocketChannel
繫結到mainGroup
,而NioSockerChannel
繫結到minorChannel
中
參考: