Netty高速網(wǎng)絡(luò)通訊(一)

1馅袁、Netty基礎(chǔ)入門

Netty是由JBOSS提供的一個(gè)java開源框架乃戈。Netty提供異步的、事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架和工具念颈,用以快速開發(fā)高性能、高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序连霉。

也就是說榴芳,Netty 是一個(gè)基于NIO的客戶、服務(wù)器端編程框架跺撼,使用Netty 可以確保你快速和簡(jiǎn)單的開發(fā)出一個(gè)網(wǎng)絡(luò)應(yīng)用窟感,例如實(shí)現(xiàn)了某種協(xié)議的客戶,服務(wù)端應(yīng)用歉井。Netty相當(dāng)簡(jiǎn)化和流線化了網(wǎng)絡(luò)應(yīng)用的編程開發(fā)過程柿祈,例如,TCP和UDP的socket服務(wù)開發(fā)。

“快速”和“簡(jiǎn)單”并不用產(chǎn)生維護(hù)性或性能上的問題躏嚎。Netty 是一個(gè)吸收了多種協(xié)議的實(shí)現(xiàn)經(jīng)驗(yàn)蜜自,這些協(xié)議包括FTP,SMTP,HTTP,各種二進(jìn)制紧索,文本協(xié)議袁辈,并經(jīng)過相當(dāng)精心設(shè)計(jì)的項(xiàng)目,最終珠漂,Netty 成功的找到了一種方式晚缩,在保證易于開發(fā)的同時(shí)還保證了其應(yīng)用的性能,穩(wěn)定性和伸縮性媳危。

2. Netty高性能之道

2.1. RPC調(diào)用的性能模型分析

網(wǎng)絡(luò)傳輸方式問題:傳統(tǒng)的RPC框架或者基于RMI等方式的遠(yuǎn)程服務(wù)(過程)調(diào)用采用了同步阻塞IO荞彼,當(dāng)客戶端的并發(fā)壓力或者網(wǎng)絡(luò)時(shí)延增大之后,同步阻塞IO會(huì)由于頻繁的wait導(dǎo)致IO線程經(jīng)常性的阻塞待笑,由于線程無法高效的工作鸣皂,IO處理能力自然下降。

下面暮蹂,我們通過BIO通信模型圖看下BIO通信的弊端:

圖2-1 BIO通信模型圖

采用BIO通信模型的服務(wù)端寞缝,通常由一個(gè)獨(dú)立的Acceptor線程負(fù)責(zé)監(jiān)聽客戶端的連接,接收到客戶端連接之后為客戶端連接創(chuàng)建一個(gè)新的線程處理請(qǐng)求消息仰泻,處理完成之后荆陆,返回應(yīng)答消息給客戶端,線程銷毀集侯,這就是典型的一請(qǐng)求一應(yīng)答模型被啼。該架構(gòu)最大的問題就是不具備彈性伸縮能力,當(dāng)并發(fā)訪問量增加后棠枉,服務(wù)端的線程個(gè)數(shù)和并發(fā)訪問數(shù)成線性正比浓体,由于線程是JAVA虛擬機(jī)非常寶貴的系統(tǒng)資源,當(dāng)線程數(shù)膨脹之后辈讶,系統(tǒng)的性能急劇下降命浴,隨著并發(fā)量的繼續(xù)增加,可能會(huì)發(fā)生句柄溢出贱除、線程堆棧溢出等問題咳促,并導(dǎo)致服務(wù)器最終宕機(jī)。

序列化方式問題:Java序列化存在如下幾個(gè)典型問題:

1) Java序列化機(jī)制是Java內(nèi)部的一種對(duì)象編解碼技術(shù)勘伺,無法跨語(yǔ)言使用;例如對(duì)于異構(gòu)系統(tǒng)之間的對(duì)接褂删,Java序列化后的碼流需要能夠通過其它語(yǔ)言反序列化成原始對(duì)象(副本)飞醉,目前很難支持;

2) 相比于其它開源的序列化框架,Java序列化后的碼流太大缅帘,無論是網(wǎng)絡(luò)傳輸還是持久化到磁盤轴术,都會(huì)導(dǎo)致額外的資源占用;

3) 序列化性能差(CPU資源占用高)钦无。

