Netty是什麼? Netty相關知識的深入解析
這篇文章帶給大家的內容是關於Netty是什麼? Netty相關知識的深入解析,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
Netty到底是什麼
從HTTP說起
有了Netty,你可以實作自己的HTTP伺服器,FTP伺服器,UDP伺服器, RPC伺服器,WebSocket伺服器,Redis的Proxy伺服器,MySQL的Proxy伺服器等等。
我們回顧傳統的HTTP伺服器的原理
1、建立一個ServerSocket,監聽並綁定一個連接埠
2、一系列客戶端來請求這個連接埠
3、伺服器使用Accept,取得一個來自客戶端的Socket連線物件
4、啟動一個新執行緒處理連線
4.1、讀取Socket,得到位元組流
4.2、解碼協議,得到Http請求物件
4.3、處理Http請求,得到一個結果,封裝成一個HttpResponse物件
4.4、編碼協議,將結果序列化字節流寫Socket,將位元組流發給客戶端
5、繼續循環步驟3
HTTP伺服器之所以稱為HTTP伺服器,是因為編碼解碼協定是HTTP協議,如果協定是Redis協議,那它就變成了Redis伺服器,如果協定是WebSocket,那它就變成了WebSocket伺服器,等等。使用Netty你就可以自訂編解碼協議,實作自己的特定協議的伺服器。
NIO
上面有傳統處理http的伺服器,但在高並發的環境下,執行緒數量會比較多,System load也會比較高,所以就有了NIO。
他不是Java獨有的概念,NIO代表的一個詞彙叫著IO多路復用。它是由作業系統提供的系統調用,早期這個作業系統調用的名字是select,但是效能低下,後來漸漸演化成了Linux下的epoll和Mac裡的kqueue。我們通常會說是epoll,因為沒有人拿蘋果電腦當伺服器來使用對外提供服務。而Netty就是基於Java NIO技術封裝的一套架構。為什麼要封裝,因為原生的Java NIO使用起來沒那麼方便,而且還有臭名昭著的bug,Netty把它封裝之後,提供了一個易於操作的使用模式和接口,用戶使用起來也就便捷多了。
說NIO之前先說一下BIO(Blocking IO),如何理解這個Blocking呢?
客戶端監聽(Listen)時,Accept是阻塞的,只有新連線來了,Accept才會回,主執行緒才能繼
讀寫socket時,Read是阻塞的,只有請求訊息來了,Read才能返回,子執行緒才能繼續處理
讀寫socket時,Write是阻塞的,只有客戶端把訊息收了,Write才能返回,子執行緒才能繼續讀取下一個請求
傳統的BIO模式下,從頭到尾的所有執行緒都是阻塞的,這些執行緒就乾等著,佔用系統的資源,什麼事也不幹。
那麼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() // 写消息 } } }
Reactor執行緒模型
Reactor單執行緒模型
一個NIO執行緒一個accept執行緒:
#Reactor多執行緒模型
Reactor主從模型
主從Reactor多執行緒:多個acceptor的NIO執行緒池用於接受客戶端的連線
Netty可以基於如上三種模型進行靈活的配置。
總結
Netty是建立在NIO基礎之上,Netty在NIO之上又提供了更高層次的抽象。
在Netty裡面,Accept連線可以使用單獨的執行緒池去處理,讀寫操作又是另外的執行緒池來處理。
Accept连接和读写操作也可以使用同一个线程池来进行处理。而请求处理逻辑既可以使用单独的线程池进行处理,也可以跟放在读写线程一块处理。线程池中的每一个线程都是NIO线程。用户可以根据实际情况进行组装,构造出满足系统需求的高性能并发模型。
为什么选择Netty
如果不用netty,使用原生JDK的话,有如下问题:
1、API复杂
2、对多线程很熟悉:因为NIO涉及到Reactor模式
3、高可用的话:需要出路断连重连、半包读写、失败缓存等问题
4、JDK NIO的bug
而Netty来说,他的api简单、性能高而且社区活跃(dubbo、rocketmq等都使用了它)
什么是TCP 粘包/拆包
现象
先看如下代码,这个代码是使用netty在client端重复写100次数据给server端,ByteBuf是netty的一个字节容器,里面存放是的需要发送的数据
public class FirstClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) { for (int i = 0; i < 1000; i++) { ByteBuf buffer = getByteBuf(ctx); ctx.channel().writeAndFlush(buffer); } } private ByteBuf getByteBuf(ChannelHandlerContext ctx) { byte[] bytes = "需要更多资料加群:586446657".getBytes(Charset.forName("utf-8")); ByteBuf buffer = ctx.alloc().buffer(); buffer.writeBytes(bytes); return buffer; } }
从client端读取到的数据为:
从服务端的控制台输出可以看出,存在三种类型的输出
一种是正常的字符串输出。
一种是多个字符串“粘”在了一起,我们定义这种 ByteBuf 为粘包。
一种是一个字符串被“拆”开,形成一个破碎的包,我们定义这种 ByteBuf 为半包。
透过现象分析原因
应用层面使用了Netty,但是对于操作系统来说,只认TCP协议,尽管我们的应用层是按照 ByteBuf 为 单位来发送数据,server按照Bytebuf读取,但是到了底层操作系统仍然是按照字节流发送数据,因此,数据到了服务端,也是按照字节流的方式读入,然后到了 Netty 应用层面,重新拼装成 ByteBuf,而这里的 ByteBuf 与客户端按顺序发送的 ByteBuf 可能是不对等的。因此,我们需要在客户端根据自定义协议来组装我们应用层的数据包,然后在服务端根据我们的应用层的协议来组装数据包,这个过程通常在服务端称为拆包,而在客户端称为粘包。
拆包和粘包是相对的,一端粘了包,另外一端就需要将粘过的包拆开,发送端将三个数据包粘成两个 TCP 数据包发送到接收端,接收端就需要根据应用协议将两个数据包重新组装成三个数据包。
如何解决
在没有 Netty 的情况下,用户如果自己需要拆包,基本原理就是不断从 TCP 缓冲区中读取数据,每次读取完都需要判断是否是一个完整的数据包 如果当前读取的数据不足以拼接成一个完整的业务数据包,那就保留该数据,继续从 TCP 缓冲区中读取,直到得到一个完整的数据包。 如果当前读到的数据加上已经读取的数据足够拼接成一个数据包,那就将已经读取的数据拼接上本次读取的数据,构成一个完整的业务数据包传递到业务逻辑,多余的数据仍然保留,以便和下次读到的数据尝试拼接。
而在Netty中,已经造好了许多类型的拆包器,我们直接用就好:
选好拆包器后,在代码中client段和server端将拆包器加入到chanelPipeline之中就好了:
如上实例中:
客户端:
ch.pipeline().addLast(new FixedLengthFrameDecoder(31));
服务端:
ch.pipeline().addLast(new FixedLengthFrameDecoder(31));
Netty 的零拷贝
传统意义的拷贝
是在发送数据的时候,传统的实现方式是:
1. `File.read(bytes)`
2. `Socket.send(bytes)`
这种方式需要四次数据拷贝和四次上下文切换:
1. 数据从磁盘读取到内核的read buffer
2. 数据从内核缓冲区拷贝到用户缓冲区
3. 数据从用户缓冲区拷贝到内核的socket buffer
4. 数据从内核的socket buffer拷贝到网卡接口(硬件)的缓冲区
零拷贝的概念
明显上面的第二步和第三步是没有必要的,通过java的FileChannel.transferTo方法,可以避免上面两次多余的拷贝(当然这需要底层操作系统支持)
1. 呼叫transferTo,資料從檔案由DMA引擎拷貝到核心read buffer
2. 接著DMA從核心read buffer將資料拷貝到網卡介面buffer
上面的兩次操作都不需要CPU參與,所以就達到零拷貝了。
Netty中的零拷貝
主要體現在三個方面:
#1、bytebuffer
Netty發送和接收訊息主要使用bytebuffer,bytebuffer使用對外記憶體(DirectMemory)直接進行Socket讀寫。
原因:如果使用傳統的堆疊記憶體進行Socket讀寫,JVM會將堆疊記憶體buffer拷貝一份到直接記憶體中然後再寫入socket,多了一次緩衝區的記憶體拷貝。 DirectMemory中可以直接透過DMA傳送到網卡介面
2、Composite Buffers
傳統的ByteBuffer,如果需要將兩個ByteBuffer中的資料組合在一起,我們需要先建立一個size= size1 size2大小的新的數組,然後將兩個數組中的資料拷貝到新的數組中。但是使用Netty提供的組合ByteBuf,就可以避免這樣的操作,因為CompositeByteBuf並沒有真正將多個Buffer組合起來,而是保存了它們的引用,從而避免了數據的拷貝,實現了零拷貝。
3、對於FileChannel.transferTo的使用
Netty中使用了FileChannel的transferTo方法,該方法依賴作業系統實作零拷貝。
Netty 內部執行流程
服務端:
1、建立ServerBootStrap實例
2、設定並綁定Reactor執行緒池:EventLoopGroup,EventLoop就是處理所有註冊到本執行緒的Selector上面的Channel
3、設定並綁定服務端的channel
4、5、建立處理網路事件的ChannelPipeline和handler,網路時間以流的形式在其中流轉,handler完成多數的功能自訂:例如編解碼SSl安全認證
6、綁定並啟動監聽埠
7、當輪訓到準備就緒的channel後,由Reactor執行緒:NioEventLoop執行pipline中的方法,最終調度並執行channelHandler
8、說到這裡順便給大家推薦一個Java的交流學習社區:586446657,裡面不僅可以交流討論,還有面試經驗分享以及免費的資料下載,包括Spring,MyBatis,Netty源碼分析,高並發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。相信對於已經工作和遇到技術瓶頸的碼友,在這裡會有你需要的內容。
客戶端
#總結
以上就是我對Netty相關知識整理,如果有不同的見解,歡迎討論!
以上是Netty是什麼? Netty相關知識的深入解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

