Netty系列之Netty可靠性分析--轉載

原文地址:http://www.infoq.com/cn/articles/netty-reliability程序員

1. 背景

1.1. 宕機的代價

1.1.1. 電信行業

畢馬威國際(KPMG International)在對46個國家的74家運營商進行調查後發現,全球通訊行業每一年的收益流失約爲400億美圓,佔總收入的1%-3%。致使收益流失的因素有多種,主要緣由就是計費BUG。編程

1.1.2. 互聯網行業

美國太平洋時間8月16日下午3點50分到3點55分(北京時間8月17日6點50分到6點55分),谷歌遭遇了宕機。根據過後統計,短短的5分鐘,谷歌損失了54.5萬美圓。也就是服務每中斷一分鐘,損失就達10.8萬美圓。後端

2013年,從美國東部時間8月19日下午2點45分開始,有用戶率先發現了亞馬遜網站出現宕機,大約在20多分鐘後又恢復正常。這次宕機讓亞馬遜每分鐘損失近6.7萬美圓,在宕機期間,消費者沒法經過Amazon.com、亞馬遜移動端以及Amazon.ca等網站進行購物。api

 

1.2. 軟件可靠性

軟件可靠性是指在給定時間內,特定環境下軟件無錯運行的機率。軟件可靠性包含了如下三個要素:緩存

1) 規定的時間:軟件可靠性只是體如今其運行階段,因此將運行時間做爲規定的時間的度量。運行時間包括軟件系統運行後工做與掛起(開啓但空閒)的累計時間。因爲軟件運行的環境與程序路徑選取的隨機性,軟件的失效爲隨機事件,因此運行時間屬於隨機變量;安全

2) 規定的環境條件:環境條件指軟件的運行環境。它涉及軟件系統運行時所需的各類支持要素,如支持硬件、操做系統、其它支持軟件、輸入數據格式和範圍以及操做規程等。不一樣的環境條件下軟件的可靠性是不一樣的。具體地說,規定的環境條件主要是描述軟件系統運行時計算機的配置狀況以及對輸入數據的要求,並假定其它一切因素都是理想的。有了明確規定的環境條件,還能夠有效判斷軟件失效的責任在用戶方仍是提供方;網絡

 

3) 規定的功能:軟件可靠性還與規定的任務和功能有關。因爲要完成的任務不一樣,軟件的運行剖面會有所區別,則調用的子模塊就不一樣(即程序路徑選擇不一樣),其可靠性也就可能不一樣。因此要準確度量軟件系統的可靠性必須首先明確它的任務和功能。架構

1.3. Netty的可靠性

首先,咱們要從Netty的主要用途來分析它的可靠性,Netty目前的主流用法有三種:框架

1) 構建RPC調用的基礎通訊組件,提供跨節點的遠程服務調用能力;運維

2) NIO通訊框架,用於跨節點的數據交換;

3) 其它應用協議棧的基礎通訊組件,例如HTTP協議以及其它基於Netty開發的應用層協議棧。

以阿里的分佈式服務框架Dubbo爲例,Netty是Dubbo RPC框架的核心。它的服務調用示例圖以下:

圖1-1 Dubbo的節點角色說明圖

其中,服務提供者和服務調用者之間能夠經過Dubbo協議進行RPC調用,消息的收發默認經過Netty完成。

經過對Netty主流應用場景的分析,咱們發現Netty面臨的可靠性問題大體分爲三類:

1) 傳統的網絡I/O故障,例如網絡閃斷、防火牆Hang住鏈接、網絡超時等;

2) NIO特有的故障,例如NIO類庫特有的BUG、讀寫半包處理異常、Reactor線程跑飛等等;

3) 編解碼相關的異常。

在大多數的業務應用場景中,一旦由於某些故障致使Netty不能正常工做,業務每每會陷入癱瘓。因此,從業務訴求來看,對Netty框架的可靠性要求是很是的高。做爲當前業界最流行的一款NIO框架,Netty在不一樣行業和領域都獲得了普遍的應用,它的高可靠性已經獲得了成百上千的生產系統檢驗。

