公司CTO:高性能開發,你不會Netty,怎麼好意思拿20K?

**主管:**這個版塊用Netty框架就可以了呀,不會嗎?

(此時,公司CTO路過)

**某程序員:**這個我真不會…

**主管:**好了好了,那這一塊我交給別人去做,這個也不難啊?!

**某程序員:**大佬,我一定會好好學習,早日把這一塊弄懂!

**主管:**行了,你先去忙吧!

**CTO:**慢着!這是什麼情況?項目分配下去了,怎麼能又安排其他同事來加班做呢?

**主管:**總監,項目這個版塊涉及到高性能的開發,這個同事可能搞不定,眼看着項目要上線了,還是讓經驗豐富的工程師來做吧!

**CTO(兇狠的對着程序員):**那也不行,拿着這麼高的工資,這都做不了,Netty都不會用,你怎麼好意思拿20K的?

**某程序員(委屈地):**大佬,我每個月只有8K…

CTO:…哦,算了,當我沒來


我不記得是誰跟我說過,“十個高性能,九個用Netty”,我也不知道是騙我的還是咋的…

Netty到底有這麼重要嗎?

我翻閱了一下我手中的各大廠面試真題,問BIO、NIO、異步這一塊的也有,Netty出現的頻次不算很高,也許我看的是初中級的面試題吧。

無論怎麼說,想要漲薪升職,高性能、高併發、高可用你就不得不會。

這裏,我就來分享一些Netty相關的核心技術點:

注:由於篇幅原因,我就簡單的提取其中部分,獲取完整內容及高清導圖,私信【高性能】免費領取!

Netty 原理

Netty 是一個高性能、異步事件驅動的 NIO 框架,基於 JAVA NIO 提供的 API 實現。它提供了對TCP、UDP 和文件傳輸的支持,作爲一個異步 NIO 框架,Netty 的所有 IO 操作都是異步非阻塞的,通過 Future-Listener 機制,用戶可以方便的主動獲取或者通過通知機制獲得 IO 操作結果。

Netty 高性能

在 IO 編程過程中,當需要同時處理多個客戶端接入請求時,可以利用多線程或者 IO 多路複用技術進行處理。IO 多路複用技術通過把多個 IO 的阻塞複用到同一個 select 的阻塞上,從而使得系統在單線程的情況下可以同時處理多個客戶端請求。與傳統的多線程/多進程模型比,I/O 多路複用的最大優勢是系統開銷小,系統不需要創建新的額外進程或者線程,也不需要維護這些進程和線程的運行,降低了系統的維護工作量,節省了系統資源。

與 Socket 類和 ServerSocket 類相對應,NIO 也提供了 SocketChannel 和 ServerSocketChannel兩種不同的套接字通道實現。

1、多路複用通訊方式

Netty 架構按照 Reactor 模式設計和實現,它的服務端通信序列圖如下:

客戶端通信序列圖如下:

Netty 的 IO 線程 NioEventLoop 由於聚合了多路複用器 Selector,可以同時併發處理成百上千個客戶端 Channel,由於讀寫操作都是非阻塞的,這就可以充分提升 IO 線程的運行效率,避免由於頻繁 IO 阻塞導致的線程掛起。

  • 異步通訊 NIO

由於 Netty 採用了異步通信模式,一個 IO 線程可以併發處理 N 個客戶端連接和讀寫操作,這從根本上解決了傳統同步阻塞 IO 一連接一線程模型,架構的性能、彈性伸縮能力和可靠性都得到了極大的提升。

  • 零拷貝(DIRECT BUFFERS 使用堆外直接內存)

1、Netty 的接收和發送 ByteBuffer 採用 DIRECT BUFFERS,使用堆外直接內存進行 Socket 讀寫,不需要進行字節緩衝區的二次拷貝。如果使用傳統的堆內存(HEAP BUFFERS)進行 Socket 讀寫,JVM 會將堆內存 Buffer 拷貝一份到直接內存中,然後才寫入 Socket 中。相比於堆外直接內存,消息在發送過程中多了一次緩衝區的內存拷貝。

2、Netty 提供了組合 Buffer 對象,可以聚合多個 ByteBuffer 對象,用戶可以像操作一個 Buffer 那樣方便的對組合 Buffer 進行操作,避免了傳統通過內存拷貝的方式將幾個小 Buffer 合併成一個大的Buffer。

3、Netty的文件傳輸採用了transferTo方法,它可以直接將文件緩衝區的數據發送到目標Channel,避免了傳統通過循環 write 方式導致的內存拷貝問題。

  • 內存池(基於內存池的緩衝區重用機制)

隨着 JVM 虛擬機和 JIT 即時編譯技術的發展,對象的分配和回收是個非常輕量級的工作。但是對於緩衝區 Buffer,情況卻稍有不同,特別是對於堆外直接內存的分配和回收,是一件耗時的操作。爲了儘量重用緩衝區,Netty 提供了基於內存池的緩衝區重用機制。

  • 高效的 Reactor 線程模型

常用的 Reactor 線程模型有三種,Reactor 單線程模型, Reactor 多線程模型, 主從 Reactor 多線程模型。

Reactor 單線程模型

指的是所有的 IO 操作都在同一個 NIO 線程上面完成,NIO 線程的職責如下:

  1. 作爲 NIO 服務端,接收客戶端的 TCP 連接;

  2. 作爲 NIO 客戶端,向服務端發起 TCP 連接;

  3. 讀取通信對端的請求或者應答消息;

  4. 向通信對端發送消息請求或者應答消息。

由於 Reactor 模式使用的是異步非阻塞 IO,所有的 IO 操作都不會導致阻塞,理論上一個線程可以獨立處理所有 IO 相關的操作。從架構層面看,一個 NIO 線程確實可以完成其承擔的職責。例如,通過Acceptor 接收客戶端的 TCP 連接請求消息,鏈路建立成功之後,通過 Dispatch 將對應的 ByteBuffer派發到指定的 Handler 上進行消息解碼。用戶 Handler 可以通過 NIO 線程將消息發送給客戶端。

Reactor 多線程模型

Reactor 多線程模型與單線程模型最大的區別就是有一組 NIO 線程處理 IO 操作。 有專門一個NIO 線程-Acceptor 線程用於監聽服務端,接收客戶端的 TCP 連接請求; 網絡 IO 操作-讀、寫等由一個 NIO 線程池負責,線程池可以採用標準的 JDK 線程池實現,它包含一個任務隊列和 N個可用的線程,由這些 NIO 線程負責消息的讀取、解碼、編碼和發送;

主從 Reactor 多線程模型

服務端用於接收客戶端連接的不再是個 1 個單獨的 NIO 線程,而是一個獨立的 NIO 線程池。Acceptor 接收到客戶端 TCP 連接請求處理完成後(可能包含接入認證等),將新創建的SocketChannel 註冊到 IO 線程池(sub reactor 線程池)的某個 IO 線程上,由它負責SocketChannel 的讀寫和編解碼工作。Acceptor 線程池僅僅只用於客戶端的登陸、握手和安全認證,一旦鏈路建立成功,就將鏈路註冊到後端 subReactor 線程池的 IO 線程上,由 IO 線程負責後續的 IO 操作。

等等…

Netty RPC 實現

概念

RPC,即 Remote Procedure Call(遠程過程調用),調用遠程計算機上的服務,就像調用本地服務一樣。RPC 可以很好的解耦系統,如 WebService 就是一種基於 Http 協議的 RPC。這個 RPC 整體框架如下:

等等…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章