天天看點

【NIO系列】——之Netty

如果你看過前面三篇文章,我們從最低層來分解nio底層原理和使用方式,幫忙我們了解了nio是什麼,解決了什麼問題,以及又有那些不足。

原則上nio的出現,已經提升和加快了網絡io的處理方式,但它隻能幫忙我們解決了io層次的讀寫問題,在軟體層次上我們需要更好的程式設計架構模型,來解決擴充性以及高并發的問題。netty正是用來解決這些問題的,這一篇我們将詳細介紹netty的知識點。

一、netty是什麼

我們采用官方的話來說:

netty是一個高性能、異步事件驅動的網絡應用架構。 基于netty,可以快速的開發和部署高性能、 高可用的網絡服務端和用戶端應用。

簡單來說,它是一個網絡應用架構,幫你解決面向網絡開發中的三個問題:

面向網絡io的讀寫,如tcp的socket連接配接 應用層協定編解碼,如http協定 高并發架構

那麼他有哪些優點?

fast —性能強悍,高并發,低延遲 easy —高擴充,api使用簡單,開發門檻低 non-blocking — 無阻塞,支援nio
【NIO系列】——之Netty

對于我們用慣了web容器的人來說,第一個疑惑就是netty究竟能幹什麼,為何要用它。既然netty是一個網絡應用架構,這些明明tomcat也能幫我們解決了,為何還要用netty?

netty和tomcat的不同,主要在以下幾點:

tomcat是一個「http server」,更準确的說是一個「servlet/jsp」應用的容器,它主要解決的是 http 協定層面的傳輸和通路。 http是一種應用層協定,應用層的協定除了http以外,還有面向郵局協定的pop和imap,以及ftp、ldap、ssh、tls/ssl等其他協定。 netty 不僅可以支援http,還可以支援ftp、ldap、ssh、tls/ssl等應用層多數的協定,另外還支援自定義的應用層協定,隻要你有這方面的需求,它足夠靈活。 netty 雖然按歸類上算屬于osi的第七層【應用層】,但它的存在是幫你支援第三層【傳輸層】的問題,比如面向tcp,面向udp,以及sctp網絡協定的開發,它都能很好的支援。是以他可以稱為一個通信元件。 原則上,tomcat的網絡通信元件也可以采用netty,但servlet3.0之前完全是同步阻塞模型,tomcat要遵循servlet規範是以不能最大發揮nio的特性,而netty不用遵循servlet規範,可以最大化發揮nio的特性,性能更高一些。

二、為何要用netty

netty的三大特性(fast,easy,no-blocking)可以詳細分解為以下特性:

支援nio,異步程式設計 性能強悍,高并發,低延遲,更少的資源占用和記憶體使用率帶來更快的性能支撐,nio領域最強 成熟、穩定,你想到的一切tcp 問題,都已經解決,特别是nio bug,以及完美解決了。 不僅僅支援http,支援多種應用協定和網絡協定,如tcp/udp/udt/sctp/ftp/smtp等。 功能強大,預制了多種編解碼處理器,支援多種主流應用協定 api使用簡單,開發門檻低

為何快,可以參考上篇文章(​​【nio系列】——之reactor模型​​)介紹的reactor io模型。

【NIO系列】——之Netty

netty正是基于nio實作了這種reactor模型,boss線程用來專門處理連接配接的建立,subreactor專門用來處理io的讀寫以及任務的處理。這種線程模型在充分利用cpu性能的情況下支撐大量的并發連接配接。

【NIO系列】——之Netty

具體效果如何,我們看下測試資料:

【NIO系列】——之Netty

以上是在techempower擷取的關于webframe的純文字響應測試,可以看到netty在響應速度方面,排名第二,雖然近幾年高性能的web架構不斷的挑戰,netty排名有所下降,但依然還能保持前列位置。

【NIO系列】——之Netty

以上是在dubbo的官方測試案例中,給定協定序列化tps對比,可以看到采用netty的dubbo,在tps方面名列前茅。

netty因為要面對大量的網絡資料包處理,是以會有大量的網絡對象建立和銷毀,對jvm來說有很大的壓力。

netty主要采用兩種方案來緩解jvm的壓力:

bytebufallocator 對象池。池化bytebuf執行個體以提高性能并最小化記憶體碎片,後者每次調用時都傳回一個新的執行個體。