Netty是如何支持系統高可靠性的?下面,咱們就從幾個不一樣維度出發一探究竟。

2. Netty高可靠性之道

2.1. 網絡通訊類故障

2.1.1. 客戶端鏈接超時

在傳統的同步阻塞編程模式下,客戶端Socket發起網絡鏈接,每每須要指定鏈接超時時間,這樣作的目的主要有兩個:

1) 在同步阻塞I/O模型中,鏈接操做是同步阻塞的,若是不設置超時時間,客戶端I/O線程可能會被長時間阻塞,這會致使系統可用I/O線程數的減小;

2) 業務層須要:大多數系統都會對業務流程執行時間有限制,例如WEB交互類的響應時間要小於3S。客戶端設置鏈接超時時間是爲了實現業務層的超時。

JDK原生的Socket鏈接接口定義以下:

圖2-1 JDK Socket鏈接超時接口

對於NIO的SocketChannel,在非阻塞模式下,它會直接返回鏈接結果,若是沒有鏈接成功,也沒有發生IO異常,則須要將SocketChannel註冊到Selector上監聽鏈接結果。因此,異步鏈接的超時沒法在API層面直接設置,而是須要經過定時器來主動監測。

下面咱們首先看下JDK NIO類庫的SocketChannel鏈接接口定義:

圖2-2 JDK NIO 類庫SocketChannel鏈接接口

從上面的接口定義能夠看出,NIO類庫並無現成的鏈接超時接口供用戶直接使用,若是要在NIO編程中支持鏈接超時,每每須要NIO框架或者用戶本身封裝實現。

下面咱們看下Netty是如何支持鏈接超時的,首先,在建立NIO客戶端的時候,能夠配置鏈接超時參數:

圖2-3 Netty客戶端建立支持設置鏈接超時參數

設置完鏈接超時以後,Netty在發起鏈接的時候,會根據超時時間建立ScheduledFuture掛載在Reactor線程上,用於定時監測是否發生鏈接超時,相關代碼以下:

圖2-4 根據鏈接超時建立超時監測定時任務

建立鏈接超時定時任務以後,會由NioEventLoop負責執行。若是已經鏈接超時,可是服務端仍然沒有返回TCP握手應答,則關閉鏈接,代碼如上圖所示。

若是在超時期限內處理完成鏈接操做,則取消鏈接超時定時任務,相關代碼以下:

圖2-5 取消鏈接超時定時任務

Netty的客戶端鏈接超時參數與其它經常使用的TCP參數一塊兒配置,使用起來很是方便,上層用戶不用關心底層的超時實現機制。這既知足了用戶的個性化需求,又實現了故障的分層隔離。

2.1.2. 通訊對端強制關閉鏈接

在客戶端和服務端正常通訊過程當中,若是發生網絡閃斷、對方進程忽然宕機或者其它非正常關閉鏈路事件時,TCP鏈路就會發生異常。因爲TCP是全雙工的,通訊雙方都須要關閉和釋放Socket句柄纔不會發生句柄的泄漏。

在實際的NIO編程過程當中,咱們常常會發現因爲句柄沒有被及時關閉致使的功能和可靠性問題。究其緣由總結以下:

1) IO的讀寫等操做並不是僅僅集中在Reactor線程內部,用戶上層的一些定製行爲可能會致使IO操做的外逸,例如業務自定義心跳機制。這些定製行爲加大了統一異常處理的難度,IO操做愈加散,故障發生的機率就越大;

2) 一些異常分支沒有考慮到,因爲外部環境誘因致使程序進入這些分支,就會引發故障。

下面咱們經過故障模擬,看Netty是如何處理對端鏈路強制關閉異常的。首先啓動Netty服務端和客戶端,TCP鏈路創建成功以後,雙方維持該鏈路,查看鏈路狀態,結果以下:

圖2-6 Netty服務端和客戶端TCP鏈路狀態正常

