1. 程式人生 > >通俗地講,Netty 能做什麼?

通俗地講,Netty 能做什麼?

作為一個學Java的,如果沒有研究過Netty,那麼你對Java語言的使用和理解僅僅停留在表面水平,會點SSH,寫幾個MVC,訪問資料庫和快取,這些只是初等Java程式設計師乾的事。如果你要進階,想了解Java伺服器的深層高階知識,Netty絕對是一個必須要過的門檻。

有了Netty,你可以實現自己的HTTP伺服器,FTP伺服器,UDP伺服器,RPC伺服器,WebSocket伺服器,Redis的Proxy伺服器,MySQL的Proxy伺服器等等。

如果你想知道Nginx是怎麼寫出來的,如果你想知道Tomcat和Jetty是如何實現的,如果你也想實現一個簡單的Redis伺服器,那都應該好好理解一下Netty,它們高效能的原理都是類似的。

我們回顧一下傳統的HTTP伺服器的原理:

建立一個ServerSocket,監聽並繫結一個埠
一系列客戶端來請求這個埠
伺服器使用Accept,獲得一個來自客戶端的Socket連線物件
啟動一個新執行緒處理連線

讀Socket,得到位元組流
解碼協議,得到Http請求物件
處理Http請求,得到一個結果,封裝成一個HttpResponse物件
編碼協議,將結果序列化位元組流
寫Socket,將位元組流發給客戶端
繼續迴圈步驟3

HTTP伺服器之所以稱為HTTP伺服器,是因為編碼解碼協議是HTTP協議,如果協議是Redis協議,那它就成了Redis伺服器,如果協議是WebSocket,那它就成了WebSocket伺服器,等等。

使用Netty你就可以定製編解碼協議,實現自己的特定協議的伺服器。

上面我們說的是一個傳統的多執行緒伺服器,這個也是Apache處理請求的模式。在高併發環境下,執行緒數量可能會建立太多,作業系統的任務排程壓力大,系統負載也會比較高。那怎麼辦呢?

於是NIO誕生了,NIO並不是Java獨有的概念,NIO代表的一個詞彙叫著IO多路複用。它是由作業系統提供的系統呼叫,早期這個作業系統呼叫的名字是select,但是效能低下,後來漸漸演化成了Linux下的epoll和Mac裡的kqueue。我們一般就說是epoll,因為沒有人拿蘋果電腦作為伺服器使用對外提供服務。而Netty就是基於Java NIO技術封裝的一套框架。為什麼要封裝,因為原生的Java NIO使用起來沒那麼方便,而且還有臭名昭著的bug,Netty把它封裝之後,提供了一個易於操作的使用模式和介面,使用者使用起來也就便捷多了。

那NIO究竟是什麼東西呢?NIO的全稱是NoneBlocking IO,非阻塞IO,區別與BIO,BIO的全稱是Blocking IO,阻塞IO。那這個阻塞是什麼意思呢?

Accept是阻塞的,只有新連線來了,Accept才會返回,主執行緒才能繼續
Read是阻塞的,只有請求訊息來了,Read才能返回,子執行緒才能繼續處理
Write是阻塞的,只有客戶端把訊息收了,Write才能返回,子執行緒才能繼續讀取下一個請求
所以傳統的多執行緒伺服器是BlockingIO模式的,從頭到尾所有的執行緒都是阻塞的。這些執行緒就乾等在哪裡,佔用了作業系統的排程資源,什麼事也不幹,是浪費。

那麼NIO是怎麼做到非阻塞的呢。它用的是事件機制。它可以用一個執行緒把Accept,讀寫操作,請求處理的邏輯全乾了。如果什麼事都沒得做,它也不會死迴圈,它會將執行緒休眠起來,直到下一個事件來了再繼續幹活,這樣的一個執行緒稱之為NIO執行緒。

