前言
上篇文章通過(guò) Java NIO 的處理流程與 Netty 的總體流程比較,并結(jié)合 Netty 的源碼,可以更加清晰地理解Netty。本文將結(jié)合源碼詳細(xì)解析Netty的高效和強(qiáng)大功能的設(shè)計(jì)原理,學(xué)習(xí) Netty 是如何實(shí)現(xiàn)其卓越的性能和功能特性,也希望可以在日后工作中利用到 Netty 的設(shè)計(jì)思想。
Netty 解決的問(wèn)題
我們先看看使用 Netty 在網(wǎng)絡(luò)編程中幫助我們解決了什么問(wèn)題
簡(jiǎn)化網(wǎng)絡(luò)編程
首先基于 Netty 初次編碼的直觀體驗(yàn)來(lái)講,開(kāi)發(fā)者不用手動(dòng)處理網(wǎng)絡(luò)通信細(xì)節(jié),包括線程管理、I/O 處理、協(xié)議解析等,可以專注于業(yè)務(wù)邏輯的實(shí)現(xiàn)。也正是因?yàn)槿绱?,在學(xué)習(xí) Netty 時(shí)比較抽象難懂 。
下面對(duì)比一下 Java NIO 實(shí)現(xiàn)的簡(jiǎn)單的服務(wù)端和 Netty 實(shí)現(xiàn)的 HTTP 服務(wù)端,如下圖,可以看到 Java NIO 的代碼大概有 80 行,而且還沒(méi)有實(shí)現(xiàn) HTTP 協(xié)議,并且還是單線程,沒(méi)有復(fù)雜的線程管理,更不用說(shuō)性能什么的,而 Netty 實(shí)現(xiàn)的代碼只有 30 多行,其中的差別一目了然。
粘包和拆包
我們一般說(shuō)粘包和拆包都是說(shuō) TCP 協(xié)議的問(wèn)題,因?yàn)楫?dāng)用戶消息通過(guò) UDP 協(xié)議傳輸時(shí),操作系統(tǒng)不會(huì)對(duì)消息進(jìn)行拆分,所以發(fā)送出去的一條 UDP 報(bào)文就是完整的用戶消息,也就是每個(gè) UDP 報(bào)文就是用戶消息的邊界。而當(dāng)用戶消息通過(guò) TCP 協(xié)議傳輸時(shí),消息可能會(huì)被操作系統(tǒng)分組成多個(gè)的 TCP 報(bào)文進(jìn)行傳輸,這個(gè)時(shí)候接收方收到多個(gè)報(bào)文后,由于不知道消息的邊界,也就無(wú)法讀出一個(gè)有效的用戶消息。
舉個(gè)例子,當(dāng)發(fā)送方準(zhǔn)備發(fā)送 「Hi」和「I am Erdan」這兩個(gè)消息,由于MTU限制、緩沖區(qū)的大小等條件,可能會(huì)出現(xiàn)幾種情況:
第一種情況,兩條消息分到一個(gè)報(bào)文中,像這樣:
第二種情況,「I am Erdan」中的部分消息隨「Hi」被分到一個(gè)報(bào)文中,像這樣:
還可能會(huì)有第三、四…種情況,而當(dāng)接收方接收到第一種情況時(shí)我們稱之為粘包,第二種情況稱之為拆包。并且上面的種種情況可以表明不能認(rèn)為一個(gè)用戶消息對(duì)應(yīng)一個(gè) TCP 報(bào)文,正因?yàn)檫@樣,所以 TCP 是面向字節(jié)流的協(xié)議。
解決粘包和拆包的根本手段就是找出消息的邊界,有幾種方式:
- 固定消息長(zhǎng)度,這種方式靈活性不高,實(shí)際中很少用。
-
特殊字符作為邊界,HTTP 是一個(gè)非常好的例子,通過(guò)設(shè)置回車(chē)符、換行符作為 HTTP 報(bào)文協(xié)議的邊界。
- 自定義消息結(jié)構(gòu):消息頭消息體,可以自定義一個(gè)消息結(jié)構(gòu),由包頭和數(shù)據(jù)組成,其中包頭包是固定大小的,而且包頭里有一個(gè)字段來(lái)說(shuō)明緊隨其后的數(shù)據(jù)有多大。
而 Netty 提供了固定長(zhǎng)度解碼器(FixedLengthFrameDecoder
)、行分隔符解碼器(LineBasedFrameDecoder
)、分隔符解碼器(DelimiterBasedFrameDecoder
)、**基于長(zhǎng)度字段的解碼器(LengthFieldBasedFrameDecoder
)**幾種方式來(lái)解決粘包問(wèn)題,可以結(jié)合 Netty 的 ChannelPipeline
來(lái)使用。
除此之外 Netty 也提供了 HTTP、WebSocket、TCP、UDP幾種協(xié)議的編解碼器,這也是 Netty 靈活擴(kuò)展強(qiáng)大之處。
高性能的設(shè)計(jì)
Netty 除了幫助開(kāi)發(fā)人員解決了一些問(wèn)題,還提高了網(wǎng)絡(luò)編程性能,體現(xiàn)如下:
多線程調(diào)度
在網(wǎng)絡(luò)編程中如果使用單線程來(lái)處理,即便是IO多路復(fù)用,吞吐和性能也是會(huì)有局限的。而 Netty 中通過(guò) EventLoopGroup
管理線程池,每個(gè)線程就是一個(gè) EventLoop
,而 EventLoop
內(nèi)部有一個(gè) Selector
負(fù)責(zé)處理一個(gè)或多個(gè) Channel
的注冊(cè)、讀寫(xiě)和其他事件。所以 Netty 通過(guò) EventLoopGroup
、EventLoop
和 Selector
的配合工作,實(shí)現(xiàn)了高效的并發(fā)處理能力。
既然是多線程處理,肯定要去考慮線程安全以確保程序的正確性。而 Netty 是如何保障線程安全的?Netty 通過(guò)使用管道(ChannelPipeline
)和處理器(ChannelHandler
)的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)的處理和流轉(zhuǎn),而 ChannelHandler
會(huì)被分配給一個(gè) EventLoop
處理,而 EventLoop
內(nèi)部的數(shù)據(jù)結(jié)構(gòu)和狀態(tài)都是線程封閉的,不會(huì)被其他線程訪問(wèn)或修改。所以 Netty 通過(guò)合理地設(shè)計(jì)組件之間的關(guān)系,通過(guò)單線程執(zhí)行、無(wú)鎖設(shè)計(jì)等方式保證了在高并發(fā)情況下的線程安全性。
零拷貝
在傳統(tǒng)的網(wǎng)絡(luò)編程中,數(shù)據(jù)在進(jìn)行網(wǎng)絡(luò)傳輸之前需要從應(yīng)用層緩沖區(qū)復(fù)制到操作系統(tǒng)內(nèi)核的緩沖區(qū),然后再?gòu)膬?nèi)核的緩沖區(qū)復(fù)制到網(wǎng)絡(luò)設(shè)備的緩沖區(qū)。這種復(fù)制操作會(huì)增加 CPU 的負(fù)載和內(nèi)存的開(kāi)銷,如下圖
而 Netty 利用零拷貝技術(shù)來(lái)減少數(shù)據(jù)復(fù)制的次數(shù),提高了數(shù)據(jù)傳輸?shù)男省A憧截愅ㄟ^(guò)將數(shù)據(jù)從內(nèi)核空間直接傳輸?shù)骄W(wǎng)絡(luò)適配器,避免了數(shù)據(jù)在內(nèi)核空間和用戶空間之間的復(fù)制,從而減少了CPU的負(fù)擔(dān)。
具體體現(xiàn)在以下幾個(gè)方面:
-
零拷貝文件傳輸:Netty 的 FileRegion 接口提供了直接在文件系統(tǒng)和網(wǎng)絡(luò)之間傳輸數(shù)據(jù)的功能。通過(guò)使用零拷貝技術(shù),數(shù)據(jù)可以直接從磁盤(pán)讀取并發(fā)送到網(wǎng)絡(luò)設(shè)備,避免了中間的緩沖區(qū)拷貝,提高了文件傳輸?shù)男阅堋?/p>
-
零拷貝內(nèi)存?zhèn)鬏?/strong>:Netty 的 ByteBuf 類型支持零拷貝的內(nèi)存?zhèn)鬏?。?dāng)數(shù)據(jù)在應(yīng)用程序和內(nèi)核之間傳輸時(shí),Netty 使用直接內(nèi)存緩沖區(qū)(Direct ByteBuffer)來(lái)避免額外的數(shù)據(jù)拷貝操作,提高了內(nèi)存?zhèn)鬏數(shù)男省?/p>
通過(guò)以上方式,Netty 實(shí)現(xiàn)了零拷貝技術(shù)在網(wǎng)絡(luò)編程中的應(yīng)用,提高了數(shù)據(jù)傳輸?shù)男屎托阅?。這使得 Netty 在處理大量數(shù)據(jù)傳輸和高并發(fā)場(chǎng)景下具有更好的性能表現(xiàn)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-662854.html
總結(jié)
總的來(lái)說(shuō),Netty 不論在功能、性能以及穩(wěn)定性來(lái)講都是一款很nice的網(wǎng)絡(luò)編程框架,很多知名的項(xiàng)目都將 Netty 作為其網(wǎng)絡(luò)通信的底層框架,比如Apache Kafka、Elasticsearch、gRPC、Dubbo等。熟悉這些框架的開(kāi)發(fā)者通常都具備高并發(fā)開(kāi)發(fā)經(jīng)驗(yàn),并且掌握 Netty 是理解這些框架的重要基礎(chǔ)之一。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-662854.html
到了這里,關(guān)于Netty為什么高效,為什么這么受歡迎?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!