天天看點

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型

部落格名稱: pjmike的部落格

前言

我們在使用Netty進行服務端開發的時候,一般來說會定義兩個NioEventLoopGroup線程池,一個"bossGroup"線程池去負責處理用戶端連接配接,一個"workGroup"線程池去負責處理讀寫操作。那麼,我們為什麼要這麼做呢?這樣做的好處是什麼呢?能不能隻使用一個NioEventLoopGroup呢?這就是我們今天要讨論的主題——Netty的線程模型

Reactor線程模型

實際上Netty線程模型就是Reactor模式的一個實作,而Reactor模式又是什麼呢?

Reactor模式是基于事件驅動開發的,核心組成部分包括Reactor和線程池,其中Reactor負責監聽和配置設定事件,線程池負責處理事件,而根據Reactor的數量和線程池的數量,又将Reactor分為三種模型:

  • 單線程模型 (單Reactor單線程)
  • 多線程模型 (單Reactor多線程)
  • 主從多線程模型 (多Reactor多線程)

單線程模型

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型
圖檔摘自: http:// gee.cs.oswego.edu/dl/cp jslides/nio.pdf
  • Reactor内部通過 selector 監控連接配接事件,收到事件後通過 dispatch 進行分發,如果是連接配接建立的事件,則由Acceptor處理, Acceptor 通過accept接受連接配接,并建立一個Handler來處理連接配接後續的各種事件,如果是讀寫事件,直接調用連接配接對應的 Handler 來處理
  • Handler完成read->(decode->compute->encode)->send的業務流程
  • 這種模型好處是簡單,壞處卻很明顯,當某個Handler阻塞時,會導緻其他用戶端的handler和accpetor都得不到執行,無法做到高性能,隻适用于業務處理非常快速的場景

多線程模型

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型
圖檔摘自: http:// gee.cs.oswego.edu/dl/cp jslides/nio.pdf
  • 主線程中,Reactor對象通過selector監控連接配接事件,收到事件後通過dispatch進行分發,如果是連接配接建立事件,則由Acceptor處理,Acceptor通過accept接收連接配接,并建立一個Handler來處理後續事件,而Handler隻負責響應事件,不進行業務操作,也就是隻進行read讀取資料和write寫出資料,業務處理交給一個線程池進行處理
  • 線程池配置設定一個線程完成真正的業務處理,然後将響應結果交給主程序的Handler處理,Handler将結果send給client (下面是核心代碼)
netty權威指南第三版 pdf_Netty系列文章之Netty線程模型

單Reactor承當所有事件的監聽和響應,而當我們的服務端遇到大量的用戶端同時進行連接配接,或者在請求連接配接時執行一些耗時操作,比如身份認證,權限檢查等,這種瞬時的高并發就容易成為性能瓶頸

主從多線程模型 (最流行)

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型
圖檔摘自: http:// gee.cs.oswego.edu/dl/cp jslides/nio.pdf
  • 存在多個Reactor, 每個Reactor都有自己的selector選擇器 ,線程和dispatch
  • 主線程中的mainReactor通過自己的selector監控連接配接建立事件,收到事件後通過Accpetor接收,将新的連接配接配置設定給某個子線程
  • 子線程中的subReactor将mainReactor配置設定的連接配接加入連接配接隊列中通過自己的selector進行監聽,并建立一個Handler用于處理後續事件
  • Handler完成read->業務處理->send的完整業務流程
netty權威指南第三版 pdf_Netty系列文章之Netty線程模型

Netty中的線程模型與Reactor的聯系

Netty主要靠NioEventLoopGroup線程池來實作具體的線程模型的

單線程模型

單線程模型就是隻指定一個線程執行用戶端連接配接和讀寫操作,也就是在一個Reactor中完成,對應在Netty中的實作就是将NioEventLoopGroup線程數設定為1,核心代碼是:

NioEventLoopGroup group = new NioEventLoopGroup(1);
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(group)
                .channel(NioServerSocketChannel.class)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ServerHandlerInitializer());
           

它的工作流程大緻如下:

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型

上述單線程模型就對應了Reactor的單線程模型

多線程模型

多線程模型就是在一個單Reactor中進行用戶端連接配接處理,然後業務處理交給線程池,核心代碼如下:

NioEventLoopGroup eventGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(eventGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ServerHandlerInitializer());
           

走進group方法可以發現我們平時設定的bossGroup和workerGroup就是使用了同一個group

@Override
public ServerBootstrap group(EventLoopGroup group) {
    return group(group, group);
}
           

工作流程如下:

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型

主從多線程模型 (最常使用)

主從多線程模型是有多個Reactor,也就是存在多個selector,是以我們定義一個bossGroup和一個workGroup,核心代碼如下:

NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ServerHandlerInitializer());
           

工作流程如下:

netty權威指南第三版 pdf_Netty系列文章之Netty線程模型
注意:其實在Netty中,bossGroup線程池最終還是隻會随機選擇一個線程用于處理用戶端連接配接,與此同時,NioServerSocetChannel綁定到bossGroup的線程中,NioSocketChannel綁定到workGroup的線程中

小結

以上總結了Reactor的三種模型以及Netty中的對應實作,在Netty中,我們使用的最多的還是主從多線程模型。關于Reactor的學習,最權威的資料應該是Doug Lea大神的Scalable IO in Java,有興趣的同學可以看看

參考資料

  • http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf
  • https://time.geekbang.org/column/article/8805
  • https://segmentfault.com/a/1190000007403873
  • https://www.infoq.cn/article/netty-threading-model

繼續閱讀