Netty源碼分析:圖解Pipeline、Handler、Context

      爲了和以前的Wangle源碼分析系列造成呼應,如今將之前寫的Netty的圖解過程搬移過來。 如下所繪製圖形均基於Netty4.0.28版本。nginx

1、connect(outbound類型事件)

   當用戶調用channel的connect時,會發起一個outbound類型的事件,該事件將在pipeline中傳遞(pipeline.connect),首先由tail handler處理,該handler只是將事件透傳給下一個outbound類型的用戶Handler(若是有),事件依次傳遞下去,直到傳遞到head handler,該handler會調用unsafe.connect()向eventloop(nio的selector)註冊一個讀事件。 緩存

             

 

2、connect成功以後數據流圖(inbound類型事件)

   當用戶發起一個connect請求後,當鏈接可用時,eventloop(底層使用nio的selector)會引起一個ChannelActive事件,該事件最早有unsafe捕獲,以後會調用pipeline.fireChannelActive()將該事件在pipeline中傳播,緊接着會根據inbound類型事件的傳遞方式在各個handler和context之間進行鏈式傳遞。其中,有一個比較關注的地方是,在channelActive事件觸發的時候,若是channel被設置成autoRead,那麼此時還會調用channel.read()方法,該方法並非真正的從channel讀取數據,而是向eventloop註冊讀事件(由於一個channel在向eventloop中註冊時,默認不註冊任何事件),關於channel.read的過程能夠看下文的另外一張圖。網絡

              

3、channel.read事件流圖(outbound類型事件)

     當用戶調用channel.read()後,會發起一個outbound類型的事件,該事件最早會由pipeline中tail handler處理,該handler只是將該事件透傳給前面一個outbound類型的用戶handler(若是有的話),這樣依次繼續向前傳遞,直到傳遞到head handler,該handler會調用unsafe.read()向eventloop註冊讀事件(也就是向nio的selector上添加讀事件)。oop

                

4、channel.write(outbound類型事件)

      與channel.read()類型相同,wirte也是一個outbound類型事件,該事件最早會由pipeline中的tail handler透傳給前面的一個outbound類型的用戶handler(若是有的話),這樣依次傳遞,直到傳遞給head handler,該handler會調用unsafe.write()方法,這裏的wirte並不會執行真正的發送,而是將要發送的數據緩存起來,直到調用flush時,這些數據纔會執行真正的網絡io。 這裏須要注意,若是調用write的線程不是當前channel綁定的io線程(EventLoop),那麼在write內部會判斷,並將寫操做封裝成一個task強行加入io線程(EventLoop)的隊列,所以後續的write操做就是在io線程中執行的。源碼分析

                  

5、flush(outbound類型事件)

         如前文所示,flush也是一個outbound類型的事件,與wirte不一樣,flush會執行真正的網絡io操做。spa

                 

6、當channel有數據可讀時(inbound類型事件)

      當eventloop層檢測到網絡層有數據可讀時(nio的selector返回相應的seleciontKeys),該事件會首先傳遞給unsafe,緊接着會調用pipeline.fireChannelRead(),將事件開始在pipeline中傳遞,該事件最早會有head handler處理(head.fireChannelRead()),該handler直接將事件透傳給下一個inbound類型的用戶handler(若是有的話),該事件依次向下傳遞,直到傳遞到tail handler。這裏須要注意,由於全部的handler默認都是在io線程中串行執行的,所以若是某個handler比較耗時,就可能致使io線程阻塞,從而致使綁定在這個io線程(EventLoop)上的全部channel上的事件得不處處理,引發各類超時,爲此,能夠爲這樣的handler單獨設置一個線程池EventExecutorGroup,這樣當執行到這個handler時,將從EventExecutorGroup取一個線程執行,可是此時要注意handler之間的共享訪問問題。線程

                 

 

 

       最後,盜用一張網絡的圖,從總體上介紹一下Netty的線程模型,便於理解。3d

                

 

一、Boss Group:做爲服務端 Acceptor 線程,用於 accept 客戶端連接,並轉發給 WorkerGroup 中的線程。Netty中雖然也能夠將Boss Group設置爲多個,可是在執行bind的時候只會綁定其中的一個,而不是同時綁定全部(相似nginx之前的驚羣效應)。blog

二、Worker Group:做爲 IO 線程,負責 IO 的讀寫,從 SocketChannel 中讀取報文或向 SocketChannel 寫入報文。隊列

三、Task Queue/Delay Task Queue:做爲定時任務線程,執行定時任務,例如鏈路空閒檢測和發送心跳消息等。

四、ExecutorGroup:業務自定義線程池,處理一些耗時任務。

相關文章
相關標籤/搜索