線程模型問題:由于采用同步阻塞IO逗栽,這會(huì)導(dǎo)致每個(gè)TCP連接都占用1個(gè)線程,由于線程資源是JVM虛擬機(jī)非常寶貴的資源失暂,當(dāng)IO讀寫阻塞導(dǎo)致線程無法及時(shí)釋放時(shí)彼宠,會(huì)導(dǎo)致系統(tǒng)性能急劇下降,嚴(yán)重的甚至?xí)?dǎo)致虛擬機(jī)無法創(chuàng)建新的線程弟塞。

2.1.2. 高性能的三個(gè)主題

1) 傳輸:用什么樣的通道將數(shù)據(jù)發(fā)送給對(duì)方凭峡,BIO、NIO或者AIO决记,IO模型在很大程度上決定了框架的性能摧冀。

2) 協(xié)議:采用什么樣的通信協(xié)議,HTTP或者內(nèi)部私有協(xié)議系宫。協(xié)議的選擇不同索昂,性能模型也不同。相比于公有協(xié)議扩借,內(nèi)部私有協(xié)議的性能通辰凡遥可以被設(shè)計(jì)的更優(yōu)。

3) 線程:數(shù)據(jù)報(bào)如何讀韧稀框产?讀取之后的編解碼在哪個(gè)線程進(jìn)行,編解碼后的消息如何派發(fā)错洁,Reactor線程模型的不同秉宿,對(duì)性能的影響也非常大。

圖2-2 RPC調(diào)用性能三要素

2.2. Netty高性能之道

2.2.1. 異步非阻塞通信

在IO編程過程中屯碴,當(dāng)需要同時(shí)處理多個(gè)客戶端接入請(qǐng)求時(shí)描睦,可以利用多線程或者IO多路復(fù)用技術(shù)進(jìn)行處理。IO多路復(fù)用技術(shù)通過把多個(gè)IO的阻塞復(fù)用到同一個(gè)select的阻塞上导而,從而使得系統(tǒng)在單線程的情況下可以同時(shí)處理多個(gè)客戶端請(qǐng)求忱叭。與傳統(tǒng)的多線程/多進(jìn)程模型比,I/O多路復(fù)用的最大優(yōu)勢(shì)是系統(tǒng)開銷小今艺,系統(tǒng)不需要?jiǎng)?chuàng)建新的額外進(jìn)程或者線程韵丑,也不需要維護(hù)這些進(jìn)程和線程的運(yùn)行,降低了系統(tǒng)的維護(hù)工作量虚缎,節(jié)省了系統(tǒng)資源撵彻。

JDK1.4提供了對(duì)非阻塞IO(NIO)的支持,JDK1.5_update10版本使用epoll替代了傳統(tǒng)的select/poll,極大的提升了NIO通信的性能陌僵。

JDK NIO通信模型如下所示:

圖2-3 NIO的多路復(fù)用模型圖

與Socket類和ServerSocket類相對(duì)應(yīng)轴合,NIO也提供了SocketChannel和ServerSocketChannel兩種不同的套接字通道實(shí)現(xiàn)。這兩種新增的通道都支持阻塞和非阻塞兩種模式碗短。阻塞模式使用非常簡(jiǎn)單受葛,但是性能和可靠性都不好,非阻塞模式正好相反偎谁。開發(fā)人員一般可以根據(jù)自己的需要來選擇合適的模式总滩,一般來說,低負(fù)載搭盾、低并發(fā)的應(yīng)用程序可以選擇同步阻塞IO以降低編程復(fù)雜度咳秉。但是對(duì)于高負(fù)載、高并發(fā)的網(wǎng)絡(luò)應(yīng)用鸯隅,需要使用NIO的非阻塞模式進(jìn)行開發(fā)澜建。

Netty架構(gòu)按照Reactor模式設(shè)計(jì)和實(shí)現(xiàn),它的服務(wù)端通信序列圖如下:

圖2-3 NIO服務(wù)端通信序列圖

客戶端通信序列圖如下:

圖2-4 NIO客戶端通信序列圖