強制關閉客戶端,模擬客戶端宕機,服務端控制檯打印以下異常:

圖2-7 模擬TCP鏈路故障

從堆棧信息能夠判斷,服務端已經監控到客戶端強制關閉了鏈接,下面咱們看下服務端是否已經釋放了鏈接句柄,再次執行netstat命令,執行結果以下:

圖2-8 查看故障鏈路狀態

從執行結果能夠看出,服務端已經關閉了和客戶端的TCP鏈接,句柄資源正常釋放。由此能夠得出結論,Netty底層已經自動對該故障進行了處理。

下面咱們一塊兒看下Netty是如何感知到鏈路關閉異常並進行正確處理的,查看AbstractByteBuf的writeBytes方法,它負責將指定Channel的緩衝區數據寫入到ByteBuf中,詳細代碼以下:

圖2-9 AbstractByteBuf的writeBytes方法

在調用SocketChannel的read方法時發生了IOException,代碼以下:

圖2-10 讀取緩衝區數據發生IO異常

爲了保證IO異常被統一處理,該異常向上拋,由AbstractNioByteChannel進行統一異常處理,代碼以下:

圖2-11 鏈路異常退出異常處理

爲了可以對異常策略進行統一,也爲了方便維護,防止處理不當致使的句柄泄漏等問題,句柄的關閉,統一調用AbstractChannel的close方法,代碼以下:

圖2-12 統一的Socket句柄關閉接口

2.1.3. 正常的鏈接關閉

對於短鏈接協議,例如HTTP協議,通訊雙方數據交互完成以後,一般按照雙方的約定由服務端關閉鏈接,客戶端得到TCP鏈接關閉請求以後,關閉自身的Socket鏈接,雙方正式斷開鏈接。

在實際的NIO編程過程當中,常常存在一種誤區:認爲只要是對方關閉鏈接,就會發生IO異常,捕獲IO異常以後再關閉鏈接便可。實際上,鏈接的合法關閉不會發生IO異常,它是一種正常場景,若是遺漏了該場景的判斷和處理就會致使鏈接句柄泄漏。

下面咱們一塊兒模擬故障,看Netty是如何處理的。測試場景設計以下:改造下Netty客戶端,雙發鏈路創建成功以後,等待120S,客戶端正常關閉鏈路。看服務端是否可以感知並釋放句柄資源。

首先啓動Netty客戶端和服務端,雙方TCP鏈路鏈接正常:

圖2-13 TCP鏈接狀態正常

120S以後,客戶端關閉鏈接,進程退出,爲了可以看到整個處理過程,咱們在服務端的Reactor線程處設置斷點,先不作處理,此時鏈路狀態以下:

圖2-14 TCP鏈接句柄等待釋放

從上圖能夠看出,此時服務端並無關閉Socket鏈接,鏈路處於CLOSE_WAIT狀態,放開代碼讓服務端執行完,結果以下:

圖2-15 TCP鏈接句柄正常釋放

下面咱們一塊兒看下服務端是如何判斷出客戶端關閉鏈接的,當鏈接被對方合法關閉後,被關閉的SocketChannel會處於就緒狀態,SocketChannel的read操做返回值爲-1,說明鏈接已經被關閉,代碼以下:

圖2-16 須要對讀取的字節數進行判斷

若是SocketChannel被設置爲非阻塞,則它的read操做可能返回三個值:

1) 大於0,表示讀取到了字節數;

2) 等於0,沒有讀取到消息,可能TCP處於Keep-Alive狀態,接收到的是TCP握手消息;

3) -1,鏈接已經被對方合法關閉。

經過調試,咱們發現,NIO類庫的返回值確實爲-1:

圖2-17 鏈路正常關閉,返回值爲-1

得知鏈接關閉以後,Netty將關閉操做位設置爲true,關閉句柄,代碼以下:

圖2-18 鏈接正常關閉,釋放資源

2.1.4. 故障定製

