聽(tīng)說(shuō)96.5%的程序員都沒(méi)用過(guò)Netty
Netty介紹
Netty是一個(gè)基于Java的高性能網(wǎng)絡(luò)應(yīng)用框架,封裝了Java NIO的復(fù)雜性,提供了簡(jiǎn)單而強(qiáng)大的網(wǎng)絡(luò)編程API,使得開(kāi)發(fā)者能夠更方便地開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用程序。
所以說(shuō)學(xué)習(xí)Netty前先理解一下Java NIO是很有必要的,不然云里霧里的。
Netty有多優(yōu)秀呢?包括但不限于以下幾點(diǎn)
高性能的IO處理
如果基于Java NIO開(kāi)發(fā)一個(gè)成熟的應(yīng)用,要非常注意如ByteBuffer內(nèi)存泄漏、Channel注冊(cè)連接、線(xiàn)程管理等問(wèn)題。
而Netty能夠更好地處理連接管理、線(xiàn)程模型和內(nèi)存管理等方面的問(wèn)題,提供更高的吞吐量和更低的延遲。
強(qiáng)大的功能擴(kuò)展
如果基于Java NIO寫(xiě)一個(gè)HTTP協(xié)議、Websocket協(xié)議,那我們需要考慮格式、編解碼問(wèn)題。
而Netty提供了豐富的擴(kuò)展點(diǎn),比如編解碼器、處理器和攔截器等,開(kāi)發(fā)人員可以通過(guò)不同的配置搭建HTTP、WebSocket、TCP和RTSP等協(xié)議,也可以輕松地添加編解碼器,實(shí)現(xiàn)自定義協(xié)議。
可靠性和穩(wěn)定性
Netty具有良好的容錯(cuò)能力和穩(wěn)定性,能夠處理各種網(wǎng)絡(luò)故障和異常情況,并提供了多種容錯(cuò)和恢復(fù)機(jī)制,如斷線(xiàn)重連和心跳機(jī)制等。
總的來(lái)說(shuō),開(kāi)發(fā)人員在開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用程序時(shí),使用Netty能夠更專(zhuān)注于業(yè)務(wù)邏輯。
下圖為Netty所支持的功能
圖片
Netty發(fā)展歷程
為了進(jìn)一步了解Netty,這里介紹一下Netty的前世今生。
- 2004年:Netty的前身Jboss Netty項(xiàng)目在JBoss公司內(nèi)部啟動(dòng),目標(biāo)是提供一個(gè)可擴(kuò)展的、易用的網(wǎng)絡(luò)編程框架。
- 2008年:Netty項(xiàng)目在JBoss公司內(nèi)部開(kāi)源,并發(fā)布了第一個(gè)公開(kāi)版本Netty 3.0。該版本主要針對(duì)TCP和HTTP協(xié)議進(jìn)行了支持。
- 2011年:Netty 3.2發(fā)布,引入了更多的特性和改進(jìn),包括更好的性能和更靈活的API設(shè)計(jì)。
- 2012年:Netty 4.0發(fā)布,這是一個(gè)重大的里程碑版本。在這個(gè)版本中,Netty進(jìn)行了全面的重構(gòu)和優(yōu)化,引入了新的API設(shè)計(jì)和更高級(jí)的特性。
- 2013年:Netty 4.0獲得了廣泛的認(rèn)可和采用,并成為了許多大型互聯(lián)網(wǎng)公司和項(xiàng)目的首選網(wǎng)絡(luò)編程框架。同年底發(fā)布了5.0.0.Alpha1,目標(biāo)是對(duì)Netty 4改進(jìn)和優(yōu)化。
- 2015年:Netty 5在開(kāi)發(fā)過(guò)程中遇到了一些挑戰(zhàn)和技術(shù)難題,決定暫停Netty 5的開(kāi)發(fā),并將重心轉(zhuǎn)移到Netty 4的改進(jìn)和維護(hù)上。
- 2016年:Netty 4.1發(fā)布,基于4.0版本進(jìn)一步改進(jìn)和優(yōu)化,提供了更好的性能和更多的功能。
目前有很多知名的項(xiàng)目都選用了Netty作為網(wǎng)絡(luò)通信的基礎(chǔ),比如知名的RPC框架Dubbo、gRPC,消息隊(duì)列Kafka、RocketMQ,搜索引擎Elasticsearch等,所以當(dāng)學(xué)習(xí)了解這些項(xiàng)目時(shí),Netty會(huì)作為一個(gè)加分項(xiàng)。
Netty核心組件
因?yàn)镹etty是基于Java NIO封裝的,更加的抽象,要使用Netty進(jìn)行開(kāi)發(fā),必須要熟悉Netty中的幾個(gè)核心組件,下面一一介紹:
- Channel(通道):與Java NIO中的SocketChannel一樣,可以進(jìn)行數(shù)據(jù)的讀取和寫(xiě)入。
- EventLoop(事件循環(huán)):EventLoop是Netty的事件處理機(jī)制,它負(fù)責(zé)處理各種事件,包括連接的建立與關(guān)閉、數(shù)據(jù)的讀取與寫(xiě)入等。可以理解成Java NIO中的Selector監(jiān)聽(tīng)socket的事件,只不過(guò)Netty是多線(xiàn)程處理,后面代碼中有體現(xiàn)。
- ChannelHandler(通道處理器):用來(lái)處理Channel中的事件和數(shù)據(jù)的組件,例如對(duì)數(shù)據(jù)編解碼、業(yè)務(wù)邏輯處理等。Netty提供了許多內(nèi)置的ChannelHandler,用于處理網(wǎng)絡(luò)連接和I/O操作。以下是一些常用的ChannelHandler:
ChannelInboundHandler:用于處理入站事件,例如連接建立、數(shù)據(jù)讀取等。
ChannelOutboundHandler:用于處理出站事件,例如數(shù)據(jù)寫(xiě)入、連接關(guān)閉等。
SimpleChannelInboundHandler:繼承自ChannelInboundHandler,簡(jiǎn)化了消息處理的邏輯。
SimpleChannelOutboundHandler:繼承自ChannelOutboundHandler,簡(jiǎn)化了消息發(fā)送的邏輯。
HttpServerCodec:它負(fù)責(zé)處理 HTTP 請(qǐng)求和響應(yīng)的編解碼。
HttpObjectAggregator:將 HTTP 請(qǐng)求的多個(gè)部分合并成一個(gè)完整的 FullHttpRequest。
WebSocketServerProtocolHandler:處理 WebSocket 協(xié)議的握手和幀的編解碼。
- ChannelPipeline(通道管道):ChannelPipeline是一個(gè)事件處理器鏈,用于管理和執(zhí)行ChannelHandler,每個(gè)Channel都有一個(gè)對(duì)應(yīng)的Pipeline,當(dāng)數(shù)據(jù)進(jìn)入或離開(kāi)Channel時(shí),會(huì)經(jīng)過(guò)Pipeline中的一系列ChannelHandler進(jìn)行處理。
- ByteBuf(字節(jié)緩沖區(qū)):ByteBuf是Netty中的字節(jié)容器,用于高效地存儲(chǔ)和傳輸字節(jié)數(shù)據(jù)。與Java NIO的ByteBuffer相比,ByteBuf提供了更靈活的API和更高效的內(nèi)存管理。
- Future(異步操作結(jié)果):Netty中的操作都是異步的,F(xiàn)uture用來(lái)獲取操作的狀態(tài)和結(jié)果。
- Bootstrap(引導(dǎo)類(lèi)):Bootstrap是啟動(dòng)客戶(hù)端的類(lèi),負(fù)責(zé)配置和啟動(dòng)客戶(hù)端的相關(guān)組件。
- ServerBootstrap(服務(wù)器引導(dǎo)類(lèi)):ServerBootstrap是創(chuàng)建和啟動(dòng)服務(wù)器的類(lèi),用于配置和管理服務(wù)器的各個(gè)組件。
Netty 編程示例
HTTP請(qǐng)求報(bào)文格式
下面以HTTP協(xié)議為例,用Netty編寫(xiě)一個(gè)HTTP服務(wù)器。
在這之前,我們先用上篇文章的NIOServer接收一下瀏覽器的請(qǐng)求,大概是這樣的:
HTTP請(qǐng)求格式
可以看到接收到了一個(gè)HTTP請(qǐng)求的報(bào)文數(shù)據(jù),有請(qǐng)求行、請(qǐng)求頭和請(qǐng)求主體,這時(shí)候也能看到瀏覽器返回的響應(yīng)是:ERR_INVALID_HTTP_RESPONSE,發(fā)送的響應(yīng)無(wú)效。
為什么?這是因?yàn)镹IOServer中的輸出格式HTTP協(xié)議不認(rèn)識(shí)。
實(shí)現(xiàn)HTTP服務(wù)器
所以如果使用Java NIO實(shí)現(xiàn)一個(gè)HTTP服務(wù)器,需要處理很多的工作,但是如果用Netty實(shí)現(xiàn)一個(gè)HTTP服務(wù)器非常簡(jiǎn)單,直接上代碼:
Netty實(shí)現(xiàn)HTTP服務(wù)器
運(yùn)行這個(gè)示例后,你可以使用瀏覽器或者其他工具發(fā)送HTTP請(qǐng)求到 http://localhost:8080 ,一個(gè)HTTP服務(wù)器就誕生了,非常簡(jiǎn)單。
示例代碼說(shuō)明
接下來(lái)對(duì)代碼進(jìn)行講解:
代碼中的b.group(bossGroup, workerGroup)意思是有兩個(gè)線(xiàn)程組會(huì)去處理服務(wù)器中的IO事件,bossGroup只用一個(gè)線(xiàn)程來(lái)專(zhuān)門(mén)負(fù)責(zé)監(jiān)聽(tīng)服務(wù)端的端口,接收客戶(hù)端連接請(qǐng)求,并將連接分配給 workerGroup 中的 EventLoop 進(jìn)行處理。
workerGroup負(fù)責(zé)處理已接收的連接的 I/O 事件,將請(qǐng)求解碼、處理業(yè)務(wù)邏輯以及發(fā)送響應(yīng)等操作都交給 EventLoop 來(lái)處理。這個(gè)是典型的主從Reactor模式,通過(guò)將連接的接收和處理分離到不同的線(xiàn)程池中,可以提高網(wǎng)絡(luò)應(yīng)用程序的性能,模型如下。
圖片
NioServerSocketChannel是指定服務(wù)器的Channel類(lèi)型,還有NioDatagramChannel等類(lèi)型,取決于應(yīng)用場(chǎng)景。
.handler(new LoggingHandler(LogLevel.INFO))是為bossGroup指定一個(gè)通道處理器,記錄進(jìn)出 Channel 的數(shù)據(jù)流,將相關(guān)信息打印到日志中,便于排查。
.childHandler()則是為workerGroup中的EventLoop配置處理器,比如請(qǐng)求解碼、處理業(yè)務(wù)邏輯以及發(fā)送響應(yīng)。
ChannelPipeline就是添加具體的通道處理器,代碼中的HttpServerCodec、HttpObjectAggregator處理器都是用來(lái)處理HTTP請(qǐng)求的編解碼,SimpleChannelInboundHandler則是拿到經(jīng)過(guò)多個(gè)處理器的數(shù)據(jù)流后進(jìn)行業(yè)務(wù)邏輯及響應(yīng)。
總結(jié)
Netty是一個(gè)非常優(yōu)秀的、強(qiáng)大的、高性能的網(wǎng)絡(luò)通信框架,在這個(gè)互聯(lián)網(wǎng)飛速發(fā)展的時(shí)代,我們需要了解并且使用像這樣的優(yōu)秀的框架,幫助我們快速開(kāi)發(fā)應(yīng)用,在使用它的同時(shí)要知其原理,也可以在業(yè)務(wù)中進(jìn)行創(chuàng)新,就像Dubbo、gRPC、Zookeeper一樣采用Netty成為與其一樣優(yōu)秀的框架。
本文轉(zhuǎn)載自微信公眾號(hào)「Hi程序員」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Hi程序員公眾號(hào)。