Netty的IO線程N(yùn)ioEventLoop由于聚合了多路復(fù)用器Selector蝌以,可以同時(shí)并發(fā)處理成百上千個(gè)客戶端Channel炕舵,由于讀寫操作都是非阻塞的,這就可以充分提升IO線程的運(yùn)行效率跟畅,避免由于頻繁IO阻塞導(dǎo)致的線程掛起咽筋。另外,由于Netty采用了異步通信模式徊件,一個(gè)IO線程可以并發(fā)處理N個(gè)客戶端連接和讀寫操作奸攻,這從根本上解決了傳統(tǒng)同步阻塞IO一連接一線程模型,架構(gòu)的性能虱痕、彈性伸縮能力和可靠性都得到了極大的提升睹耐。

2.2.2. 零拷貝

很多用戶都聽說過Netty具有“零拷貝”功能,但是具體體現(xiàn)在哪里又說不清楚部翘,本小節(jié)就詳細(xì)對(duì)Netty的“零拷貝”功能進(jìn)行講解硝训。

Netty的“零拷貝”主要體現(xiàn)在如下三個(gè)方面:

1) Netty的接收和發(fā)送ByteBuffer采用DIRECT BUFFERS,使用堆外直接內(nèi)存進(jìn)行Socket讀寫新思,不需要進(jìn)行字節(jié)緩沖區(qū)的二次拷貝窖梁。如果使用傳統(tǒng)的堆內(nèi)存(HEAP BUFFERS)進(jìn)行Socket讀寫,JVM會(huì)將堆內(nèi)存Buffer拷貝一份到直接內(nèi)存中夹囚,然后才寫入Socket中纵刘。相比于堆外直接內(nèi)存,消息在發(fā)送過程中多了一次緩沖區(qū)的內(nèi)存拷貝荸哟。

2) Netty提供了組合Buffer對(duì)象假哎,可以聚合多個(gè)ByteBuffer對(duì)象蛔翅,用戶可以像操作一個(gè)Buffer那樣方便的對(duì)組合Buffer進(jìn)行操作,避免了傳統(tǒng)通過內(nèi)存拷貝的方式將幾個(gè)小Buffer合并成一個(gè)大的Buffer位谋。

3) Netty的文件傳輸采用了transferTo方法,它可以直接將文件緩沖區(qū)的數(shù)據(jù)發(fā)送到目標(biāo)Channel堰燎,避免了傳統(tǒng)通過循環(huán)write方式導(dǎo)致的內(nèi)存拷貝問題掏父。

下面,我們對(duì)上述三種“零拷貝”進(jìn)行說明秆剪,先看Netty 接收Buffer的創(chuàng)建:

圖2-5 異步消息讀取“零拷貝”

每循環(huán)讀取一次消息赊淑,就通過ByteBufAllocator的ioBuffer方法獲取ByteBuf對(duì)象,下面繼續(xù)看它的接口定義:

圖2-6 ByteBufAllocator 通過ioBuffer分配堆外內(nèi)存

當(dāng)進(jìn)行Socket IO讀寫的時(shí)候仅讽,為了避免從堆內(nèi)存拷貝一份副本到直接內(nèi)存陶缺,Netty的ByteBuf分配器直接創(chuàng)建非堆內(nèi)存避免緩沖區(qū)的二次拷貝,通過“零拷貝”來提升讀寫性能洁灵。

下面我們繼續(xù)看第二種“零拷貝”的實(shí)現(xiàn)CompositeByteBuf饱岸,它對(duì)外將多個(gè)ByteBuf封裝成一個(gè)ByteBuf,對(duì)外提供統(tǒng)一封裝后的ByteBuf接口徽千,它的類定義如下:

圖2-7 CompositeByteBuf類繼承關(guān)系

通過繼承關(guān)系我們可以看出CompositeByteBuf實(shí)際就是個(gè)ByteBuf的包裝器苫费,它將多個(gè)ByteBuf組合成一個(gè)集合,然后對(duì)外提供統(tǒng)一的ByteBuf接口双抽,相關(guān)定義如下:

圖2-8 CompositeByteBuf類定義

添加ByteBuf百框,不需要做內(nèi)存拷貝,相關(guān)代碼如下:

圖2-9 新增ByteBuf的“零拷貝”

最后牍汹,我們看下文件傳輸?shù)摹傲憧截悺保?/p>

