面試:Netty高性能框架面試題精選集(深度)

1. 什麼是Netty

Netty 是一款提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。
也就是說,Netty 是一個基於 NIO 的客戶、服務器端編程框架。使用 Netty 可以確保你快速和簡單地開發出一個網絡應用,例如實現了某種協議的客戶,服務端應用。Netty 相當簡化和流線化了網絡應用的編程開發過程,例如,TCP 和 UDP 的 socket 服務開發。

2. Netty的特點是什麼( 爲什麼選擇 Netty )
  • 簡單易上手:API 使用簡單,學習,使用門檻低。
  • 功能強大:預置了多種編解碼功能,支持多種主流協議。
  • 靈活度高:可以通過 ChannelHandler 對通信框架進行靈活的擴展。
  • 高性能:通過與其它業界主流的 NIO 框架對比,Netty 的綜合性能最優。
  • 穩定:Netty 修復了已經發現的所有 JDK NIO BUG,業務開發人員不需要再爲 NIO 的 BUG 而煩惱。
  • 社區活躍:版本迭代週期短,發現的BUG可以被及時修復,同時,更多的新功能會被加入。
  • 案例豐富:經歷了大規模的商業應用考驗,質量已經得到驗證。在互聯網、大數據、網絡遊戲、企業應用。
3. Netty爲什麼說使用簡單
  • 無需關心 OP_ACCEPT、OP_READ、OP_WRITE 等等 IO 操作,Netty 已經封裝,對我們在使用是透明無感的。
  • 使用 boss 和 worker EventLoopGroup ,Netty 直接提供多 Reactor 多線程模型。
  • 在 Netty 中,我們看到有使用一個解碼器 FixedLengthFrameDecoder,可以用於處理定長消息的問題,能夠解決 TCP 粘包拆包問題,十分方便。如果使用 Java NIO ,需要我們自行實現解碼器。
4. Netty 的使用場景
  • 構建高性能、低時延的各種 Java 中間件,Netty 主要作爲基礎通信框架提供高性能、低時延的通信服務。例如:RocketMQ ,分佈式消息隊列。Dubbo ,服務調用框架。Spring WebFlux ,基於響應式的 Web 框架。
  • 公有或者私有協議棧的基礎通信框架,例如可以基於 Netty 構建異步、高性能的 WebSocket、Protobuf 等協議的支持。
  • 各領域應用,例如大數據、遊戲等,Netty 作爲高性能的通信框架用於內部各模塊的數據分發、傳輸和彙總等,實現模塊之間高性能通信。
5. Netty 如何實現高性能
  1. 線程模型 :更加優雅的 Reactor 模式實現、靈活的線程模型、利用 EventLoop 等創新性的機制,可以非常高效地管理成百上千的 Channel 。
  2. 內存池設計 :使用池化的 Direct Buffer 等技術,在提高 IO 性能的同時,減少了對象的創建和銷燬。並且,Netty的內部實現是用一顆二叉查找樹,更好的管理內存分配情況。
  3. 內存零拷貝 :使用 Direct Buffer ,可以使用 Zero-Copy 機制(避免上下分切換頻繁)。
  4. 協議支持 :提供對 Protobuf 等高性能序列化協議支持。
6. Netty 的高性能體現在哪方面
  1. 線程模型 :採用異步非阻塞的 I/O 類庫,基於 Reactor 模式實現,解決了傳統同步阻塞 I/O 模式下服務端無法平滑處理客戶端線性增長的問題。
  2. 堆外內存 :TCP 接收和發送緩衝區採用直接內存代替堆內存,避免了內存複製,提升了 I/O 讀取和寫入性能。
  3. 內存池設計 :支持通過內存池的方式循環利用 ByteBuf,避免了頻繁創建和銷燬 ByteBuf 帶來的性能消耗。
  4. 參數配置 :可配置的 I/O 線程數目和 TCP 參數等,爲不同用戶提供定製化的調優參數,滿足不同的性能場景。
  5. 隊列優化 :採用環形數組緩衝區,實現無鎖化併發編程,代替傳統的線程安全容器或鎖。
  6. 併發能力 :合理使用線程安全容器、原子類等,提升系統的併發能力。
  7. 降低鎖競爭 :關鍵資源的使用採用單線程串行化的方式,避免多線程併發訪問帶來的鎖競爭和額外的 CPU 資源消耗問題。
  8. 內存泄露檢測 :通過引用計數器及時地釋放不再被引用的對象,細粒度的內存管理降低了 GC 的頻率,減少頻繁 GC 帶來的時延增大和 CPU 損耗。