零拷貝。支援directbuffer的使用,通過jvm的本地調用配置設定記憶體,這可避免每次調用本地i / o操作之前(或之後)将緩沖區的内容複制到(或從)中間緩沖區。

以下是twitter對應netty4的使用對象池應用壓測:

【NIO系列】——之Netty

我們知道牽扯到網絡上的程式設計會比較複雜,除了有一堆需要設定的tpc參數以外,還有一堆io讀寫的問題要處理,同時為了提高并發能力,還采用多線程,這就又帶來了線程安全的問題,往往給開發者帶來了很大的挑戰和複雜度。

而netty 正是針對這些難點統一做了簡易化的封裝,除了讓api更加簡單易用以外,比如:tcp伺服器的配置啟動,資料包buffbyte的讀寫等。另外基于事件模式,對網絡事件進行串行處理,在保證了高效的同時,又降低了程式設計的複雜度。

為何串行化執行會提升netty的性能:

串行無鎖化設計,在io線程内部進行串行操作,避免多線程競争導緻的性能下降。 通過調整nio線程池的線程參數,可以同時啟動多個串行化的線程并行運作,這種局部無鎖化的串行線程設計相比一個隊列-多個工作線程模型性能更優 減少上下文切換,以及狀态資料的同步

以下 是channelpipeline用來處理網絡事件的職責鍊,負責管理和執行channelhandler。網絡事件以事件流的形式在channelpipeline中流轉。支援插拔模式,擴充性也很強。

【NIO系列】——之Netty

在網絡方面,應用常常要面對複雜的網絡環境,比如網絡環境差,常會出現一些網絡閃斷,單通以及網絡阻塞等等一系列問題。另外作為基礎的通信元件,還需要考慮健壯性的問題,因為一旦出現bug,則會導緻依賴的大量業務中斷。

netty 在版本疊代中不斷的加入一些可靠性特性來滿足使用者日益高漲的可靠性與健壯性需求。比如nio的select空轉bug,比如tcp的斷線重連,keep-alive檢測等問題,netty已經幫你解決了。

特别是netty在推出4.0之後,已經被各家大廠采納為通信元件,這是對其可靠性驗證,也是社群對其穩定性的認可。以下是在使用netty的一些公司,更多參考netty.adopters

【NIO系列】——之Netty

上面介紹了這麼多netty如何厲害,到編碼階段不會出現一堆代碼來要處理吧。

我們來一個簡單的tcpserver來進行示例.

需求:

client:接收使用者輸入的内容,并發送給server,同時收并顯示server傳回的内容 server:監聽8088端口,接收并顯示client發送的内容,并給client相應的回複
【NIO系列】——之Netty

代碼:

childchannelhander 擴充pipeline的執行政策:

通過以上代碼,我們大概需要通過7個步驟,就能建立一個tcp的server伺服器了,看似7步較多,其實看代碼量來說,已經很少了。

【NIO系列】——之Netty

通過以上的執行流程圖,我們可以看到:

serverbootstrap是服務啟動(引導)輔助類,采用無參構造器(builder模式)提供一系統方法用于設定啟動相關的參數

eventloopgroup:netty的reactor線程池,負責維護一組eventloop的排程工作,通常是bosseventloop用來維護連接配接,subeventloop來維護所有已注冊的channel的i/o操作處理使用者自定義的task和定時任務的task

channel:對java原生的nio類庫進行了封裝對一般使用者而言,不需要關心底層實作細節和工作原理,隻需要指定具體使用哪種channel,用以連接配接io裝置(socket)的紐帶,提供與io裝置異步i/o操作的支援(如讀、寫、連接配接和綁定)

childchannelhandler,用來配置channelpipeline的執行政策。用來擴充的關鍵接口,使用者可以完成大多數的功能定制,如消息編解碼、心跳、安全認證、tsl/ssl認證、流量控制等。

四、最後

以上我們通過netty 是什麼、怎麼用、為何用三個方面闡述了netty的優勢以及基本的介紹,想必能夠對netty做一個基本的了解。後續我們将對netty高性能架構,以及多線程高效程式設計方面,結合源碼,會有更多的剖析。我們不僅僅關注源碼是如何實作了,還會結合整個架構,來分析設計理念,以及探讨魯棒性很強的代碼的編寫方式。若有興趣,歡迎持續關注。