圖2-10 文件傳輸“零拷貝”

Netty文件傳輸DefaultFileRegion通過transferTo方法將文件發(fā)送到目標(biāo)Channel中铐维,下面重點(diǎn)看FileChannel的transferTo方法,它的API DOC說明如下:

圖2-11 文件傳輸 “零拷貝”

對(duì)于很多操作系統(tǒng)它直接將文件緩沖區(qū)的內(nèi)容發(fā)送到目標(biāo)Channel中慎菲,而不需要通過拷貝的方式嫁蛇,這是一種更加高效的傳輸方式,它實(shí)現(xiàn)了文件傳輸?shù)摹傲憧截悺薄?/p>

2.2.3. 內(nèi)存池

隨著JVM虛擬機(jī)和JIT即時(shí)編譯技術(shù)的發(fā)展钧嘶,對(duì)象的分配和回收是個(gè)非常輕量級(jí)的工作棠众。但是對(duì)于緩沖區(qū)Buffer,情況卻稍有不同有决,特別是對(duì)于堆外直接內(nèi)存的分配和回收闸拿,是一件耗時(shí)的操作。為了盡量重用緩沖區(qū)书幕,Netty提供了基于內(nèi)存池的緩沖區(qū)重用機(jī)制新荤。下面我們一起看下Netty ByteBuf的實(shí)現(xiàn):

圖2-12 內(nèi)存池ByteBuf

Netty提供了多種內(nèi)存管理策略,通過在啟動(dòng)輔助類中配置相關(guān)參數(shù)台汇,可以實(shí)現(xiàn)差異化的定制苛骨。

下面通過性能測(cè)試篱瞎,我們看下基于內(nèi)存池循環(huán)利用的ByteBuf和普通ByteBuf的性能差異。

用例一痒芝,使用內(nèi)存池分配器創(chuàng)建直接內(nèi)存緩沖區(qū):

圖2-13 基于內(nèi)存池的非堆內(nèi)存緩沖區(qū)測(cè)試用例

用例二俐筋,使用非堆內(nèi)存分配器創(chuàng)建的直接內(nèi)存緩沖區(qū):

圖2-14 基于非內(nèi)存池創(chuàng)建的非堆內(nèi)存緩沖區(qū)測(cè)試用例

各執(zhí)行300萬次,性能對(duì)比結(jié)果如下所示:

圖2-15 內(nèi)存池和非內(nèi)存池緩沖區(qū)寫入性能對(duì)比

性能測(cè)試表明严衬,采用內(nèi)存池的ByteBuf相比于朝生夕滅的ByteBuf澄者,性能高23倍左右(性能數(shù)據(jù)與使用場(chǎng)景強(qiáng)相關(guān))。

下面我們一起簡(jiǎn)單分析下Netty內(nèi)存池的內(nèi)存分配:

圖2-16 AbstractByteBufAllocator的緩沖區(qū)分配

繼續(xù)看newDirectBuffer方法请琳,我們發(fā)現(xiàn)它是一個(gè)抽象方法粱挡,由AbstractByteBufAllocator的子類負(fù)責(zé)具體實(shí)現(xiàn),代碼如下:

圖2-17 newDirectBuffer的不同實(shí)現(xiàn)

代碼跳轉(zhuǎn)到PooledByteBufAllocator的newDirectBuffer方法俄精,從Cache中獲取內(nèi)存區(qū)域PoolArena询筏,調(diào)用它的allocate方法進(jìn)行內(nèi)存分配:

圖2-18 PooledByteBufAllocator的內(nèi)存分配

PoolArena的allocate方法如下:

圖2-18 PoolArena的緩沖區(qū)分配

我們重點(diǎn)分析newByteBuf的實(shí)現(xiàn),它同樣是個(gè)抽象方法竖慧,由子類DirectArena和HeapArena來實(shí)現(xiàn)不同類型的緩沖區(qū)分配嫌套,由于測(cè)試用例使用的是堆外內(nèi)存,

圖2-19 PoolArena的newByteBuf抽象方法

因此重點(diǎn)分析DirectArena的實(shí)現(xiàn):如果沒有開啟使用sun的unsafe测蘑,則

圖2-20 DirectArena的newByteBuf方法實(shí)現(xiàn)