TCP是電腦網路通訊協定的一種,是一種連線導向的傳輸協定。在Java應用開發中,TCP通訊被廣泛應用於各種場景,例如客戶端和伺服器之間的資料傳輸、音訊視訊即時傳輸等等。 Netty4是一個高效能、高可擴展性、高效能的網路程式框架,能夠優化伺服器和用戶端之間的資料交換流程,使其更有效率可靠。使用Netty4進行TCP通訊的具體實作步驟如下:引入

Java開發:如何使用Netty進行高效能網路程式設計摘要:Netty是一個高效能、非同步事件驅動的網路程式框架,能夠簡化網路應用程式的開發過程。本文將介紹Netty的主要特點以及如何使用Netty進行高性能網路程式設計。同時,我們也會提供一些具體的Java程式碼範例,幫助讀者更能理解和應用Netty。一、Netty簡介Netty是一個基於JavaNIO的網路程式框

隨著網路科技的不斷發展,網路程式設計變得越來越重要。在這個領域中,Netty是一個十分知名的框架。它是一個高效能、非同步事件驅動的網路應用程式框架,被廣泛用於開發各種高並發的網路應用程式。 Netty是一個Java框架,它的產生推動了Java網路程式設計的發展。然而,隨著PHP的廣泛使用,PHP開發者也在尋找能夠勝任高並發網路程式設計的框架。因此,本文介紹如何利用P

