1. 程式人生 > >Netty原始碼死磕一(netty執行緒模型及EventLoop機制)

Netty原始碼死磕一(netty執行緒模型及EventLoop機制)

## 引言 好久沒有寫部落格了,近期準備把`Netty`原始碼啃一遍。在這之前本想直接看原始碼,但是看到後面發現其實效率不高, 有些概念還是有必要回頭再細啃的,特別是其執行緒模型以及`EventLoop`的概念。 當然在開始之前還是有務必要對`IO模型`要有清晰準確的認識。 傳送門 []() ## 事件迴圈機制(EventLoop) Netty執行緒模型中一個非常重要的概念: `事件迴圈機制(EventLoop)` 這個概念在`JS`上體現的也非常淋漓盡致,下面在開始介紹netty的執行緒模型之前,允許我簡單的介紹下事件迴圈機 制在`JS`中的體現 `JS`的語言性質: 單執行緒非阻塞,單執行緒意味著,js程式碼在執行的任何時候,都只有一個主執行緒來處理所有的任務>。非阻塞則意味著,在進行非同步IO任務時不會阻塞主執行緒,主執行緒會掛起這個任務,等待非同步任務完成再執行對應>的回撥。 那麼JS是如何實現單執行緒非阻塞的呢?`JS`引擎遇到一個非同步事件後並不會一直等待其返回結果,而是會將此事件>掛起(例如交給瀏覽器去執行請求),主執行緒會繼續執行方法棧中的其他任務。之後當非同步任務返回結果後,(可>能是瀏覽器?)會將回調函式加入到事件佇列(`Task Queue`)中,那麼什麼時候會從事件佇列中取出回撥函式執行>呢?當前執行棧中的所有任務都執行完畢,主執行緒處於閒置狀態時會去查詢事件佇列是否有任務待執行,如果有則>將回調函式加入到主執行緒的方法執行棧中執行,如此反覆,我們就把這個迴圈過程稱為事件迴圈機制(`EventLoop`)。 不知道介紹了JS的件迴圈機制,大家有沒有對`Event Loop`有了一個初步的認識,下面我將會著重介紹我們主角Netty的執行緒模型及其與`Event Loop`的聯絡。 ## Netty執行緒模型 Netty的執行緒模型基於`Reactor`,`Reactor`的核心在於事件分發,它有三種經典的執行緒模型(單執行緒模型,多執行緒>模型,主從多執行緒模型),下面我們會結合`Netty`的`EventLoop`機制一一介紹 ### Reactor單執行緒模型 單執行緒模型全域性只有一個執行緒在工作,也就意味著請求的接收,分發,IO讀取寫入等操作都在一個執行緒中完成,該>模型算得上是最經典的執行緒模型了,例如redis也是採用的此種單執行緒模型了。 ![](http://img.souche.com/f2e/97669ede0e1dd1121c2af90867722d39.jpg) 可以看到上圖中,我們把一個`Reactor執行緒`可以認為是一個`EventLoop IO`執行緒,一個事件迴圈機制。 由於其執行緒中的IO讀寫都是基於NIO,理論上所有的IO讀寫操作都不會阻塞`EventLoop`執行緒。所以即使是該單執行緒>模型,也是足以應付絕大多數的場景。 那麼為什麼又會延伸出`Reactor多執行緒模型`呢? 當應用併發量非常大時,例如一個`Reactor NIO 執行緒`需要同時處理成百上千的連線時,雖然IO讀寫是非阻塞的,>但是訊息的編碼解碼都是需要同步阻塞的,這就導致NIO執行緒處理速度變慢,最終導致訊息積壓,出現效能瓶頸。 基於以上原因也就演進出了第二種模型`Reactor多執行緒模型` ### Reactor多執行緒模型 `Reactor多執行緒模型`與`Reactor單執行緒模型`最大的區別就是,有一組`Reactor NIO執行緒`(也就是一組 `EventLoop`)來處理IO操作 ![](http://img.souche.com/f2e/85e2477417d5c80f7d4831ce70900d87.jpg) 通過上圖,可以比較清晰的看到,IO的讀寫操作都由一個`Reactor NIO執行緒池`(對應到`EventLoop`也就是`EventLoopGroup`)來完成的,而請求的監聽和`Accept`則是由另一個單獨的`Reactor執行緒`來完成。 **注意`Reactor NIO`執行緒池中的每一個執行緒都是處理N條鏈路,但是一個鏈路只能有一個執行緒來處理** `多執行緒的Reactor模型`可以滿足絕大部分的應用場景,通常情況下,我們使用Netty使用這種執行緒模型就OK(建立>兩個NioEventLoopGroup,bossGroup大小為1,workGroup大小為CPU*2)。但是有可能會存在某些極少數的情況,一 個`Reactor執行緒`處理請求的`Accept`可能會產生效能瓶頸,例如上百萬的併發連線請求。這時候我們可能就需要採 用第三種模型`Reactor主從多執行緒模型` ### Reactor主從多執行緒模型 `Reactor主從多執行緒模型`和`Reactor多執行緒模型`的區別在於原本是一個`Reactor執行緒`處理請求的Accept,變成了 `一組Reactor執行緒`。 ![](http://img.souche.com/f2e/81734cca15c63c5395502fb3a515bee1.jpg) 對於`Reactor主從多執行緒模型`,其實大多數情況下我們並不需要。即使我們給BossGroup指定了多個執行緒,最終也>只會選擇其中的一個作為Accepor的NIO執行緒,除非在**服務端綁定了多個埠的情況下才會啟用BossGroup的多個線 程**。 ## 尾言 把`Netty`的執行緒模型以及`EventLoop`理解清楚,個人覺得最好的方法還是順著`Netty`的原始碼一步一步看,看多了 也就理解了這幾種執行緒模型分別對應了哪幾種情況,後面的文章我應該會根據原始碼來進一步理