在大多數場景下,當底層網絡發生故障的時候,應該由底層的NIO框架負責釋放資源,處理異常等。上層的業務應用不須要關心底層的處理細節。可是,在一些特殊的場景下,用戶可能須要感知這些異常,並針對這些異常進行定製處理,例如:

1) 客戶端的斷連重連機制;

2) 消息的緩存重發;

3) 接口日誌中詳細記錄故障細節;

4) 運維相關功能,例如告警、觸發郵件/短信等

Netty的處理策略是發生IO異常,底層的資源由它負責釋放,同時將異常堆棧信息以事件的形式通知給上層用戶,由用戶對異常進行定製。這種處理機制既保證了異常處理的安全性,也向上層提供了靈活的定製能力。

具體接口定義以及默認實現以下:

圖2-19 故障定製接口

用戶能夠覆蓋該接口,進行個性化的異常定製。例如發起重連等。

2.2. 鏈路的有效性檢測

當網絡發生單通、鏈接被防火牆Hang住、長時間GC或者通訊線程發生非預期異常時,會致使鏈路不可用且不易被及時發現。特別是異常發生在凌晨業務低谷期間,當早晨業務高峯期到來時,因爲鏈路不可用會致使瞬間的大批量業務失敗或者超時,這將對系統的可靠性產生重大的威脅。

從技術層面看,要解決鏈路的可靠性問題,必須週期性的對鏈路進行有效性檢測。目前最流行和通用的作法就是心跳檢測。

心跳檢測機制分爲三個層面:

1) TCP層面的心跳檢測,即TCP的Keep-Alive機制,它的做用域是整個TCP協議棧;

2) 協議層的心跳檢測,主要存在於長鏈接協議中。例如SMPP協議;

3) 應用層的心跳檢測,它主要由各業務產品經過約定方式定時給對方發送心跳消息實現。

心跳檢測的目的就是確認當前鏈路可用,對方活着而且可以正常接收和發送消息。

作爲高可靠的NIO框架,Netty也提供了心跳檢測機制,下面咱們一塊兒熟悉下心跳的檢測原理。

圖2-20 心跳檢測機制

不一樣的協議,心跳檢測機制也存在差別,概括起來主要分爲兩類:

1) Ping-Pong型心跳:由通訊一方定時發送Ping消息,對方接收到Ping消息以後,當即返回Pong應答消息給對方,屬於請求-響應型心跳;

2) Ping-Ping型心跳:不區分心跳請求和應答,由通訊雙方按照約定定時向對方發送心跳Ping消息,它屬於雙向心跳。

心跳檢測策略以下:

1) 連續N次心跳檢測都沒有收到對方的Pong應答消息或者Ping請求消息,則認爲鏈路已經發生邏輯失效,這被稱做心跳超時;

2) 讀取和發送心跳消息的時候如何直接發生了IO異常,說明鏈路已經失效,這被稱爲心跳失敗。

不管發生心跳超時仍是心跳失敗,都須要關閉鏈路,由客戶端發起重連操做,保證鏈路可以恢復正常。

Netty的心跳檢測其實是利用了鏈路空閒檢測機制實現的,相關代碼以下:

圖2-21 心跳檢測的代碼包路徑

Netty提供的空閒檢測機制分爲三種:

1) 讀空閒,鏈路持續時間t沒有讀取到任何消息;

2) 寫空閒,鏈路持續時間t沒有發送任何消息;

3) 讀寫空閒,鏈路持續時間t沒有接收或者發送任何消息。

Netty的默認讀寫空閒機制是發生超時異常,關閉鏈接,可是,咱們能夠定製它的超時實現機制,以便支持不一樣的用戶場景。

WriteTimeoutHandler的超時接口以下:

圖2-22 寫超時

ReadTimeoutHandler的超時接口以下:

圖2-23 讀超時

讀寫空閒的接口以下:

圖2-24 讀寫空閒