7. Netty的高可靠體現在哪幾方面
  1. 鏈路有效性檢測:由於長連接不需要每次發送消息都創建鏈路,也不需要在消息完成交互時關閉鏈路,因此相對於短連接性能更高。
  2. 內存保護機制,Netty 提供多種機制對內存進行保護。通過對象引用計數器對 ByteBuf 進行細粒度的內存申請和釋放,對非法的對象引用進行檢測和保護。可設置的內存容量上限,包括 ByteBuf、線程池線程數等,避免異常請求耗光內存。
  3. 優雅停機:優雅停機功能指的是當系統推出時,JVM 通過註冊的 Shutdown Hook 攔截到退出信號量,然後執行推出操作,釋放相關模塊的資源佔用,將緩衝區的消息處理完成或清空,將待刷新的數據持久化到磁盤和數據庫中,等到資源回收和緩衝區消息處理完成之後,再退出。
8. Netty 的可擴展如何體現
  • 提供大量系統參數 :供用戶按需設置,增強系統的場景定製性。
  • 提供大量的工廠類 :通過重載這些工廠類,可以按需創建出用戶需要的對象。
  • 基於接口的開發 :關鍵的類庫都提供了接口或抽象類,便於用戶自定義實現。
  • 責任鏈模式 :ChannelPipeline 基於責任鏈模式開發,便於業務邏輯的攔截、定製和擴展。
9. Netty 的核心組件介紹下
  • Bootstrap & ServerBootstrap
  • Channel
  • ChannelFuture
  • EventLoop & EventLoopGroup
  • ChannelHandler
  • ChannelPipeline
10. 什麼是 Reactor 模型

反應器設計模式是一個事件處理模式,用於處理一個或多個輸入併發地傳遞給服務處理程序的服務請求。然後,服務處理程序對傳入請求進行多路複用,並將它們同步分派給相關的請求處理程序。

可以參考這篇文章:Reactor模型

11. TCP 粘包 / 拆包的產生原因,應該這麼解決
  • TCP 是以流的方式來處理數據,所以會導致粘包 / 拆包。
    • 拆包:一個完整的包可能會被 TCP 拆分成多個包進行發送。
    • 粘包:也可能把小的封裝成一個大的數據包發送。
  • Netty中提供了多個 Decoder 解析類 用於解決上述問題:
    • FixedLengthFrameDecoder 、LengthFieldBasedFrameDecoder ,固定長度是消息頭指定消息長度的一種形式,進行粘包拆包處理的。
    • LineBasedFrameDecoder 、DelimiterBasedFrameDecoder ,換行是於指定消息邊界方式的一種形式,進行消息粘包拆包處理的。
12. 瞭解哪幾種序列化協議
  • 序列化
  • 反序列化
13. Netty怎樣實現零拷貝
  • Netty 的接收和發送 ByteBuffer 採用堆外直接內存 Direct Buffer
    • 使用堆外直接內存進行 Socket 讀寫,不需要進行字節緩衝區的二次拷貝;使用堆內內存會多了一次內存拷貝,JVM 會將堆內存 Buffer 拷貝一份到直接內存中,然後才寫入 Socket 中。Netty 創建的 ByteBuffer 類型,由 ChannelConfig 配置。而 ChannelConfig 配置的 ByteBufAllocator 默認創建 Direct Buffer 類型。
  • CompositeByteBuf 類,可以將多個 ByteBuf 合併爲一個邏輯上的 ByteBuf ,避免了傳統通過內存拷貝的方式將幾個小 Buffer 合併成一個大的 Buffer 。
  • 通過 FileRegion 包裝的 FileChannel 。
  • 通過 wrap 方法, 我們可以將 byte[] 數組、ByteBuf、ByteBuffer 等包裝成一個 Netty ByteBuf 對象, 進而避免了拷貝操作。
