<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:Netty的線程模型可不是Reactor這么簡(jiǎn)單

          共 3077字,需瀏覽 7分鐘

           ·

          2021-01-26 14:39

          本文公眾號(hào)來(lái)源:中間件興趣圈

          作者:丁威

          本文已收錄至我的GitHub


          【對(duì)線面試官】系列?一周兩篇持續(xù)更新中!



          Netty的內(nèi)核主要包括如下圖三個(gè)部分:


          其各個(gè)核心模塊主要的職責(zé)如下:
          • 內(nèi)存管理
            主要提高高效的內(nèi)存管理,包含內(nèi)存分配,內(nèi)存回收。

          • 網(wǎng)通通道
            復(fù)制網(wǎng)絡(luò)通信,例如實(shí)現(xiàn)對(duì)NIO、OIO等底層JAVA API 的封裝,簡(jiǎn)化網(wǎng)絡(luò)編程模型。

          • 線程模型

            提供高效的線程協(xié)作模型。

          大家不妨回想一下在以往的面試的過程中,面試官通常會(huì)問:Netty 的線程模型是什么?

          主從多 Reactor 模型,相信大家都能脫口而出,然后呢?就沒有然后了?

          線程模型在網(wǎng)絡(luò)通信中主要解決什么樣的問題?在 Netty 中又是如何解決的,Netty 的線程模型為什么如此高效?請(qǐng)容我慢慢道來(lái)。

          溫馨提示:為了保證文章觀點(diǎn)的嚴(yán)謹(jǐn)性,將探究領(lǐng)域鎖定在:Netty NIO 相關(guān)。

          1、主從多 Reactor 模型


          主從多 Reactor 模型是業(yè)界一種非常經(jīng)典的線程編程模型,其原理圖如下所示:


          我們首先簡(jiǎn)單介紹一下上圖中涉及的幾個(gè)重要角色:
          • Acceptor

            請(qǐng)求接收者,在實(shí)踐時(shí)其職責(zé)類似服務(wù)器,并不真正負(fù)責(zé)連接請(qǐng)求的建立,而只將其請(qǐng)求委托 Main Reactor 線程池來(lái)實(shí)現(xiàn),起到一個(gè)轉(zhuǎn)發(fā)的作用。

          • Main Reactor
            主 Reactor 線程組,主要負(fù)責(zé)連接事件,并將IO讀寫請(qǐng)求轉(zhuǎn)發(fā)到 SubReactor 線程池。當(dāng)然在一些需要對(duì)客戶端進(jìn)行權(quán)限控制等場(chǎng)景下,權(quán)限校驗(yàn)的職責(zé)可以放到 Main Reactor 線程池,即 Main Reactor 也可以注冊(cè)通道的讀寫事件,讀取客戶端權(quán)限校驗(yàn)相關(guān)的數(shù)據(jù)包,執(zhí)行權(quán)限驗(yàn)證,權(quán)限驗(yàn)證通過后再將2通道注冊(cè)到IO線程。

          • Sub Reactor
            Main Reactor 通常監(jiān)聽客戶端連接后會(huì)將通道的讀寫轉(zhuǎn)發(fā)到 Sub Reactor 線程池中一個(gè)線程(負(fù)載均衡),負(fù)責(zé)數(shù)據(jù)的讀寫。在 NIO 中 通常注冊(cè)通道的讀(OP_READ)、寫事件(OP_WRITE)。

          為了更加深刻的理解主從 Reactor 模型,我們來(lái)看一下網(wǎng)絡(luò)通訊一般會(huì)包含哪些關(guān)鍵動(dòng)作:


          一個(gè)網(wǎng)絡(luò)交互通常的幾個(gè)步驟如下:
          • 服務(wù)端啟動(dòng),并在特定端口上監(jiān)聽,例如 web 應(yīng)用的 80端口。

          • 客戶端發(fā)起TCP的三次握手,與服務(wù)端建立連接,這里以 NIO 為例,連接成功建立后會(huì)創(chuàng)建NioSocketChannel對(duì)象。

          • 服務(wù)端通過 NioSocketChannel 從網(wǎng)卡中讀取數(shù)據(jù)

          • 服務(wù)端根據(jù)通信協(xié)議從二進(jìn)制流中解碼出一個(gè)個(gè)請(qǐng)求。

          • 根據(jù)請(qǐng)求,執(zhí)行對(duì)應(yīng)的業(yè)務(wù)操作,例如 Dubbo 服務(wù)端接受一個(gè)查詢用戶ID為1的用戶信息。

          • 將業(yè)務(wù)執(zhí)行結(jié)果返回到客戶端,通常涉及到協(xié)議編碼、壓縮等。

          線程模型需要解決的問題:連接監(jiān)聽、網(wǎng)絡(luò)讀寫、編碼、解碼、業(yè)務(wù)執(zhí)行這些操作步驟如何運(yùn)用多線程編程,提升性能。

          主從多Reactor模型是如何解決上面的問題呢?

          1. 連接建立(OP_ACCEPT)由 Main Reactor 線程池負(fù)責(zé),創(chuàng)建NioSocketChannel后,將其轉(zhuǎn)發(fā)給SubReactor。

          2. SubReactor 線程池主要負(fù)責(zé)網(wǎng)絡(luò)的讀寫(從網(wǎng)絡(luò)中讀字節(jié)流、將字節(jié)流發(fā)送到網(wǎng)絡(luò)中),即注冊(cè)O(shè)P_READ、OP_WRITE,并且同一個(gè)通道會(huì)綁定一個(gè)SubReactor線程

          3. 編碼、解碼、業(yè)務(wù)執(zhí)行,則具體情況具體分析

            通常編碼、解碼會(huì)放在IO線程中執(zhí)行,而業(yè)務(wù)邏輯的執(zhí)行通常會(huì)采用額外的線程池,但不是絕對(duì)的,一個(gè)好的框架通常會(huì)使用參數(shù)來(lái)進(jìn)行定制化選擇,例如 ping、pong 這種心跳包,直接在 IO 線程中執(zhí)行,無(wú)需再轉(zhuǎn)發(fā)到業(yè)務(wù)線程池,避免線程切換開銷。

          溫馨提示:在網(wǎng)絡(luò)編程中,通常將用于網(wǎng)絡(luò)讀寫的線程稱為IO線程。

          2、Netty 的線程模型


          Netty的線程模型是基于主從多Reactor模型。


          Netty 中網(wǎng)絡(luò)的連接事件(OP_ACCEPT)由Main Reactor 線程組實(shí)現(xiàn),即 Boss Group,通常只需設(shè)置一個(gè)線程

          網(wǎng)絡(luò)的讀寫操作由 Work Group ( Sub Reactor) 線程組來(lái)實(shí)現(xiàn),線程的個(gè)數(shù)默認(rèn)為 2 * CPU Core,一個(gè) Channel 綁定到其中一個(gè) Work 線程,一個(gè) Work 線程中可以綁定多個(gè) Channel

          在 Netty 中編碼、解碼等操作會(huì)被封裝成一個(gè)一個(gè)事件處理器(ChannelHandler),那這些 Handler 是在IO線程池中執(zhí)行?

          默認(rèn)情況下ChannelHandler 是在 IO 線程中執(zhí)行,那如何改變默認(rèn)行為呢?其關(guān)鍵代碼如下:


          關(guān)鍵點(diǎn):在將事件處理器添加到事件鏈時(shí)可以指定在哪個(gè)線程池中執(zhí)行,如果不指定則為IO線程中執(zhí)行。

          面試官:通常業(yè)務(wù)操作會(huì)專門開辟一個(gè)線程池,那業(yè)務(wù)處理完成之后,如何將響應(yīng)結(jié)果通過 IO 線程寫入到網(wǎng)卡中呢?


          業(yè)務(wù)線程調(diào)用 Channel 對(duì)象的 write 方法并不會(huì)立即寫入網(wǎng)絡(luò),只是將數(shù)據(jù)放入一個(gè)待寫入隊(duì)列(緩存區(qū)),然后IO線程每次執(zhí)行事件選擇后,會(huì)從待寫入緩存區(qū)中獲取寫入任務(wù),將數(shù)據(jù)真正寫入到網(wǎng)絡(luò)中,數(shù)據(jù)到達(dá)網(wǎng)卡之前會(huì)經(jīng)過一系列的 Channel Handler(Netty事件傳播機(jī)制),最終寫入網(wǎng)卡。

          最后再來(lái)介紹一下 Netty 中 IO 線程的大體工作流程。


          IO線程處理的關(guān)鍵點(diǎn):
          • 每一IO線程在執(zhí)行上述操作時(shí)是串行執(zhí)行的,即注冊(cè)在一個(gè) Selector(事件選擇器)中的所有通道,同一時(shí)間只有一個(gè)通道的事件被處理。這也是為什么NIO應(yīng)對(duì)大文件傳輸時(shí)不具備優(yōu)勢(shì)的根本原因。

          • IO 線程在處理完所有就緒事件后,還會(huì)從任務(wù)隊(duì)列(Task Queue)獲取任務(wù),例如上文中提到的業(yè)務(wù)線程在執(zhí)行完業(yè)務(wù)后需要將返回結(jié)果寫入網(wǎng)絡(luò),Netty 中所有的網(wǎng)絡(luò)讀寫操作只能在IO線程中真正獲得運(yùn)行,故業(yè)務(wù)線程需要將帶寫入的響應(yīng)結(jié)果封裝成 Task,放入到 IO 線程任務(wù)隊(duì)列中。


          3、總結(jié)


          回到到主題,如果我們?cè)诿嬖囘^程中碰到面試官提問“Netty 的線程模型是什么?”時(shí),我們應(yīng)該可以從容應(yīng)對(duì)了。

          我覺得可以從如下幾個(gè)方面進(jìn)行展開。

          1. Netty的線程模型基于主從多Reactor模型。通常由一個(gè)線程負(fù)責(zé)處理OP_ACCEPT事件,擁有 CPU 核數(shù)的兩倍的IO線程處理讀寫事件。

          2. 一個(gè)通道的IO操作會(huì)綁定在一個(gè)IO線程中,而一個(gè)IO線程可以注冊(cè)多個(gè)通道。

          3. 在一個(gè)網(wǎng)絡(luò)通信中通常會(huì)包含網(wǎng)絡(luò)數(shù)據(jù)讀寫,編碼、解碼、業(yè)務(wù)處理。默認(rèn)情況下編碼、解碼等操作會(huì)在IO線程中運(yùn)行,但也可以指定其他線程池。

          4. 通常業(yè)務(wù)處理會(huì)單獨(dú)開啟業(yè)務(wù)線程池,但也可以進(jìn)一步細(xì)化,例如心跳包可以直接在IO線程中處理,而需要再轉(zhuǎn)發(fā)給業(yè)務(wù)線程池,避免線程切換。

          5. 在一個(gè)IO線程中所有通道的事件是串行處理的。



          目前已經(jīng)連載11啦!進(jìn)度是一周更新兩篇,歡迎持續(xù)關(guān)注

          怎樣偷偷努力 驚艷所有人?

          掃描二維碼關(guān)注【面試造火箭

          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91成人无码在线电影 | 天堂极品mv | 美女做受 | 国产毛片网 | 厂里宿舍少妇愉情视频 |