執(zhí)行PooledDirectByteBuf的newInstance方法灌危,代碼如下:

圖2-21 PooledDirectByteBuf的newInstance方法實(shí)現(xiàn)

通過RECYCLER的get方法循環(huán)使用ByteBuf對(duì)象,如果是非內(nèi)存池實(shí)現(xiàn)碳胳,則直接創(chuàng)建一個(gè)新的ByteBuf對(duì)象勇蝙。從緩沖池中獲取ByteBuf之后,調(diào)用AbstractReferenceCountedByteBuf的setRefCnt方法設(shè)置引用計(jì)數(shù)器挨约,用于對(duì)象的引用計(jì)數(shù)和內(nèi)存回收(類似JVM垃圾回收機(jī)制)味混。

2.2.4. 高效的Reactor線程模型

常用的Reactor線程模型有三種,分別如下:

1) Reactor單線程模型诫惭;

2) Reactor多線程模型翁锡;

3) 主從Reactor多線程模型

Reactor單線程模型,指的是所有的IO操作都在同一個(gè)NIO線程上面完成夕土,NIO線程的職責(zé)如下:

1) 作為NIO服務(wù)端馆衔,接收客戶端的TCP連接;

2) 作為NIO客戶端怨绣,向服務(wù)端發(fā)起TCP連接角溃;

3) 讀取通信對(duì)端的請(qǐng)求或者應(yīng)答消息;

4) 向通信對(duì)端發(fā)送消息請(qǐng)求或者應(yīng)答消息篮撑。

Reactor單線程模型示意圖如下所示:

圖2-22 Reactor單線程模型

由于Reactor模式使用的是異步非阻塞IO减细,所有的IO操作都不會(huì)導(dǎo)致阻塞,理論上一個(gè)線程可以獨(dú)立處理所有IO相關(guān)的操作赢笨。從架構(gòu)層面看未蝌,一個(gè)NIO線程確實(shí)可以完成其承擔(dān)的職責(zé)驮吱。例如,通過Acceptor接收客戶端的TCP連接請(qǐng)求消息萧吠,鏈路建立成功之后左冬,通過Dispatch將對(duì)應(yīng)的ByteBuffer派發(fā)到指定的Handler上進(jìn)行消息解碼。用戶Handler可以通過NIO線程將消息發(fā)送給客戶端纸型。

對(duì)于一些小容量應(yīng)用場(chǎng)景又碌,可以使用單線程模型。但是對(duì)于高負(fù)載绊袋、大并發(fā)的應(yīng)用卻不合適,主要原因如下:

1) 一個(gè)NIO線程同時(shí)處理成百上千的鏈路铸鹰,性能上無法支撐癌别,即便NIO線程的CPU負(fù)荷達(dá)到100%,也無法滿足海量消息的編碼蹋笼、解碼展姐、讀取和發(fā)送;

2) 當(dāng)NIO線程負(fù)載過重之后剖毯,處理速度將變慢圾笨,這會(huì)導(dǎo)致大量客戶端連接超時(shí),超時(shí)之后往往會(huì)進(jìn)行重發(fā)逊谋,這更加重了NIO線程的負(fù)載擂达,最終會(huì)導(dǎo)致大量消息積壓和處理超時(shí),NIO線程會(huì)成為系統(tǒng)的性能瓶頸胶滋;

3) 可靠性問題:一旦NIO線程意外跑飛板鬓,或者進(jìn)入死循環(huán),會(huì)導(dǎo)致整個(gè)系統(tǒng)通信模塊不可用究恤,不能接收和處理外部消息俭令,造成節(jié)點(diǎn)故障。

為了解決這些問題部宿,演進(jìn)出了Reactor多線程模型抄腔,下面我們一起學(xué)習(xí)下Reactor多線程模型。

Rector多線程模型與單線程模型最大的區(qū)別就是有一組NIO線程處理IO操作理张,它的原理圖如下:

圖2-23 Reactor多線程模型

Reactor多線程模型的特點(diǎn):

1) 有專門一個(gè)NIO線程-Acceptor線程用于監(jiān)聽服務(wù)端赫蛇,接收客戶端的TCP連接請(qǐng)求;

