騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

1.介紹

Netty是由JBOSS提供的一個java開源框架。

Netty是一個高性能、異步事件驅動的NIO框架,它提供了對TCP、UDP和文件傳輸的支持。作爲當前最流行的NIO框架,Netty在互聯網領域、大數據分佈式計算領域、遊戲行業、通信行業等獲得了廣泛的應用,一些業界著名的開源組件也基於Netty的NIO框架構建

關於Netty,給大家構建一張思維導圖

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

2.Netty的特點

  • 高併發

Netty是一款基於NIO(Nonblocking I/O,非阻塞IO)開發的網絡通信框架,對比於BIO(Blocking I/O,阻塞IO),他的併發性能得到了很大提高 。

  • 傳輸快

Netty的傳輸快其實也是依賴了NIO的一個特性——零拷貝。

  • 封裝好

Netty封裝了NIO操作的很多細節,提供易於使用的API。

爲什麼選擇Netty

JDK 原生也有一套網絡應用程序 API,但是存在一系列問題,主要如下:

1)NIO 的類庫和 API 繁雜,使用麻煩:你需要熟練掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等。

2)需要具備其他的額外技能做鋪墊:例如熟悉 Java 多線程編程,因爲 NIO 編程涉及到 Reactor 模式,你必須對多線程和網路編程非常熟悉,才能編寫出高質量的 NIO 程序。

3)可靠性能力不齊,開發工作量和難度都非常大:例如客戶端面臨斷連重連、網絡閃斷、半包讀寫、失敗緩存、網絡擁塞和異常碼流的處理等等。NIO 編程的特點是功能開發相對容易,但是可靠性能力補齊工作量和難度都非常大。

4)JDK NIO 的 Bug:例如臭名昭著的 Epoll Bug,它會導致 Selector 空輪詢,最終導致 CPU 100%。官方聲稱在 JDK 1.6 版本的 update 18 修復了該問題,但是直到 JDK 1.7 版本該問題仍舊存在,只不過該 Bug 發生概率降低了一些而已,它並沒有被根本解決。

Netty框架的優勢

  • API使用簡單,開發門檻低;
  • 功能強大,預置了多種編解碼功能,支持多種主流協議;
  • 定製能力強,可以通過ChannelHandler對通信框架進行靈活地擴展;
  • 性能高,通過與其他業界主流的NIO框架對比,Netty的綜合性能最優;
  • 成熟、穩定,Netty修復了已經發現的所有JDK NIO BUG,業務開發人員不需要再爲NIO的BUG而煩惱;
  • 社區活躍,版本迭代週期短,發現的BUG可以被及時修復,同時,更多的新功能會加入;
  • 經歷了大規模的商業應用考驗,質量得到驗證。在互聯網、大數據、網絡遊戲、企業應用、電信軟件等衆多行業得到成功商用,證明了它已經完全能夠滿足不同行業的商業應用了。

Netty的架構設計

總體結構

Netty 採用了比較典型的三層網絡架構進行設計,邏輯架構圖如下所示:

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

1)傳輸服務:支持 BIO 和 NIO;

2)容器集成:支持 OSGI、JBossMC、Spring、Guice 容器;

3)協議支持:HTTP、Protobuf、二進制、文本、WebSocket 等一系列常見協議都支持。還支持通過實行編碼解碼邏輯來實現自定義協議;

4)Core 核心:可擴展事件模型、通用通信 API、支持零拷貝的 ByteBuf 緩衝對象。

Netty的高性能設計

1.高性能的三大要素

1) 傳輸:用什麼樣的通道將數據發送給對方,BIO、NIO或者AIO,IO模型在很大程度上決定了框架的性能。

2) 協議:採用什麼樣的通信協議,HTTP或者內部私有協議。協議的選擇不同,性能模型也不同。相比於公有協議,內部私有協議的性能通常可以被設計的更優。

3) 線程:數據報如何讀取?讀取之後的編解碼在哪個線程進行,編解碼後的消息如何派發,Reactor線程模型的不同,對性能的影響也非常大。

2.IO模型

Netty的I/O模型基於非阻塞I/O實現,底層依賴的是JDK NIO框架的Selector。

3.Reactor線程模型

1)Reactor單線程模型

2)Reactor多線程模型

3)主從Reactor多線程模型

Netty的線程模型基於Reactor,Reactor的核心在於事件分發,它有三種經典的線程模型(單線程模型,多線程>模型,主從多線程模型)

 

