Netty為什么高性能

Netty作為異步事件驅動的網絡,高性能之處主要來自于其I/O模型和線程處理模型,前者決定如何收發數據,后者決定如何處理數據

異步非阻塞通信

Netty的非阻塞I/O的實現關鍵是基于I/O復用模型,這里用Selector對象表示:


image

Netty的IO線程NioEventLoop由于聚合了多路復用器Selector,可以同時并發處理成百上千個客戶端連接。當線程從某客戶端Socket通道進行讀寫數據時,若沒有數據可用時,該線程可以進行其他任務。線程通常將非阻塞 IO 的空閑時間用于在其他通道上執行 IO 操作,所以單獨的線程可以管理多個輸入和輸出通道。

由于讀寫操作都是非阻塞的,這就可以充分提升IO線程的運行效率,避免由于頻繁I/O阻塞導致的線程掛起,一個I/O線程可以并發處理N個客戶端連接和讀寫操作,這從根本上解決了傳統同步阻塞I/O一連接一線程模型,架構的性能、彈性伸縮能力和可靠性都得到了極大的提升。

零拷貝

Netty的“零拷貝”主要體現在如下三個方面:

  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方式導致的內存拷貝問題。

零拷貝的實現原理面試場景

基于buffer

傳統的I/O是面向字節流或字符流的,以流式的方式順序地從一個Stream 中讀取一個或多個字節, 因此也就不能隨意改變讀取指針的位置。
在NIO中, 拋棄了傳統的 I/O流, 而是引入了Channel和Buffer的概念. 在NIO中, 只能從Channel中讀取數據到Buffer中或將數據 Buffer 中寫入到 Channel。
基于buffer操作不像傳統IO的順序操作, NIO 中可以隨意地讀取任意位置的數據

內存池

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

無鎖化的串行設計理念

在大多數場景下,并行多線程處理可以提升系統的并發性能。但是,如果對于共享資源的并發訪問處理不當,會帶來嚴重的鎖競爭,這最終會導致性能的下降。為了盡可能的避免鎖競爭帶來的性能損耗,可以通過串行化設計,即消息的處理盡可能在同一個線程內完成,期間不進行線程切換,這樣就避免了多線程競爭和同步鎖。

為了盡可能提升性能,Netty采用了串行無鎖化設計,在IO線程內部進行串行操作,避免多線程競爭導致的性能下降。表面上看,串行化設計似乎 CPU利用率不高,并發程度不夠。但是,通過調整NIO線程池的線程參數,可以同時啟動多個串行化的線程并行運行,這種局部無鎖化的串行線程設計相比一個 隊列-多個工作線程模型性能更優。

Netty的NioEventLoop讀取到消息之后,直接調用ChannelPipeline的fireChannelRead(Object msg),只要用戶不主動切換線程,一直會由NioEventLoop調用到用戶的Handler,期間不進行線程切換,這種串行化處理方式避免了多線程 操作導致的鎖的競爭,從性能角度看是最優的。

事件驅動模型

詳細請看Netty背后的事件驅動機制

Netty線程模型

詳細請看Netty線程模型

異步處理

異步的概念和同步相對。當一個異步過程調用發出后,調用者不能立刻得到結果。實際處理這個調用的部件在完成后,通過狀態、通知和回調來通知調用者。

Netty中的I/O操作是異步的,包括bind、write、connect等操作會簡單的返回一個ChannelFuture,調用者并不能立刻獲得結果,通過Future-Listener機制,用戶可以方便的主動獲取或者通過通知機制獲得IO操作結果。

當future對象剛剛創建時,處于非完成狀態,調用者可以通過返回的ChannelFuture來獲取操作執行的狀態,注冊監聽函數來執行完成后的操,常見有如下操作:

通過isDone方法來判斷當前操作是否完成
通過isSuccess方法來判斷已完成的當前操作是否成功
通過getCause方法來獲取已完成的當前操作失敗的原因
通過isCancelled方法來判斷已完成的當前操作是否被取消
通過addListener方法來注冊監聽器,當操作已完成(isDone方法返回完成),將會通知指定的監聽器;如果future對象已完成,則理解通知指定的監聽器

例如下面的的代碼中綁定端口是異步操作,當綁定操作處理完,將會調用相應的監聽器處理邏輯

serverBootstrap.bind(port).addListener(future -> {
       if (future.isSuccess()) {
           System.out.println(new Date() + ": 端口[" + port + "]綁定成功!");
       } else {
           System.err.println("端口[" + port + "]綁定失敗!");
       }
   });

相比傳統阻塞I/O,執行I/O操作后線程會被阻塞住, 直到操作完成;異步處理的好處是不會造成線程阻塞,線程在I/O操作期間可以執行別的程序,在高并發情形下會更穩定和更高的吞吐量。

高效的并發編程

  1. volatile的大量、正確使用;
  2. CAS和原子類的廣泛使用;
  3. 線程安全容器的使用;
  4. 通過讀寫鎖提升并發性能。

高性能的序列化框架

影響序列化性能的關鍵因素總結如下:

  1. 序列化后的碼流大?。ňW絡帶寬的占用);
  2. 序列化&反序列化的性能(CPU資源占用);
  3. 是否支持跨語言(異構系統的對接和開發語言切換)。

Netty默認提供了對Google Protobuf的支持,通過擴展Netty的編解碼接口,用戶可以實現其它的高性能序列化框架,例如Thrift的壓縮二進制編解碼框架。

靈活的TCP參數配置能力

合理設置TCP參數在某些場景下對于性能的提升可以起到顯著的效果,例如SO_RCVBUF和SO_SNDBUF。如果設置不當,對性能的影響是非常大的。下面總結下對性能影響比較大的幾個配置項:

  1. SO_RCVBUF和SO_SNDBUF:通常建議值為128K或者256K;
  2. SO_TCPNODELAY:NAGLE算法通過將緩沖區內的小封包自動相連,組成較大的封包,阻止大量小封包的發送阻塞網絡,從而提高網絡應用效率。但是對于時延敏感的應用場景需要關閉該優化算法;
  3. 軟中斷:如果Linux內核版本支持RPS(2.6.35以上版本),開啟RPS后可以實現軟中斷,提升網絡吞吐量。RPS根據數據包的源地址,目的地址以及目的和源端口,計算出一個hash值,然后根據這個hash值來選擇軟中斷運行的cpu,從上層來看,也就是說將每個連接和cpu綁定,并通過這個 hash值,來均衡軟中斷在多個cpu上,提升網絡并行處理性能。

參考:
Netty高性能之道
Netty的“零拷貝”


技術討論 & 疑問建議 & 個人博客

版權聲明: 本博客所有文章除特別聲明外,均采用 CC BY-NC-SA 3.0 許可協議,轉載請注明出處!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,626評論 2 370

推薦閱讀更多精彩內容