Netty知識彙總

1、TCP、UDP的區別?

TCP與UDP區別總結:

1)、TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的,即發送數據之前不需要建立連接。

2)、TCP提供可靠的服務。也就是說,通過TCP連接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付

3)、TCP面向字節流,實際上是TCP把數據看成一連串無結構的字節流;UDP是面向報文的
UDP沒有擁塞控制,因此網絡出現擁塞不會使源主機的發送速率降低(對實時應用很有用,如IP電話,實時視頻會議等)

4)、每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信

5)、TCP首部開銷20字節;UDP的首部開銷小,只有8個字節

6)、TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道

2、TCP協議如何保證可靠傳輸?

https://www.cnblogs.com/xiaokang01/p/10033267.html

3、TCP的握手、揮手機制?

TCP的握手機制:

TCP的揮手機制:

詳情參考文章:
https://blog.csdn.net/qzcsu/article/details/72861891

4、TCP的粘包/拆包原因及其解決方法是什麼?

爲什麼會發生TCP粘包、拆包?
發生TCP粘包、拆包主要是由於下面一些原因:

1).應用程序寫入的數據大於套接字緩衝區大小,這將會發生拆包。

2).應用程序寫入數據小於套接字緩衝區大小,網卡將應用多次寫入的數據發送到網絡上,這將會發生粘包。

3).進行MSS(最大報文長度)大小的TCP分段,當TCP報文長度-TCP頭部長度>MSS的時候將發生拆包。

4).接收方法不及時讀取套接字緩衝區數據,這將發生粘包。

粘包、拆包解決辦法:

TCP本身是面向流的,作爲網絡服務器,如何從這源源不斷涌來的數據流中拆分出或者合併出有意義的信息呢?通常會有以下一些常用的方法:

1)、發送端給每個數據包添加包首部,首部中應該至少包含數據包的長度,這樣接收端在接收到數據後,通過讀取包首部的長度字段,便知道每一個數據包的實際長度了。

2)、發送端將每個數據包封裝爲固定長度(不夠的可以通過補0填充),這樣接收端每次從接收緩衝區中讀取固定長度的數據就自然而然的把每個數據包拆分開來。

3)、可以在數據包之間設置邊界,如添加特殊符號,這樣,接收端通過這個邊界就可以將不同的數據包拆分開。

詳情參考文章:https://www.cnblogs.com/panch...

5、Netty的粘包/拆包是怎麼處理的,有哪些實現?

對於粘包和拆包問題,常見的解決方案有四種:

1)、客戶端在發送數據包的時候,每個包都固定長度,比如1024個字節大小,如果客戶端發送的數據長度不足1024個字節,則通過補充空格的方式補全到指定長度;Netty提供的FixedLengthFrameDecoder

2)、客戶端在每個包的末尾使用固定的分隔符,例如rn,如果一個包被拆分了,則等待下一個包發送過來之後找到其中的rn,然後對其拆分後的頭部部分與前一個包的剩餘部分進行合併,這樣就得到了一個完整的包;Netty提供LineBasedFrameDecoder與DelimiterBasedFrameDecoder

3)、將消息分爲頭部和消息體,在頭部中保存有當前整個消息的長度,只有在讀取到足夠長度的消息之後纔算是讀到了一個完整的消息;Netyy提供了LengthFieldBasedFrameDecoder與LengthFieldPrepender

4)、通過自定義協議進行粘包和拆包的處理。Netty提供了通過實現MessageToByteEncoder和ByteToMessageDecoder來實現

更詳細請閱讀文章:https://www.cnblogs.com/AIPAO...

6、同步與異步、阻塞與非阻塞的區別?

簡單點理解就是:

1). 同步,就是我調用一個功能,該功能沒有結束前,我死等結果。

2). 異步,就是我調用一個功能,不需要知道該功能結果,該功能有結果後通知我(回調通知)

3). 阻塞,就是調用我(函數),我(函數)沒有接收完數據或者沒有得到結果之前,我不會返回。

4). 非阻塞,就是調用我(函數),我(函數)立即返回,通過select通知調用者

同步IO和異步IO的區別就在於:數據拷貝的時候進程是否阻塞

阻塞IO和非阻塞IO的區別就在於:應用程序的調用是否立即返回

7、說說網絡IO模型?

8、BIO、NIO、AIO分別是什麼?

BIO:同步並阻塞,服務器實現模式爲一個連接一個線程,即客戶端有連接請求時服務器端就需要啓動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。BIO方式適用於連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。

NIO:同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的連接請求都會註冊到多路複用器上,多路複用器輪詢到連接有I/O請求時才啓動一個線程進行處理。NIO方式適用於連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4開始支持。

AIO:異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啓動線程進行處理.AIO方式使用於連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與併發操作,編程比較複雜,JDK7開始支持。

9、select、poll、epoll的機制及其區別?

1).單個進程打開的文件描述符(fd文件句柄)不一致

select :有最大連接數限制數爲1024,單個進程所能打開的最大連接數由FD_ZETSIZE宏定義。