事件循環機制(EventLoop)

而提到上面的性能中的線性模型,就不得不提到另外一個點,相信有朋友已經猜到了,對,就是事件循環機制

Netty線程模型中一個非常重要的概念: 事件循環機制(EventLoop)這個概念在JS上體現的也非常淋漓盡致,下面在開始介紹netty的線程模型之前,允許我簡單的介紹下事件循環機制在JS中的體現

JS的語言性質: 單線程非阻塞,單線程意味着,js代碼在執行的任何時候,都只有一個主線程來處理所有的任務>。非阻塞則意味着,在進行異步IO任務時不會阻塞主線程,主線程會掛起這個任務,等待異步任務完成再執行對應>的回調。

那麼JS是如何實現單線程非阻塞的呢?JS引擎遇到一個異步事件後並不會一直等待其返回結果,而是會將此事件掛起(例如交給瀏覽器去執行請求),主線程會繼續執行方法棧中的其他任務。之後當異步任務返回結果後,(可能是瀏覽器?)會將回調函數加入到事件隊列(Task Queue)中,那麼什麼時候會從事件隊列中取出回調函數執行呢?當前執行棧中的所有任務都執行完畢,主線程處於閒置狀態時會去查找事件隊列是否有任務待執行,如果有則>將回調函數加入到主線程的方法執行棧中執行,如此反覆,我們就把這個循環過程稱爲事件循環機制(EventLoop)。

 


不知道介紹了JS的事件循環機制,大家有沒有對Event Loop有了一個初步的認識,下面我將會着重介紹我們主角Netty的線程模型及其與Event Loop的聯繫

Netty線程模型

Netty的線程模型基於Reactor,Reactor的核心在於事件分發,它有三種經典的線程模型(單線程模型,多線程>模型,主從多線程模型),下面我們會結合Netty的EventLoop機制一一介紹

Reactor單線程模型

單線程模型全局只有一個線程在工作,也就意味着請求的接收,分發,IO讀取寫入等操作都在一個線程中完成,該>模型算得上是最經典的線程模型了,例如redis也是採用的此種單線程模型了。

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

可以看到上圖中,我們把一個Reactor線程可以認爲是一個EventLoop IO線程,一個事件循環機制。

由於其線程中的IO讀寫都是基於NIO,理論上所有的IO讀寫操作都不會阻塞EventLoop線程。所以即使是改善線程>模型,也是足以應付絕大多數的場景。

那麼爲什麼又會延伸出Reactor多線程模型呢?當應用併發量非常大時,例如一個Reactor NIO 線程需要同時處理成百上千的連接時,雖然IO讀寫是非阻塞的,>但是消息的編碼解碼都是需要同步阻塞的,這就導致NIO線程處理速度變慢,最終導致消息積壓,出現性能瓶頸。

基於以上原因也就演進出了第二種模型Reactor多線程模型

Reactor多線程模型

Reactor多線程模型與Reactor單線程模型最大的區別就是,有一組Reactor NIO線程(也就是一組 EventLoop)來處理IO操作

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

通過上圖,可以比較清晰的看到,IO的讀寫操作都由一個Reactor NIO線程池(對應到EventLoop也就是EventLoopGroup)來完成的,而請求的監聽和Accept則是由另一個單獨的Reactor線程來完成。注意Reactor NIO線程池中的每一個線程都是處理N條鏈路,但是一個鏈路只能有一個線程來處理多線程的Reactor模型可以滿足絕大部分的應用場景,通常情況下,我們使用Netty使用這種線程模型就OK(創建>兩個NioEventLoopGroup,bossGroup大小爲1,workGroup大小爲CPU*2)。但是有可能會存在某些極少數的情況,一個Reactor線程處理請求的Accept可能會產生性能瓶頸,例如上百萬的併發連接請求。這時候我們可能就需要採用第三種模型Reactor主從多線程模型

Reactor主從多線程模型

Reactor主從多線程模型和Reactor多線程模型的區別在於原本是一個Reactor線程處理請求的Accept,變成了一組Reactor線程。

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

對於Reactor主從多線程模型,其實大多數情況下我們並不需要。即使我們給BossGroup指定了多個線程,最終也>只會選擇其中的一個作爲Accepor的NIO線程,除非在服務端綁定了多個端口的情況下才會啓用BossGroup的多個線