利用Netty提供的鏈路空閒檢測機制,能夠很是靈活的實現協議層的心跳檢測。在《Netty權威指南》中的私有協議棧設計和開發章節,我利用Netty提供的自定義Task接口實現了另外一種心跳檢測機制,感興趣的朋友能夠參閱該書。

2.3. Reactor線程的保護

Reactor線程是IO操做的核心,NIO框架的發動機,一旦出現故障,將會致使掛載在其上面的多路用複用器和多個鏈路沒法正常工做。所以它的可靠性要求很是高。

筆者就曾經遇到過由於異常處理不當致使Reactor線程跑飛,大量業務請求處理失敗的故障。下面咱們一塊兒看下Netty是如何有效提高Reactor線程的可靠性的。

2.3.1. 異常處理要小心

儘管Reactor線程主要處理IO操做,發生的異常一般是IO異常,可是,實際上在一些特殊場景下會發生非IO異常,若是僅僅捕獲IO異常可能就會致使Reactor線程跑飛。爲了防止發生這種意外,在循環體內必定要捕獲Throwable,而不是IO異常或者Exception。

Netty的相關代碼以下:

圖2-25 Reactor線程異常保護

捕獲Throwable以後,即使發生了意外未知對異常,線程也不會跑飛,它休眠1S,防止死循環致使的異常繞接,而後繼續恢復執行。這樣處理的核心理念就是:

1) 某個消息的異常不該該致使整條鏈路不可用;

2) 某條鏈路不可用不該該致使其它鏈路不可用;

3) 某個進程不可用不該該致使其它集羣節點不可用。

2.3.2. 死循環保護

一般狀況下,死循環是可檢測、可預防可是沒法徹底避免的。Reactor線程一般處理的都是IO相關的操做,所以咱們重點關注IO層面的死循環。

JDK NIO類庫最著名的就是 epoll bug了,它會致使Selector空輪詢,IO線程CPU 100%,嚴重影響系統的安全性和可靠性。

SUN在JKD1.6 update18版本聲稱解決了該BUG,可是根據業界的測試和你們的反饋,直到JDK1.7的早期版本,該BUG依然存在,並無徹底被修復。發生該BUG的主機資源佔用圖以下:

圖2-26 epoll bug CPU空輪詢

SUN在解決該BUG的問題上不給力,只能從NIO框架層面進行問題規避,下面咱們看下Netty是如何解決該問題的。

Netty的解決策略:

1) 根據該BUG的特徵,首先偵測該BUG是否發生;

2) 將問題Selector上註冊的Channel轉移到新建的Selector上;

3) 老的問題Selector關閉,使用新建的Selector替換。

下面具體看下代碼,首先檢測是否發生了該BUG:

圖2-27 epoll bug 檢測

一旦檢測發生該BUG,則重建Selector,代碼以下:

圖2-28 重建Selector

重建完成以後,替換老的Selector,代碼以下:

圖2-29 替換Selector

大量生產系統的運行代表,Netty的規避策略能夠解決epoll bug 致使的IO線程CPU死循環問題。

2.4. 優雅退出

Java的優雅停機一般經過註冊JDK的ShutdownHook來實現,當系統接收到退出指令後,首先標記系統處於退出狀態,再也不接收新的消息,而後將積壓的消息處理完,最後調用資源回收接口將資源銷燬,最後各線程退出執行。

一般優雅退出有個時間限制,例如30S,若是到達執行時間仍然沒有完成退出前的操做,則由監控腳本直接kill -9 pid,強制退出。

Netty的優雅退出功能隨着版本的優化和演進也在不斷的加強,下面咱們一塊兒看下Netty5的優雅退出。

首先看下Reactor線程和線程組,它們提供了優雅退出接口。EventExecutorGroup的接口定義以下:

圖2-30 EventExecutorGroup優雅退出

NioEventLoop的資源釋放接口實現:

圖2-31 NioEventLoop資源釋放

ChannelPipeline的關閉接口:

圖2-32 ChannelPipeline關閉接口