2) 網(wǎng)絡(luò)IO操作-讀涯穷、寫等由一個(gè)NIO線程池負(fù)責(zé)棍掐,線程池可以采用標(biāo)準(zhǔn)的JDK線程池實(shí)現(xiàn),它包含一個(gè)任務(wù)隊(duì)列和N個(gè)可用的線程拷况,由這些NIO線程負(fù)責(zé)消息的讀取作煌、解碼掘殴、編碼和發(fā)送;

3) 1個(gè)NIO線程可以同時(shí)處理N條鏈路粟誓,但是1個(gè)鏈路只對(duì)應(yīng)1個(gè)NIO線程奏寨,防止發(fā)生并發(fā)操作問題。

在絕大多數(shù)場(chǎng)景下鹰服,Reactor多線程模型都可以滿足性能需求病瞳;但是,在極特殊應(yīng)用場(chǎng)景中悲酷,一個(gè)NIO線程負(fù)責(zé)監(jiān)聽和處理所有的客戶端連接可能會(huì)存在性能問題套菜。例如百萬客戶端并發(fā)連接,或者服務(wù)端需要對(duì)客戶端的握手消息進(jìn)行安全認(rèn)證设易,認(rèn)證本身非常損耗性能逗柴。在這類場(chǎng)景下,單獨(dú)一個(gè)Acceptor線程可能會(huì)存在性能不足問題顿肺,為了解決性能問題戏溺,產(chǎn)生了第三種Reactor線程模型-主從Reactor多線程模型。

主從Reactor線程模型的特點(diǎn)是:服務(wù)端用于接收客戶端連接的不再是個(gè)1個(gè)單獨(dú)的NIO線程屠尊,而是一個(gè)獨(dú)立的NIO線程池旷祸。Acceptor接收到客戶端TCP連接請(qǐng)求處理完成后(可能包含接入認(rèn)證等),將新創(chuàng)建的SocketChannel注冊(cè)到IO線程池(sub reactor線程池)的某個(gè)IO線程上讼昆,由它負(fù)責(zé)SocketChannel的讀寫和編解碼工作托享。Acceptor線程池僅僅只用于客戶端的登陸、握手和安全認(rèn)證浸赫,一旦鏈路建立成功嫌吠,就將鏈路注冊(cè)到后端subReactor線程池的IO線程上,由IO線程負(fù)責(zé)后續(xù)的IO操作掺炭。

它的線程模型如下圖所示:

圖2-24 Reactor主從多線程模型

利用主從NIO線程模型辫诅,可以解決1個(gè)服務(wù)端監(jiān)聽線程無法有效處理所有客戶端連接的性能不足問題。因此涧狮,在Netty的官方demo中炕矮,推薦使用該線程模型。

事實(shí)上者冤,Netty的線程模型并非固定不變肤视,通過在啟動(dòng)輔助類中創(chuàng)建不同的EventLoopGroup實(shí)例并通過適當(dāng)?shù)膮?shù)配置,就可以支持上述三種Reactor線程模型涉枫。正是因?yàn)镹etty 對(duì)Reactor線程模型的支持提供了靈活的定制能力邢滑,所以可以滿足不同業(yè)務(wù)場(chǎng)景的性能訴求。

2.2.5. 無鎖化的串行設(shè)計(jì)理念

在大多數(shù)場(chǎng)景下愿汰,并行多線程處理可以提升系統(tǒng)的并發(fā)性能困后。但是乐纸,如果對(duì)于共享資源的并發(fā)訪問處理不當(dāng),會(huì)帶來嚴(yán)重的鎖競(jìng)爭(zhēng)摇予,這最終會(huì)導(dǎo)致性能的下降汽绢。為了盡可能的避免鎖競(jìng)爭(zhēng)帶來的性能損耗,可以通過串行化設(shè)計(jì)侧戴,即消息的處理盡可能在同一個(gè)線程內(nèi)完成宁昭,期間不進(jìn)行線程切換,這樣就避免了多線程競(jìng)爭(zhēng)和同步鎖酗宋。