Netty的核心組件

Netty應用中必不可少的組件:

  • Bootstrap or ServerBootstrap
  • EventLoop
  • EventLoopGroup
  • ChannelPipeline
  • Channel
  • Future or ChannelFuture
  • ChannelInitializer
  • ChannelHandler

1.Bootstrap

一個Netty應用通常由一個Bootstrap開始,它主要作用是配置整個Netty程序,串聯起各個組件。

Handler,爲了支持各種協議和處理數據的方式,便誕生了Handler組件。Handler主要用來處理各種事件,這裏的事件很廣泛,比如可以是連接、數據接收、異常、數據轉換等。

2.ChannelInboundHandler

一個最常用的Handler。這個Handler的作用就是處理接收到數據時的事件,也就是說,我們的業務邏輯一般就是寫在這個Handler裏面的,ChannelInboundHandler就是用來處理我們的核心業務邏輯。

3.ChannelInitializer

當一個鏈接建立時,我們需要知道怎麼來接收或者發送數據,當然,我們有各種各樣的Handler實現來處理它,那麼ChannelInitializer便是用來配置這些Handler,它會提供一個ChannelPipeline,並把Handler加入到ChannelPipeline。

4.ChannelPipeline

一個Netty應用基於ChannelPipeline機制,這種機制需要依賴於EventLoop和EventLoopGroup,因爲它們三個都和事件或者事件處理相關。

EventLoops的目的是爲Channel處理IO操作,一個EventLoop可以爲多個Channel服務。

EventLoopGroup會包含多個EventLoop。

5.Channel

代表了一個Socket鏈接,或者其它和IO操作相關的組件,它和EventLoop一起用來參與IO處理。

6.Future

在Netty中所有的IO操作都是異步的,因此,你不能立刻得知消息是否被正確處理,但是我們可以過一會等它執行完成或者直接註冊一個監聽,具體的實現就是通過Future和ChannelFutures,他們可以註冊一個監聽,當操作執行成功或失敗時監聽會自動觸發。

總之,所有的操作都會返回一個ChannelFuture。

Netty的應用場景

1.互聯網行業

在分佈式系統中,各個節點之間需要遠程服務調用,高性能的RPC框架必不可少,Netty作爲異步高性能的通信框架,往往作爲基礎通信組件被這些RPC框架使用。

典型的應用有:阿里分佈式服務框架Dubbo的RPC框架使用Dubbo協議進行節點間通信,Dubbo協議默認使用Netty作爲基礎通信組件,用於實現各進程節點之間的內部通信。

除了 Dubbo 之外,淘寶的消息中間件 RocketMQ 的消息生產者和消息消費者之間,也採用 Netty 進行高性能、異步通信。

2.遊戲行業

無論是手遊服務端還是大型的網絡遊戲,Java語言得到了越來越廣泛的應用。Netty作爲高性能的基礎通信組件,它本身提供了TCP/UDP和HTTP協議棧。

非常方便定製和開發私有協議棧,賬號登錄服務器,地圖服務器之間可以方便的通過Netty進行高性能的通信

3.大數據領域

經典的Hadoop的高性能通信和序列化組件Avro的RPC框架,默認採用Netty進行跨界點通信,它的Netty Service基於Netty框架二次封裝實現。

 


到這裏也洋洋灑灑寫了5000字了,對於netty,比較重要的兩個技術點:事件循環機制以及Reactor線程模型基本介紹完了,不知道大家看的怎麼樣呢?要是感覺有點印象但是還迷迷糊糊的,也沒關係,給大家分享一份資料,包括面試和學習文檔(注:面試題對應學習文檔,答案看不明白可以去學習文檔中參考)

由於篇幅限制這裏只能給大家把內容部分截取出來,因爲此書籍和麪試資料是爲內部資料,需要獲取完整電子版書籍的讀者朋友們可以關注本人,後臺私信:“Netty”免費領取。

基礎篇

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

入門篇

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

中級篇

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

高級篇

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

源碼解讀

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

行業應用

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

面試

面試題因爲每道題都附有答案,所以只截取部分的面試題和答案

騰訊T4整理Netty思維導圖。百萬級推送服務設計要點一文解決

 

 

好了,覺得這篇文章對你的學習有幫助的,歡迎點贊+關注,

關注公衆號:Java架構師聯盟,每日更新技術好文

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