while true {
    events = takeEvents(fds)  // 獲取事件,如果沒有事件,執行緒就休眠
    for event in events {
        if event.isAcceptable {
            doAccept() // 新連結來了
        } elif event.isReadable {
            request = doRead() // 讀訊息
            if request.isComplete() {
                doProcess()
            }
        } elif event.isWriteable {
            doWrite()  // 寫訊息
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NIO的流程大致就是上面的虛擬碼描述的過程,跟實際真實的程式碼有較多差異,不過對於初學者,這樣理解也是足夠了。

Netty是建立在NIO基礎之上,Netty在NIO之上又提供了更高層次的抽象。在Netty裡面,Accept連線可以使用單獨的執行緒池去處理,讀寫操作又是另外的執行緒池來處理。

Accept連線和讀寫操作也可以使用同一個執行緒池來進行處理。而請求處理邏輯既可以使用單獨的執行緒池進行處理,也可以跟放在讀寫執行緒一塊處理。執行緒池中的每一個執行緒都是NIO執行緒。使用者可以根據實際情況進行組裝,構造出滿足系統需求的併發模型。

Netty提供了內建的常用編解碼器,包括行編解碼器[一行一個請求],字首長度編解碼器[前N個位元組定義請求的位元組長度],可重放解碼器[記錄半包訊息的狀態],HTTP編解碼器,WebSocket訊息編解碼器等等

Netty提供了一些列生命週期回撥介面,當一個完整的請求到達時,當一個連線關閉時,當一個連線建立時,使用者都會收到回撥事件,然後進行邏輯處理。

Netty可以同時管理多個埠,可以使用NIO客戶端模型,這些對於RPC服務是很有必要的。

Netty除了可以處理TCP Socket之外,還可以處理UDP Socket。

在訊息讀寫過程中,需要大量使用ByteBuffer,Netty對ByteBuffer在效能和使用的便捷性上都進行了優化和抽象。

總之,Netty是Java程式設計師進階的必備神奇。如果你知其然,還想知其所以然,一定要好好研究下Netty。如果你覺得Java枯燥無謂,Netty則是重新開啟你對Java興趣大門的鑰匙。

作者:郭無心 連結:https://www.zhihu.com/question/24322387/answer/78947405 
來源:知乎 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

Netty 在哪些行業得到了應用?
網際網路行業:隨著網站規模的不斷擴大,系統併發訪問量也越來越高,傳統基於 Tomcat 等 Web 容器的垂直架構已經無法滿足需求,需要拆分應用進行服務化,以提高開發和維護效率。從組網情況看,垂直的架構拆分之後,系統採用分散式部署,各個節點之間需要遠端服務呼叫,高效能的 RPC 框架必不可少,Netty 作為非同步高效能的通訊框架,往往作為基礎通訊元件被這些 RPC 框架使用。

典型的應用有:阿里分散式服務框架 Dubbo 的 RPC 框架使用 Dubbo 協議進行節點間通訊,Dubbo 協議預設使用 Netty 作為基礎通訊元件,用於實現各程序節點之間的內部通訊。它的架構圖如下: 

其中,服務提供者和服務消費者之間,服務提供者、服務消費者和效能統計節點之間使用 Netty 進行非同步/同步通訊。

除了 Dubbo 之外,淘寶的訊息中介軟體 RocketMQ 的訊息生產者和訊息消費者之間,也採用 Netty 進行高效能、非同步通訊。除了阿里系和淘寶系之外,很多其它的大型網際網路公司或者電商內部也已經大量使用 Netty 構建高效能、分散式的網路伺服器。

遊戲行業:無論是手遊服務端、還是大型的網路遊戲,Java 語言得到了越來越廣泛的應用。Netty 作為高效能的基礎通訊元件,它本身提供了 TCP/UDP 和 HTTP 協議棧,非常方便定製和開發私有協議棧。賬號登陸伺服器、地圖伺服器之間可以方便的通過 Netty 進行高效能的通訊,架構示意圖如下:

 
Netty 在遊戲伺服器架構中的應用
大資料領域:經典的 Hadoop 的高效能通訊和序列化元件 Avro 的 RPC 框架,預設採用 Netty 進行跨節點通訊,它的 Netty Service 基於 Netty 框架二次封裝實現。

大資料計算往往採用多個計算節點和一個/N個彙總節點進行分散式部署,各節點之間存在海量的資料交換。由於 Netty 的綜合性能是目前各個成熟 NIO 框架中最高的,因此,往往會被選中用作大資料各節點間的通訊。

企業軟體:企業和 IT 整合需要 ESB,Netty 對多協議支援、私有協議定製的簡潔性和高效能是 ESB RPC 框架的首選通訊元件。事實上,很多企業匯流排廠商會選擇 Netty 作為基礎通訊元件,用於企業的 IT 整合。

通訊行業:Netty 的非同步高效能、高可靠性和高成熟度的優點,使它在通訊行業得到了大量的應用。