poll:poll本質上與select沒有區別,但是它沒有最大連接數的限制,原因是它是基於鏈表來存儲的。

epoll:雖然連接有上限,但是很大,1G內存的機器可以打開10萬左右的連接,以此類推。

2).監聽Socket的方式不一致

select :輪詢的方式,一個一個的socket檢查過去,發現有socket活躍時才進行處理,當線性socket增多時,輪詢的速度將會變得很慢,造成線性造成性能下降問題。

poll:對select稍微進行了優化,只是修改了文件描述符,但是監聽socket的方式還是輪詢。

expoll:epoll內核中實現是根據每個fd上的callback函數來實現的,只有活躍的socket纔會主動調用callback,通知expoll來處理這個socket。(會將連接的socket註冊到epoll中, 相當於socket的花名冊, 如果有一個socket活躍了, 會回調一個函數, 通知epoll,趕緊過來處理)

3).內存空間拷貝方式(消息傳遞方式)不一致

select:內核想將消息傳遞到用戶態,需要將數據從內核態拷貝到用戶態,這個過程非常的耗時

poll:同上

epoll:epoll的內核和用戶空間共享一塊內存,因此內存態數據和用戶態數據是共享的

select、poll、epoll時間複雜度分別是:O(n)、O(n)、O(1)

10、說說你對Netty的瞭解?

這個沒用過的話,就不要死撐了。用過的估計不用找了吧。

11、Netty跟Java NIO有什麼不同,爲什麼不直接使用JDK NIO類庫?

說說NIO有什麼缺點吧:

NIO的類庫和API還是有點複雜,比如Buffer的使用
Selector編寫複雜,如果對某個事件註冊後,業務代碼過於耦合
需要了解很多多線程的知識,熟悉網絡編程
面對斷連重連、保丟失、粘包等,處理複雜
NIO存在BUG,根據網上言論說是selector空輪訓導致CPU飆升,具體有興趣的可以看看JDK的官網

Netty主要的優點有:

框架設計優雅,底層模型隨意切換適應不同的網絡協議要求

提供很多標準的協議、安全、編碼解碼的支持

解決了很多NIO不易用的問題

社區更爲活躍,在很多開源框架中使用,如Dubbo、RocketMQ、Spark等

底層核心有:Zero-Copy-Capable
Buffer,非常易用的靈拷貝Buffer(這個內容很有意思,稍後專門來說);統一的API;標準可擴展的時間模型

傳輸方面的支持有:管道通信(具體不知道幹啥的,還請老司機指教);Http隧道;TCP與UDP

協議方面的支持有:基於原始文本和二進制的協議;解壓縮;大文件傳輸;流媒體傳輸;protobuf編解碼;安全認證;http和websocket

總之提供了很多現成的功能可以直接供開發者使用。

12、Netty組件有哪些,分別有什麼關聯?

Channel ----Socket

EventLoop ----控制流,多線程處理,併發;

ChannelHandler和ChannelPipeline

Bootstrap 和 ServerBootstrap

更多詳情可以閱讀:https://blog.csdn.net/summerZ...

13、說說Netty的執行流程?

1)、創建ServerBootStrap實例

2)、設置並綁定Reactor線程池:EventLoopGroup,EventLoop就是處理所有註冊到本線程的Selector上面的Channel

3)、設置並綁定服務端的channel

4)、5)、創建處理網絡事件的ChannelPipeline和handler,網絡時間以流的形式在其中流轉,handler完成多數的功能定製:比如編解碼 SSl安全認證

6)、綁定並啓動監聽端口

7)、當輪訓到準備就緒的channel後,由Reactor線程:NioEventLoop執行pipline中的方法,最終調度並執行channelHandler

更多請參考文章:https://juejin.im/post/5bf8fb...

14、Netty高性能體現在哪些方面?

https://www.infoq.cn/article/...

15、Netty的線程模型是怎麼樣的?

Reactor線程模型

Reactor單線程模型
一個NIO線程+一個accept線程:

Reactor多線程模型

Reactor主從模型
主從Reactor多線程:多個acceptor的NIO線程池用於接受客戶端的連接

Netty可以基於如上三種模型進行靈活的配置。

總結

Netty是建立在NIO基礎之上,Netty在NIO之上又提供了更高層次的抽象。在Netty裏面,Accept連接可以使用單獨的線程池去處理,讀寫操作又是另外的線程池來處理。Accept連接和讀寫操作也可以使用同一個線程池來進行處理。而請求處理邏輯既可以使用單獨的線程池進行處理,也可以跟放在讀寫線程一塊處理。線程池中的每一個線程都是NIO線程。用戶可以根據實際情況進行組裝,構造出滿足系統需求的高性能併發模型。

16、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、bytebufferNetty發送和接收消息主要使用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方法,該方法依賴於操作系統實現零拷貝。

17、Netty的內存池是怎麼實現的?

netty內存池實現原理