netty作為一個高效能的io框架,是非好用的一個技術框架,Netty是一個基於NIO的客戶、伺服器端程式設計框架,使用Netty可以確保你快速且簡單的開發出一個網路應用,例如實現了某種協定的客戶、服務端應用。 Netty相當於簡化和流線化了網路應用的程式開發過程,例如:基於TCP和UDP的socket服務開發。 「快速」和「簡單」並不用產生維護性或效能上的問題。 Netty是個吸收了多種協定(包括FTP、SMTP、HTTP等各種二進位文字協定)的實作經驗,並經過相當精心設計的專案。最終,Netty成功

隨著互聯網的不斷發展和應用領域的不斷擴展,高並發成為了網絡應用開發中必須考慮的問題,而Java作為一種廣泛應用於企業級應用開發的語言,其在高並發應用場景下的表現備受關注。 Netty是一款高效能、非同步事件驅動的網路應用框架,近年來在Java後端開發領域享有廣泛的應用。本文將介紹Netty的基本概念和使用方法,並以建立高同時的API伺服器為例,展示Netty

如何使用Java開發一個基於Netty的高效能網路應用Netty是一種基於JavaNIO技術的網路程式框架,被廣泛應用於高效能的網路應用開發。在本文中,我們將探討如何使用Java和Netty來開發一個基於Netty的高效能網路應用。我們將介紹Netty的基本概念和特性,並提供一些程式碼範例以幫助你更好地理解和使用Netty。一、Netty的基本概念與特性Ne

JavaAPI開發中使用Netty進行TCP通訊在現代軟體開發中,網路通訊已成為不可或缺的一部分。 Netty是一種Java框架,用於在高效能網路應用中有效地進行快速開發。它提供了一組易於使用的API,封裝了JavaNIO和其他網路庫。在JavaAPI開發中,Netty的優越性可以體現在以下幾個方面:高性能Netty的應用程式

在JavaAPI開發中,TCP通訊是一個非常重要的元件,而Netty5是一套基於NIO的高效能網路通訊框架,可以非常方便地處理複雜的網路通訊任務。本文將介紹如何使用Netty5進行TCP通信,包括Netty5的核心元件、常用API的介紹和實際應用案例。同時,本文也將介紹如何使用Netty5來提高TCP通訊的效能和可靠性。一、Netty5的核心組件Netty5