為了盡可能提升性能积仗,Netty采用了串行無鎖化設(shè)計(jì),在IO線程內(nèi)部進(jìn)行串行操作蜕猫,避免多線程競(jìng)爭(zhēng)導(dǎo)致的性能下降斥扛。表面上看,串行化設(shè)計(jì)似乎CPU利用率不高丹锹,并發(fā)程度不夠。但是芬失,通過調(diào)整NIO線程池的線程參數(shù)楣黍,可以同時(shí)啟動(dòng)多個(gè)串行化的線程并行運(yùn)行,這種局部無鎖化的串行線程設(shè)計(jì)相比一個(gè)隊(duì)列-多個(gè)工作線程模型性能更優(yōu)棱烂。

Netty的串行化設(shè)計(jì)工作原理圖如下:

圖2-25 Netty串行化工作原理圖

Netty的NioEventLoop讀取到消息之后租漂,直接調(diào)用ChannelPipeline的fireChannelRead(Object msg),只要用戶不主動(dòng)切換線程颊糜,一直會(huì)由NioEventLoop調(diào)用到用戶的Handler哩治,期間不進(jìn)行線程切換,這種串行化處理方式避免了多線程操作導(dǎo)致的鎖的競(jìng)爭(zhēng)衬鱼,從性能角度看是最優(yōu)的业筏。

2.2.6. 高效的并發(fā)編程

Netty的高效并發(fā)編程主要體現(xiàn)在如下幾點(diǎn):

1) volatile的大量、正確使用;

2) CAS和原子類的廣泛使用鸟赫;

3) 線程安全容器的使用蒜胖;

4) 通過讀寫鎖提升并發(fā)性能。

如果大家想了解Netty高效并發(fā)編程的細(xì)節(jié)抛蚤,可以閱讀之前我在微博分享的《多線程并發(fā)編程在 Netty 中的應(yīng)用分析》台谢,在這篇文章中對(duì)Netty的多線程技巧和應(yīng)用進(jìn)行了詳細(xì)的介紹和分析。

2.2.7. 高性能的序列化框架

影響序列化性能的關(guān)鍵因素總結(jié)如下:

1) 序列化后的碼流大兴昃(網(wǎng)絡(luò)帶寬的占用)朋沮;

2) 序列化&反序列化的性能(CPU資源占用);

3) 是否支持跨語(yǔ)言(異構(gòu)系統(tǒng)的對(duì)接和開發(fā)語(yǔ)言切換)缀壤。

Netty默認(rèn)提供了對(duì)Google Protobuf的支持樊拓,通過擴(kuò)展Netty的編解碼接口纠亚,用戶可以實(shí)現(xiàn)其它的高性能序列化框架,例如Thrift的壓縮二進(jìn)制編解碼框架骑脱。

下面我們一起看下不同序列化&反序列化框架序列化后的字節(jié)數(shù)組對(duì)比:

圖2-26 各序列化框架序列化碼流大小對(duì)比

從上圖可以看出菜枷,Protobuf序列化后的碼流只有Java序列化的1/4左右。正是由于Java原生序列化性能表現(xiàn)太差叁丧,才催生出了各種高性能的開源序列化技術(shù)和框架(性能差只是其中的一個(gè)原因啤誊,還有跨語(yǔ)言、IDL定義等其它因素)拥娄。

2.2.8. 靈活的TCP參數(shù)配置能力

合理設(shè)置TCP參數(shù)在某些場(chǎng)景下對(duì)于性能的提升可以起到顯著的效果蚊锹,例如SO_RCVBUF和SO_SNDBUF。如果設(shè)置不當(dāng)稚瘾,對(duì)性能的影響是非常大的牡昆。下面我們總結(jié)下對(duì)性能影響比較大的幾個(gè)配置項(xiàng):

1) SO_RCVBUF和SO_SNDBUF:通常建議值為128K或者256K;

2) SO_TCPNODELAY:NAGLE算法通過將緩沖區(qū)內(nèi)的小封包自動(dòng)相連摊欠,組成較大的封包丢烘,阻止大量小封包的發(fā)送阻塞網(wǎng)絡(luò),從而提高網(wǎng)絡(luò)應(yīng)用效率些椒。但是對(duì)于時(shí)延敏感的應(yīng)用場(chǎng)景需要關(guān)閉該優(yōu)化算法播瞳;