14. 原生的NIO存在Epoll Bug有什麼BUG、Netty 是怎麼解決的
  • Java NIO Epoll 會導致 Selector 空輪詢,最終導致 CPU 100% 。
  • Netty對Selector的select 操作週期進行統計,每完成一次空的 select 操作進行一次計數,若在某個週期內連續發生 N 次空輪詢,則判斷觸發了 Epoll 死循環 Bug 。
15. Netty 空閒檢測
  • IdleStateHandler ,用於檢測連接的讀寫是否處於空閒狀態。如果是,則會觸發 IdleStateEvent 。
16. Netty如何實現重連
  • 客戶端,通過 IdleStateHandler 實現定時檢測是否空閒
    • 如果空閒,則向服務端發起心跳*
    • 如果多次心跳失敗,則關閉和服務端的連接,然後重新發起連接
  • 服務端,通過 IdleStateHandler 實現定時檢測客戶端是否空閒
    • 如果檢測到空閒,則關閉客戶端
    • 如果接收到客戶端的心跳請求,要反饋一個心跳響應給客戶端。
17. Netty自己實現的ByteBuf有什麼優點
  1. 它可以被用戶自定義的緩衝區類型擴展
  2. 通過內置的符合緩衝區類型實現了透明的零拷貝
  3. 讀和寫使用了不同的索引
  4. 支持方法的鏈式調用
  5. 支持池化
18. Netty爲什麼要實現內存管理
  • 頻繁分配、釋放 buffer 時減少了 GC 壓力。
  • 在初始化新 buffer 時減少內存帶寬消耗( 初始化時不可避免的要給buffer數組賦初始值 )。
  • 及時的釋放 direct buffer 。
19. BIO 是什麼?

BIO ,全稱 Block-IO ,是一種阻塞 + 同步的通信模式。一種比較傳統的通信方式,模式簡單,使用方便。但併發處理能力低,通信耗時,依賴網速。
原理:服務器通過一個 Acceptor 線程,負責監聽客戶端請求和爲每個客戶端創建一個新的線程進行鏈路處理。典型的一請求一應答模式。若客戶端數量增多,頻繁地創建和銷燬線程會給服務器打開很大的壓力。後改良爲用線程池的方式代替新增線程,被稱爲僞異步 IO 。

20. NIO 是什麼?

NIO ,全稱 New IO ,也叫 Non-Block IO ,是一種非阻塞 + 同步的通信模式。Java NIO( New IO 或者 Non Blocking IO ) ,從 Java 1.4 版本開始引入的非阻塞 IO ,用於替換標準( 有些文章也稱爲傳統,或者 Blocking IO 。下文統稱爲 BIO ) Java IO API 的 IO API 。
NIO 相對於 BIO 來說一大進步。客戶端和服務器之間通過 Channel 通信。NIO 可以在 Channel 進行讀寫操作。這些 Channel 都會被註冊在 Selector 多路複用器上。Selector 通過一個線程不停的輪詢這些 Channel 。找出已經準備就緒的 Channel 執行 IO 操作。

21. AIO 是什麼?

AIO ,全稱 Asynchronous IO ,也叫 NIO2 ,是一種非阻塞 + 異步的通信模式。在 NIO 的基礎上,引入了新的異步通道的概念,並提供了異步文件通道和異步套接字通道的實現。AIO 並沒有採用 NIO 的多路複用器,而是使用異步通道的概念。其 read,write 方法的返回類型,都是 Future 對象。而 Future 模型是異步的,其核心思想是:去主函數等待時間。

22. BIO、NIO 有什麼區別?
  • 線程模型不同
    • BIO:一個連接一個線程,客戶端有連接請求時服務器端就需要啓動一個線程進行處理。所以,線程開銷大。可改良爲用線程池的方式代替新創建線程,被稱爲僞異步 IO 。
    • NIO:一個請求一個線程,但客戶端發送的連接請求都會註冊到多路複用器上,多路複用器輪詢到連接有新的 I/O 請求時,才啓動一個線程進行處理。可改良爲一個線程處理多個請求,基於 多 Reactor 模型。
  • BIO 是面向流( Stream )的,而 NIO 是面向緩衝區( Buffer )的。
  • BIO 的各種操作是阻塞的,而 NIO 的各種操作是非阻塞的。
  • BIO 的 Socket 是單向的,而 NIO 的 Channel 是雙向的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章