不只概念,用代碼來解釋netty的線程模型

不只概念,用代碼來解釋netty的線程模型

前言

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

Reactor線程模型

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

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

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

單線程模型

不只概念,用代碼來解釋netty的線程模型

  • Reactor內部通過selector 監控連接事件,收到事件後通過dispatch進行分發,如果是連接建立的事件,則由Acceptor處理,Acceptor通過accept接受連接,並創建一個Handler來處理連接後續的各種事件,如果是讀寫事件,直接調用連接對應的Handler來處理
  • Handler完成read->(decode->compute->encode)->send的業務流程
  • 這種模型好處是簡單,壞處卻很明顯,當某個Handler阻塞時,會導致其他客戶端的handler和accpetor都得不到執行,無法做到高性能,只適用於業務處理非常快速的場景

多線程模型

不只概念,用代碼來解釋netty的線程模型

  • 主線程中,Reactor對象通過selector監控連接事件,收到事件後通過dispatch進行分發,如果是連接建立事件,則由Acceptor處理,Acceptor通過accept接收連接,並創建一個Handler來處理後續事件,而Handler只負責響應事件,不進行業務操作,也就是隻進行read讀取數據和write寫出數據,業務處理交給一個線程池進行處理
  • 線程池分配一個線程完成真正的業務處理,然後將響應結果交給主進程的Handler處理,Handler將結果send給client (下面是核心代碼)
不只概念,用代碼來解釋netty的線程模型

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

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

不只概念,用代碼來解釋netty的線程模型

  • 存在多個Reactor,
    每個Reactor都有自己的selector選擇器,線程和dispatch
  • 主線程中的mainReactor通過自己的selector監控連接建立事件,收到事件後通過Accpetor接收,將新的連接分配給某個子線程
  • 子線程中的subReactor將mainReactor分配的連接加入連接隊列中通過自己的selector進行監聽,並創建一個Handler用於處理後續事件
  • Handler完成read->業務處理->send的完整業務流程
不只概念,用代碼來解釋netty的線程模型

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

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

單線程模型

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

不只概念,用代碼來解釋netty的線程模型

它的工作流程大致如下:

不只概念,用代碼來解釋netty的線程模型

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

多線程模型

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

不只概念,用代碼來解釋netty的線程模型

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

不只概念,用代碼來解釋netty的線程模型

工作流程如下:

不只概念,用代碼來解釋netty的線程模型

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

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

不只概念,用代碼來解釋netty的線程模型

工作流程如下:

不只概念,用代碼來解釋netty的線程模型

注意:其實在Netty中,bossGroup線程池最終還是隻會隨機選擇一個線程用於處理客戶端連接,與此同時,NioServerSocetChannel綁定到bossGroup的線程中,NioSocketChannel綁定到workGroup的線程中

小結

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

鏈接:https://juejin.im/post/5dac6ef75188252bc1657ead


分享到:


相關文章: