Netty是一個高性能、異步事件驅(qū)動的NIO框架,它提供了對TCP、UDP和文件傳輸?shù)闹С?,作為一個異步NIO框架,Netty的所有IO操作都是異步非阻塞的,通過Future-Listener機(jī)制,用戶可以方便的主動獲取或者通過通知機(jī)制獲得IO操作結(jié)果。

作為當(dāng)前最流行的NIO框架,Netty在互聯(lián)網(wǎng)領(lǐng)域、大數(shù)據(jù)分布式計(jì)算領(lǐng)域、游戲行業(yè)、通信行業(yè)等獲得了廣泛的應(yīng)用,一些業(yè)界著名的開源組件也基于Netty的NIO框架構(gòu)建。
為什么選擇Netty
Netty是業(yè)界最流行的NIO框架之一,它的健壯性、功能、性能、可定制性和可擴(kuò)展性在同類框架中都是首屈一指的,它已經(jīng)得到成百上千的商用項(xiàng)目驗(yàn)證,例如Hadoop的RPC框架avro使用Netty作為底層通信框架;很多其他業(yè)界主流的RPC框架,也使用Netty來構(gòu)建高性能的異步通信能力。
通過對Netty的分析,我們將它的優(yōu)點(diǎn)總結(jié)如下:
1.API使用簡單,開發(fā)門檻低;
2.功能強(qiáng)大,預(yù)置了多種編解碼功能,支持多種主流協(xié)議;
3.定制能力強(qiáng),可以通過ChannelHandler對通信框架進(jìn)行靈活地?cái)U(kuò)展;
4.性能高,通過與其他業(yè)界主流的NIO框架對比,Netty的綜合性能最優(yōu);
5.成熟、穩(wěn)定,Netty修復(fù)了已經(jīng)發(fā)現(xiàn)的所有JDK NIO BUG,業(yè)務(wù)開發(fā)人員不需要再為NIO的BUG而煩惱;
6.社區(qū)活躍,版本迭代周期短,發(fā)現(xiàn)的BUG可以被及時修復(fù),同時,更多的新功能會加入;
經(jīng)歷了大規(guī)模的商業(yè)應(yīng)用考驗(yàn),質(zhì)量得到驗(yàn)證。在互聯(lián)網(wǎng)、大數(shù)據(jù)、網(wǎng)絡(luò)游戲、企業(yè)應(yīng)用、電信軟件等眾多行業(yè)得到成功商用,證明了它已經(jīng)完全能夠滿足不同行業(yè)的商業(yè)應(yīng)用了。
Netty架構(gòu)分析
Netty 采用了比較典型的三層網(wǎng)絡(luò)架構(gòu)進(jìn)行設(shè)計(jì),邏輯架構(gòu)圖如下所示:

第一層:Reactor 通信調(diào)度層,它由一系列輔助類完成,包括 Reactor 線程 NioEventLoop 以及其父類、NioSocketChannel/NioServerSocketChannel 以及其父 類、ByteBuffer 以及由其衍生出來的各種 Buffer、Unsafe 以及其衍生出的各種內(nèi) 部類等。該層的主要職責(zé)就是監(jiān)聽網(wǎng)絡(luò)的讀寫和連接操作,負(fù)責(zé)將網(wǎng)絡(luò)層的數(shù)據(jù) 讀取到內(nèi)存緩沖區(qū)中,然后觸發(fā)各種網(wǎng)絡(luò)事件,例如連接創(chuàng)建、連接激活、讀事 件、寫事件等等,將這些事件觸發(fā)到 PipeLine 中,由 PipeLine 充當(dāng)?shù)穆氊?zé)鏈來 進(jìn)行后續(xù)的處理。
第二層:職責(zé)鏈 PipeLine,它負(fù)責(zé)事件在職責(zé)鏈中的有序傳播,同時負(fù)責(zé)動態(tài)的 編排職責(zé)鏈,職責(zé)鏈可以選擇監(jiān)聽和處理自己關(guān)心的事件,它可以攔截處理和向 后/向前傳播事件,不同的應(yīng)用的 Handler 節(jié)點(diǎn)的功能也不同,通常情況下,往往 會開發(fā)編解碼 Hanlder 用于消息的編解碼,它可以將外部的協(xié)議消息轉(zhuǎn)換成內(nèi)部 的 POJO 對象,這樣上層業(yè)務(wù)側(cè)只需要關(guān)心處理業(yè)務(wù)邏輯即可,不需要感知底層 的協(xié)議差異和線程模型差異,實(shí)現(xiàn)了架構(gòu)層面的分層隔離。
第三層:業(yè)務(wù)邏輯處理層,可以分為兩類:
1.純粹的業(yè)務(wù)邏輯 處理,例如訂單處理。
2.應(yīng)用層協(xié)議管理,例如HTTP協(xié)議、FTP協(xié)議等。
接下來,我從影響通信性能的三個方面(I/O模型、線程調(diào)度模型、序列化方式)來談?wù)凬etty的架構(gòu)。
I/O模型
傳統(tǒng)同步阻塞I/O模式如下圖所示:

它的弊端有很多:
1.性能問題:一連接一線程模型導(dǎo)致服務(wù)端的并發(fā)接入數(shù)和系統(tǒng)吞吐量受到極大限制;
2.可靠性問題:由于I/O操作采用同步阻塞模式,當(dāng)網(wǎng)絡(luò)擁塞或者通信對端處理緩慢會導(dǎo)致I/O線程被掛住,阻塞時間無法預(yù)測;
3.可維護(hù)性問題:I/O線程數(shù)無法有效控制、資源無法有效共享(多線程并發(fā)問題),系統(tǒng)可維護(hù)性差;
幾種I/O模型的功能和特性對比:

Netty的I/O模型基于非阻塞I/O實(shí)現(xiàn),底層依賴的是JDK NIO框架的Selector。
Selector提供選擇已經(jīng)就緒的任務(wù)的能力。簡單來講,Selector會不斷地輪詢注冊在其上的Channel,如果某個Channel上面有新的TCP連接接入、讀和寫事件,這個Channel就處于就緒狀態(tài),會被Selector輪詢出來,然后通過SelectionKey可以獲取就緒Channel的集合,進(jìn)行后續(xù)的I/O操作。
一個多路復(fù)用器Selector可以同時輪詢多個Channel,由于JDK1.5_update10版本(+)使用了epoll()代替?zhèn)鹘y(tǒng)的select實(shí)現(xiàn),所以它并沒有最大連接句柄1024/2048的限制。這也就意味著只需要一個線程負(fù)責(zé)Selector的輪詢,就可以接入成千上萬的客戶端,這確實(shí)是個非常巨大的技術(shù)進(jìn)步。
使用非阻塞I/O模型之后,Netty解決了傳統(tǒng)同步阻塞I/O帶來的性能、吞吐量和可靠性問題。
線程調(diào)度模型
常用的Reactor線程模型有三種,分別如下:
1.Reactor單線程模型:Reactor單線程模型,指的是所有的I/O操作都在同一個NIO線程上面完成。對于一些小容量應(yīng)用場景,可以使用單線程模型。
2.Reactor多線程模型:Rector多線程模型與單線程模型最大的區(qū)別就是有一組NIO線程處理I/O操作。主要用于高并發(fā)、大業(yè)務(wù)量場景。
3.主從Reactor多線程模型:主從Reactor線程模型的特點(diǎn)是服務(wù)端用于接收客戶端連接的不再是個1個單獨(dú)的NIO線程,而是一個獨(dú)立的NIO線程池。利用主從NIO線程模型,可以解決1個服務(wù)端監(jiān)聽線程無法有效處理所有客戶端連接的性能不足問題。
事實(shí)上,Netty的線程模型并非固定不變,通過在啟動輔助類中創(chuàng)建不同的EventLoopGroup實(shí)例并通過適當(dāng)?shù)膮?shù)配置,就可以支持上述三種Reactor線程模型。
在大多數(shù)場景下,并行多線程處理可以提升系統(tǒng)的并發(fā)性能。但是,如果對于共享資源的并發(fā)訪問處理不當(dāng),會帶來嚴(yán)重的鎖競爭,這最終會導(dǎo)致性能的下降。為了盡可能的避免鎖競爭帶來的性能損耗,可以通過串行化設(shè)計(jì),即消息的處理盡可能在同一個線程內(nèi)完成,期間不進(jìn)行線程切換,這樣就避免了多線程競爭和同步鎖。
為了盡可能提升性能,Netty采用了串行無鎖化設(shè)計(jì),在I/O線程內(nèi)部進(jìn)行串行操作,避免多線程競爭導(dǎo)致的性能下降。表面上看,串行化設(shè)計(jì)似乎CPU利用率不高,并發(fā)程度不夠。但是,通過調(diào)整NIO線程池的線程參數(shù),可以同時啟動多個串行化的線程并行運(yùn)行,這種局部無鎖化的串行線程設(shè)計(jì)相比一個隊(duì)列-多個工作線程模型性能更優(yōu)。

序列化方式
影響序列化性能的關(guān)鍵因素總結(jié)如下:
1.序列化后的碼流大小(網(wǎng)絡(luò)帶寬占用)
2.序列化&反序列化的性能(CPU資源占用)
3.并發(fā)調(diào)用的性能表現(xiàn):穩(wěn)定性、線性增長、偶現(xiàn)的時延毛刺等
對Java序列化和二進(jìn)制編碼分別進(jìn)行性能測試,編碼100萬次,測試結(jié)果表明:Java序列化的性能只有二進(jìn)制編碼的6.17%左右。

Netty默認(rèn)提供了對Google Protobuf的支持,通過擴(kuò)展Netty的編解碼接口,用戶可以實(shí)現(xiàn)其它的高性能序列化框架,例如Thrift的壓縮二進(jìn)制編解碼框架。
不同的應(yīng)用場景對序列化框架的需求也不同,對于高性能應(yīng)用場景Netty默認(rèn)提供了Google的Protobuf二進(jìn)制序列化框架,如果用戶對其它二進(jìn)制序列化框架有需求,也可以基于Netty提供的編解碼框架擴(kuò)展實(shí)現(xiàn)。
Netty架構(gòu)剖析之可靠性
Netty面臨的可靠性挑戰(zhàn):
1.作為RPC框架的基礎(chǔ)網(wǎng)絡(luò)通信框架,一旦故障將導(dǎo)致無法進(jìn)行遠(yuǎn)程服務(wù)(接口)調(diào)用。
2.作為應(yīng)用層協(xié)議的基礎(chǔ)通信框架,一旦故障將導(dǎo)致應(yīng)用協(xié)議棧無法正常工作。
3.網(wǎng)絡(luò)環(huán)境復(fù)雜(例如手游或者推送服務(wù)的GSM/3G/WIFI網(wǎng)絡(luò)),故障不可避免,業(yè)務(wù)卻不能中斷。
從應(yīng)用場景看,Netty是基礎(chǔ)的通信框架,一旦出現(xiàn)Bug,輕則需要重啟應(yīng)用,重則可能導(dǎo)致整個業(yè)務(wù)中斷。它的可靠性會影響整個業(yè)務(wù)集群的數(shù)據(jù)通信和交換,在當(dāng)今以分布式為主的軟件架構(gòu)體系中,通信中斷就意味著整個業(yè)務(wù)中斷,分布式架構(gòu)下對通信的可靠性要求非常高。
從運(yùn)行環(huán)境看,Netty會面臨惡劣的網(wǎng)絡(luò)環(huán)境,這就要求它自身的可靠性要足夠好,平臺能夠解決的可靠性問題需要由Netty自身來解決,否則會導(dǎo)致上層用戶關(guān)注過多的底層故障,這將降低Netty的易用性,同時增加用戶的開發(fā)和運(yùn)維成本。
Netty的可靠性是如此重要,它的任何故障都可能會導(dǎo)致業(yè)務(wù)中斷,蒙受巨大的經(jīng)濟(jì)損失。因此,Netty在版本的迭代中不斷加入新的可靠性特性來滿足用戶日益增長的高可靠和健壯性需求。
在此我向大家推薦一個架構(gòu)學(xué)習(xí)交流群。交流學(xué)習(xí)群號:478030634? 里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多
鏈路有效性檢測
Netty提供的心跳檢測機(jī)制分為三種:
1.讀空閑,鏈路持續(xù)時間t沒有讀取到任何消息;
2.寫空閑,鏈路持續(xù)時間t沒有發(fā)送任何消息;
3.讀寫空閑,鏈路持續(xù)時間t沒有接收或者發(fā)送任何消息。

當(dāng)網(wǎng)絡(luò)發(fā)生單通、連接被防火墻Hang住、長時間GC或者通信線程發(fā)生非預(yù)期異常時,會導(dǎo)致鏈路不可用且不易被及時發(fā)現(xiàn)。特別是異常發(fā)生在凌晨業(yè)務(wù)低谷期間,當(dāng)早晨業(yè)務(wù)高峰期到來時,由于鏈路不可用會導(dǎo)致瞬間的大批量業(yè)務(wù)失敗或者超時,這將對系統(tǒng)的可靠性產(chǎn)生重大的威脅。
從技術(shù)層面看,要解決鏈路的可靠性問題,必須周期性的對鏈路進(jìn)行有效性檢測。目前最流行和通用的做法就是心跳檢測。
心跳檢測機(jī)制分為三個層面:
1.TCP層面的心跳檢測,即TCP的Keep-Alive機(jī)制,它的作用域是整個TCP協(xié)議棧;
2.協(xié)議層的心跳檢測,主要存在于長連接協(xié)議中。例如SMPP協(xié)議;
3.應(yīng)用層的心跳檢測,它主要由各業(yè)務(wù)產(chǎn)品通過約定方式定時給對方發(fā)送心跳消息實(shí)現(xiàn)。
心跳檢測的目的就是確認(rèn)當(dāng)前鏈路可用,對方活著并且能夠正常接收和發(fā)送消息。做為高可靠的NIO框架,Netty也提供了基于鏈路空閑的心跳檢測機(jī)制:
1.讀空閑,鏈路持續(xù)時間t沒有讀取到任何消息;
2.寫空閑,鏈路持續(xù)時間t沒有發(fā)送任何消息;
3.讀寫空閑,鏈路持續(xù)時間t沒有接收或者發(fā)送任何消息。
流量整形
流量整形(Traffic Shaping)是一種主動調(diào)整流量輸出速率的措施。Netty的流量整形有兩個作用:
1.防止由于上下游網(wǎng)元性能不均衡導(dǎo)致下游網(wǎng)元被壓垮,業(yè)務(wù)流程中斷;
2.防止由于通信模塊接收消息過快,后端業(yè)務(wù)線程處理不及時導(dǎo)致的“撐死”問題。
流量整形的原理示意圖如下:

流量整形(Traffic Shaping)是一種主動調(diào)整流量輸出速率的措施。一個典型應(yīng)用是基于下游網(wǎng)絡(luò)結(jié)點(diǎn)的TP指標(biāo)來控制本地流量的輸出。流量整形與流量監(jiān)管的主要區(qū)別在于,流量整形對流量監(jiān)管中需要丟棄的報(bào)文進(jìn)行緩存——通常是將它們放入緩沖區(qū)或隊(duì)列內(nèi),也稱流量整形(Traffic Shaping,簡稱TS)。當(dāng)令牌桶有足夠的令牌時,再均勻的向外發(fā)送這些被緩存的報(bào)文。流量整形與流量監(jiān)管的另一區(qū)別是,整形可能會增加延遲,而監(jiān)管幾乎不引入額外的延遲。
Netty支持兩種流量整形模式:
1.全局流量整形:全局流量整形的作用范圍是進(jìn)程級的,無論你創(chuàng)建了多少個Channel,它的作用域針對所有的Channel。用戶可以通過參數(shù)設(shè)置:報(bào)文的接收速率、報(bào)文的發(fā)送速率、整形周期。
2.鏈路級流量整形:單鏈路流量整形與全局流量整形的最大區(qū)別就是它以單個鏈路為作用域,可以對不同的鏈路設(shè)置不同的整形策略。
優(yōu)雅停機(jī)
Netty的優(yōu)雅停機(jī)三部曲:
1.不再接收新消息
2.退出前的預(yù)處理操作
3.資源的釋放操作

Java的優(yōu)雅停機(jī)通常通過注冊JDK的ShutdownHook來實(shí)現(xiàn),當(dāng)系統(tǒng)接收到退出指令后,首先標(biāo)記系統(tǒng)處于退出狀態(tài),不再接收新的消息,然后將積壓的消息處理完,最后調(diào)用資源回收接口將資源銷毀,最后各線程退出執(zhí)行。
通常優(yōu)雅退出需要有超時控制機(jī)制,例如30S,如果到達(dá)超時時間仍然沒有完成退出前的資源回收等操作,則由停機(jī)腳本直接調(diào)用kill -9 pid,強(qiáng)制退出。
在實(shí)際項(xiàng)目中,Netty作為高性能的異步NIO通信框架,往往用作基礎(chǔ)通信框架負(fù)責(zé)各種協(xié)議的接入、解析和調(diào)度等,例如在RPC和分布式服務(wù)框架中,往往會使用Netty作為內(nèi)部私有協(xié)議的基礎(chǔ)通信框架。 當(dāng)應(yīng)用進(jìn)程優(yōu)雅退出時,作為通信框架的Netty也需要優(yōu)雅退出,主要原因如下:
盡快的釋放NIO線程、句柄等資源;
如果使用flush做批量消息發(fā)送,需要將積攢在發(fā)送隊(duì)列中的待發(fā)送消息發(fā)送完成;
正在write或者read的消息,需要繼續(xù)處理;
設(shè)置在NioEventLoop線程調(diào)度器中的定時任務(wù),需要執(zhí)行或者清理。
Netty架構(gòu)剖析之安全性
Netty面臨的安全挑戰(zhàn):
對第三方開放
作為應(yīng)用層協(xié)議的基礎(chǔ)通信框架

安全威脅場景分析:
對第三方開放的通信框架:如果使用Netty做RPC框架或者私有協(xié)議棧,RPC框架面向非授信的第三方開放,例如將內(nèi)部的一些能力通過服務(wù)對外開放出去,此時就需要進(jìn)行安全認(rèn)證,如果開放的是公網(wǎng)IP,對于安全性要求非常高的一些服務(wù),例如在線支付、訂購等,需要通過SSL/TLS進(jìn)行通信。
應(yīng)用層協(xié)議的安全性。作為高性能、異步事件驅(qū)動的NIO框架,Netty非常適合構(gòu)建上層的應(yīng)用層協(xié)議。由于絕大多數(shù)應(yīng)用層協(xié)議都是公有的,這意味著底層的Netty需要向上層提供通信層的安全傳輸功能。
SSL/TLS
Netty安全傳輸特性:
1.支持SSL V2和V3
2.支持TLS
3.支持SSL單向認(rèn)證、雙向認(rèn)證和第三方CA認(rèn)證。
SSL單向認(rèn)證流程圖如下:

Netty通過SslHandler提供了對SSL的支持,它支持的SSL協(xié)議類型包括:SSL V2、SSL V3和TLS。
單向認(rèn)證:單向認(rèn)證,即客戶端只驗(yàn)證服務(wù)端的合法性,服務(wù)端不驗(yàn)證客戶端。
雙向認(rèn)證:與單向認(rèn)證不同的是服務(wù)端也需要對客戶端進(jìn)行安全認(rèn)證。這就意味著客戶端的自簽名證書也需要導(dǎo)入到服務(wù)端的數(shù)字證書倉庫中。
CA認(rèn)證:基于自簽名的SSL雙向認(rèn)證,只要客戶端或者服務(wù)端修改了密鑰和證書,就需要重新進(jìn)行簽名和證書交換,這種調(diào)試和維護(hù)工作量是非常大的。因此,在實(shí)際的商用系統(tǒng)中往往會使用第三方CA證書頒發(fā)機(jī)構(gòu)進(jìn)行簽名和驗(yàn)證。我們的瀏覽器就保存了幾個常用的CA_ROOT。每次連接到網(wǎng)站時只要這個網(wǎng)站的證書是經(jīng)過這些CA_ROOT簽名過的。就可以通過驗(yàn)證了。
可擴(kuò)展的安全特性
通過Netty的擴(kuò)展特性,可以自定義安全策略:
1.IP地址黑名單機(jī)制
2.接入認(rèn)證
3.敏感信息加密或者過濾機(jī)制
IP地址黑名單是比較常用的弱安全保護(hù)策略,它的特點(diǎn)就是服務(wù)端在與客戶端通信的過程中,對客戶端的IP地址進(jìn)行校驗(yàn),如果發(fā)現(xiàn)對方IP在黑名單列表中,則拒絕與其通信,關(guān)閉鏈路。
接入認(rèn)證策略非常多,通常是較強(qiáng)的安全認(rèn)證策略,例如基于用戶名+密碼的認(rèn)證,認(rèn)證內(nèi)容往往采用加密的方式,例如Base64+AES等。
在此我向大家推薦一個架構(gòu)學(xué)習(xí)交流群。交流學(xué)習(xí)群號:478030634? 里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多
Netty架構(gòu)剖析之?dāng)U展性
通過Netty的擴(kuò)展特性,可以自定義安全策略:
1.線程模型可擴(kuò)展
2.序列化方式可擴(kuò)展
3.上層協(xié)議??蓴U(kuò)展
4.提供大量的網(wǎng)絡(luò)事件切面,方便用戶功能擴(kuò)展
Netty的架構(gòu)可擴(kuò)展性設(shè)計(jì)理念如下:
5.判斷擴(kuò)展點(diǎn),事先預(yù)留相關(guān)擴(kuò)展接口,給用戶二次定制和擴(kuò)展使用;
6.主要功能點(diǎn)都基于接口編程,方便用戶定制和擴(kuò)展。
注:給大家分享一個專門聊Java架構(gòu)等知識點(diǎn)的公眾號。