目前Netty向用戶提供的主要接口和類庫都提供了資源銷燬和優雅退出的接口,用戶的自定義實現類能夠繼承這些接口,完成用戶資源的釋放和優雅退出。

2.5. 內存保護

2.5.1. 緩衝區的內存泄漏保護

爲了提高內存的利用率,Netty提供了內存池和對象池。可是,基於緩存池實現之後須要對內存的申請和釋放進行嚴格的管理,不然很容易致使內存泄漏。

若是不採用內存池技術實現,每次對象都是以方法的局部變量形式被建立,使用完成以後,只要再也不繼續引用它,JVM會自動釋放。可是,一旦引入內存池機制,對象的生命週期將由內存池負責管理,這一般是個全局引用,若是不顯式釋放JVM是不會回收這部份內存的。

對於Netty的用戶而言,使用者的技術水平差別很大,一些對JVM內存模型和內存泄漏機制不瞭解的用戶,可能只記得申請內存,忘記主動釋放內存,特別是JAVA程序員。

爲了防止由於用戶遺漏致使內存泄漏,Netty在Pipe line的尾Handler中自動對內存進行釋放,相關代碼以下:

圖2-33 TailHandler的內存回收操做

對於內存池,實際就是將緩衝區從新放到內存池中循環使用,代碼以下:

圖2-34 PooledByteBuf的內存回收操做

2.5.2. 緩衝區內存溢出保護

作過協議棧的讀者都知道,當咱們對消息進行解碼的時候,須要建立緩衝區。緩衝區的建立方式一般有兩種:

1) 容量預分配,在實際讀寫過程當中若是不夠再擴展;

2) 根據協議消息長度建立緩衝區。

在實際的商用環境中,若是遇到畸形碼流攻擊、協議消息編碼異常、消息丟包等問題時,可能會解析到一個超長的長度字段。筆者曾經遇到過相似問題,報文長度字段值居然是2G多,因爲代碼的一個分支沒有對長度上限作有效保護,結果致使內存溢出。系統重啓後幾秒內再次內存溢出,幸虧及時定位出問題根因,險些釀成嚴重的事故。

Netty提供了編解碼框架,所以對於解碼緩衝區的上限保護就顯得很是重要。下面,咱們看下Netty是如何對緩衝區進行上限保護的:

首先,在內存分配的時候指定緩衝區長度上限:

圖2-35 緩衝區分配器能夠指定緩衝區最大長度

其次,在對緩衝區進行寫入操做的時候,若是緩衝區容量不足須要擴展,首先對最大容量進行判斷,若是擴展後的容量超過上限,則拒絕擴展:

圖2-35 緩衝區擴展上限保護

最後,在解碼的時候,對消息長度進行判斷,若是超過最大容量上限,則拋出解碼異常,拒絕分配內存:

圖2-36 超出容量上限的半包解碼,失敗

圖2-37 拋出TooLongFrameException異常

2.6. 流量整形

大多數的商用系統都有多個網元或者部件組成,例如參與短信互動,會涉及到手機、基站、短信中心、短信網關、SP/CP等網元。不一樣網元或者部件的處理性能不一樣。爲了防止由於浪涌業務或者下游網元性能低致使下游網元被壓垮,有時候須要系統提供流量整形功能。

下面咱們一塊兒看下流量整形(traffic shaping)的定義:流量整形(Traffic Shaping)是一種主動調整流量輸出速率的措施。一個典型應用是基於下游網絡結點的TP指標來控制本地流量的輸出。流量整形與流量監管的主要區別在於,流量整形對流量監管中須要丟棄的報文進行緩存——一般是將它們放入緩衝區或隊列內,也稱流量整形(Traffic Shaping,簡稱TS)。當令牌桶有足夠的令牌時,再均勻的向外發送這些被緩存的報文。流量整形與流量監管的另外一區別是,整形可能會增長延遲,而監管幾乎不引入額外的延遲。

流量整形的原理示意圖以下:

圖2-38 流量整形原理圖