3) 軟中斷:如果Linux內(nèi)核版本支持RPS(2.6.35以上版本),開啟RPS后可以實(shí)現(xiàn)軟中斷免糕,提升網(wǎng)絡(luò)吞吐量赢乓。RPS根據(jù)數(shù)據(jù)包的源地址,目的地址以及目的和源端口石窑,計(jì)算出一個(gè)hash值牌芋,然后根據(jù)這個(gè)hash值來選擇軟中斷運(yùn)行的cpu,從上層來看松逊,也就是說將每個(gè)連接和cpu綁定躺屁,并通過這個(gè)hash值,來均衡軟中斷在多個(gè)cpu上经宏,提升網(wǎng)絡(luò)并行處理性能楼咳。

Netty在啟動(dòng)輔助類中可以靈活的配置TCP參數(shù),滿足不同的用戶場(chǎng)景烛恤。相關(guān)配置接口定義如下:

圖2-27 Netty的TCP參數(shù)配置定義

2.3. 總結(jié)

通過對(duì)Netty的架構(gòu)和性能模型進(jìn)行分析母怜,我們發(fā)現(xiàn)Netty架構(gòu)的高性能是被精心設(shè)計(jì)和實(shí)現(xiàn)的,得益于高質(zhì)量的架構(gòu)和代碼缚柏,Netty支持10W TPS的跨節(jié)點(diǎn)服務(wù)調(diào)用并不是件十分困難的事情苹熏。

轉(zhuǎn)自:http://www.infoq.com/cn/articles/netty-high-performance。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市轨域,隨后出現(xiàn)的幾起案子袱耽,更是在濱河造成了極大的恐慌,老刑警劉巖干发,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件朱巨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡枉长,警方通過查閱死者的電腦和手機(jī)冀续,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來必峰,“玉大人洪唐,你說我怎么就攤上這事『鹨希” “怎么了凭需?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)肝匆。 經(jīng)常有香客問我粒蜈,道長(zhǎng),這世上最難降的妖魔是什么旗国? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任枯怖,我火速辦了婚禮,結(jié)果婚禮上粗仓,老公的妹妹穿的比我還像新娘。我一直安慰自己设捐,他們只是感情好借浊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萝招,像睡著了一般蚂斤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上槐沼,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天曙蒸,我揣著相機(jī)與錄音,去河邊找鬼岗钩。 笑死纽窟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兼吓。 我是一名探鬼主播臂港,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了审孽?” 一聲冷哼從身側(cè)響起县袱,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎佑力,沒想到半個(gè)月后式散,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡打颤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年暴拄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘸洛。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡揍移,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出反肋,到底是詐尸還是另有隱情那伐,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布石蔗,位于F島的核電站罕邀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏养距。R本人自食惡果不足惜诉探,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望棍厌。 院中可真熱鬧肾胯,春花似錦、人聲如沸耘纱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)束析。三九已至艳馒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間员寇,已是汗流浹背弄慰。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝶锋,地道東北人陆爽。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扳缕,于是被迫代替她去往敵國(guó)和親墓陈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子恶守,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前奏 https://tech.meituan.com/2016/11/04/nio.html 綜述 netty通...
    jiangmo閱讀 5,855評(píng)論 0 13
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)贡必,斷路器兔港,智...
    卡卡羅2017閱讀 134,652評(píng)論 18 139
  • 零、寫在前面 本文雖然是講Netty仔拟,但實(shí)際更關(guān)注的是Netty中的NIO的實(shí)現(xiàn)衫樊,所以對(duì)于Netty中的OIO(O...
    TheAlchemist閱讀 3,292評(píng)論 1 34
  • 今天發(fā)通知科侈,大四一周之內(nèi)選定論文方向,草擬題目炒事,申請(qǐng)導(dǎo)師臀栈。突然一驚,這就是真的要畢業(yè)了挠乳∪ㄊ恚回宿舍莫名其妙收拾房間,舍...
    牧狼人布川酷閱讀 262評(píng)論 0 0
  • 我想你了 像游魚沒有深海 那么深 卻觸不及 我想你了 是布達(dá)拉宮的風(fēng)景 你渴望的純潔 我想你了 像冬季的飄雪 融化...
    彀爾清歡閱讀 349評(píng)論 0 3