netty內存池可以分配堆內存和非堆內存(Direct內存),內存分配的核心算法是類似的,從堆內存分配代碼入手來學習整個內存池的原理。netty框架處理IO事件時,使用ByteBuf承載數據。ByteBuf的內存分配由PooledByteBufAllocator來執行,最終的內存分配工作會被委託給PoolArena,堆內存分配的PoolArena實現是HeapArena。

netty通常被用於高併發系統,多線程競爭加鎖會影響內存分配的效率,爲了緩解高併發時的線程競爭,netty允許使用者創建多個分配器(PoolArena)來分離線程競爭,提高內存分配效率。可通過PooledByteBufAllocator構造子中的nHeapArena參數來設置PoolArena的數量,或者直接取框架中的默認值,通過以下代碼決定默認值,默認值根據CPU核心數、JVM最大可用內存以及默認內存塊(PoolChunk)大小等參數來計算這個默認值,計算邏輯是:

1)獲取系統變量io.netty.allocator.numHeapArenas,通過System.setProperty("io.netty.allocator.numHeapArenas",xxx)或者增加JVM啓動參數-Dio.netty.allocator.numHeapArenas=xxx設置,如果設置了值,把這個值當做Arena的個數。

2)如果沒有設置io.netty.allocator.numHeapArenas系統變量,計算CPU核心數*2和JVM最大可用內存/默認內存塊大小/2/3,取其中一個較少的值當做PoolArena的個數。

確定PoolArena個數之後框架會創建一個PoolArena數組,數組中所有的PoolArena都會用來執行內存分配。線程申請內存分配時,線程會在這個PoolArena數組中挑選一個當前被佔用次數最少的Arena執行內存分配。

此外,netty使用擴展的線程對象FastThreadLocalThread來優化ThreadLocal性能,具體的優化思路是:默認的ThreadLocal使用ThreadLocalMap存儲線程局部變量,它的實現方式類似於HashMap,需要計算hashCode定位到線程局部變量所在Entry的索引,而FastThreadLocalThread使用FastThreadLocal代替ThreadLocal,FastThreadLocalThread用一個數組來維護線程變量,每個FastThreadLocal維護一個index,該index就是線程局部變量在數組中的位置,線程變量直接通過index訪問無需計算hashCode,FastThreadLocal的優勢是減少了hashCode的計算過程,雖然性能只會有輕微的提升,但在高併發系統中,即使只是輕微的提升也會成倍放大。

更多請閱讀文章:http://baijiahao.baidu.com/s?...

18、Netty的對象池是怎麼實現的?

Netty 並沒有使用第三方庫實現對象池,而是自己實現了一個相對輕量的對象池。通過使用 threadLocal,避免了多線程下取數據時可能出現的線程安全問題,同時,爲了實現多線程回收同一個實例,讓每個線程對應一個隊列,隊列鏈接在 Stack 對象上形成鏈表,這樣,就解決了多線程回收時的安全問題。同時,使用了軟引用的map 和 軟引用的 thradl 也避免了內存泄漏。

更詳細的可閱讀文章:

https://www.jianshu.com/p/834...
https://www.cnblogs.com/hzmar...

19、在實際項目中,你們是怎麼使用Netty的?

沒用過。

20、使用過Netty遇到過什麼問題?

(1)創建兩個NioEventLoopGroup,用於邏輯隔離NIO Acceptor和NIO I/O線程

(2)儘量不要在ChannelHandler中啓動用戶線程(解碼後用於將POJO消息派發到後端業務線程的除外)

(3)解碼要放在NIO線程調用的解碼Handler中進行,不要切換到用戶線程完成消息的解碼.

(4)如果業務邏輯操作非常簡單(純內存操作),沒有複雜的業務邏輯計算,也可能會導致線程被阻塞的磁盤操作,數據庫操作,網絡操作等,可以直接在NIO線程上完成業務邏輯編排,不需要切換到用戶線程.

(5)如果業務邏輯複雜,不要在NIO線程上完成,建議將解碼後的POJO消息封裝成任務,派發到業務線程池中由業務線程執行,以保證NIO線程儘快釋放,處理其它I/O操作.

(6)可能導致阻塞的操作,數據庫操作,第三方服務調用,中間件服務調用,同步獲取鎖,Sleep等

(7)Sharable註解的ChannelHandler要慎用

(8)避免將ChannelHandler加入到不同的ChannelPipeline中,會出現併發問題.

串行執行的ChannelHandler的工作原理

從上面的隨便挑一個吹水就行。

21、netty的線程模型,netty如何基於reactor模型上實現的。

這個網上很多了,就不說了。
https://www.cnblogs.com/codin...

23、netty的fashwheeltimer的用法,實現原理,是否出現過調用不夠準時,怎麼解決。

https://www.cnblogs.com/eryua...

24、netty的心跳處理在弱網下怎麼辦。

https://blog.csdn.net/z691837...

25、netty的通訊協議是什麼樣的。

https://www.cnblogs.com/54929...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章