做爲高性能的NIO框架,Netty的流量整形有兩個做用:

1) 防止因爲上下游網元性能不均衡致使下游網元被壓垮,業務流程中斷;

2) 防止因爲通訊模塊接收消息過快,後端業務線程處理不及時致使的「撐死」問題。

下面咱們就具體學習下Netty的流量整形功能。

2.6.1. 全局流量整形

全局流量整形的做用範圍是進程級的,不管你建立了多少個Channel,它的做用域針對全部的Channel。

用戶能夠經過參數設置:報文的接收速率、報文的發送速率、整形週期。相關的接口以下所示:

圖2-39 全局流量整形參數設置

Netty流量整形的原理是:對每次讀取到的ByteBuf可寫字節數進行計算,獲取當前的報文流量,而後與流量整形閾值對比。若是已經達到或者超過了閾值。則計算等待時間delay,將當前的ByteBuf放到定時任務Task中緩存,由定時任務線程池在延遲delay以後繼續處理該ByteBuf。相關代碼以下:

圖2-40 動態計算當前流量

若是達到整形閾值,則對新接收的ByteBuf進行緩存,放入線程池的消息隊列中,稍後處理,代碼以下:

圖2-41 緩存當前的ByteBuf

定時任務的延時時間根據檢測週期T和流量整形閾值計算得來,代碼以下:

圖2-42 計算緩存等待週期

須要指出的是,流量整形的閾值limit越大,流量整形的精度越高,流量整形功能是可靠性的一種保障,它沒法作到100%的精確。這個跟後端的編解碼以及緩衝區的處理策略相關,此處再也不贅述。感興趣的朋友能夠思考下,Netty爲何不作到 100%的精確。

流量整形與流控的最大區別在於流控會拒絕消息,流量整形不拒絕和丟棄消息,不管接收量多大,它總能以近似恆定的速度下發消息,跟變壓器的原理和功能相似。

2.6.2. 單條鏈路流量整形

除了全局流量整形,Netty也支持但鏈路的流量整形,相關的接口定義以下:

圖2-43 單鏈路流量整形

單鏈路流量整形與全局流量整形的最大區別就是它以單個鏈路爲做用域,能夠對不一樣的鏈路設置不一樣的整形策略。

它的實現原理與全局流量整形相似,咱們再也不贅述。值得說明的是,Netty支持用戶自定義流量整形策略,經過繼承AbstractTrafficShapingHandler的doAccounting方法能夠定製整形策略。相關接口定義以下:

圖2-44 定製流量整形策略

3. 總結

儘管Netty在架構可靠性上面已經作了不少精細化的設計,以及基於防護式編程對系統進行了大量可靠性保護。可是,系統的可靠性是個持續投入和改進的過程,不可能在一個版本中一蹴而就,可靠性工做任重而道遠。

從業務的角度看,不一樣的行業、應用場景對可靠性的要求也是不一樣的,例如電信行業的可靠性要求是5個9,對於鐵路等特殊行業,可靠性要求更高,達到6個9。對於企業的一些邊緣IT系統,可靠性要求會低些。

可靠性是一種投資,對於企業而言,追求極端可靠性對研發成本是個沉重的包袱,可是相反,若是不重視系統的可靠性,一旦不幸遭遇網上事故,損失每每也是驚人的。

對於架構師和設計師,如何權衡架構的可靠性和其它特性的關係,是一個很大的挑戰。經過研究和學習Netty的可靠性設計,也許可以給你們帶來一些啓示。

4. Netty學習推薦書籍

目前市面上介紹netty的文章不少,若是讀者但願系統性的學習Netty,推薦兩本書:

1) 《Netty in Action》

2) 《Netty權威指南》

5.做者簡介

李林鋒,2007年畢業於東北大學,2008年進入華爲公司從事高性能通訊軟件的設計和開發工做,有6年NIO設計和開發經驗,精通Netty、Mina等NIO框架。Netty中國社區創始人,《Netty權威指南》做者。

相關文章
相關標籤/搜索