第 1 章 Netty 介紹和應(yīng)用場(chǎng)景
1.2 Netty 的介紹
- Netty 是由 JBOSS 提供的一個(gè) Java 開源框架,現(xiàn)為 Github 上的獨(dú)立項(xiàng)目。
- Netty 是一個(gè)異步的、基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用框架,用以快速開發(fā)高性能、高可靠性的網(wǎng)絡(luò) IO 程序。

image.png
Netty 主要針對(duì)在 TCP 協(xié)議下,面向 Clients 端的高并發(fā)應(yīng)用,或者 Peer-to-Peer 場(chǎng)景下的大量數(shù)據(jù)持續(xù)傳輸?shù)?應(yīng)用。
-
Netty 本質(zhì)是一個(gè) NIO 框架,適用于服務(wù)器通訊相關(guān)的多種應(yīng)用場(chǎng)景
image.png 要透徹理解 Netty , 需要先學(xué)習(xí) NIO , 這樣我們才能閱讀 Netty 的源碼。
1.3 Netty 的應(yīng)用場(chǎng)景
1.3.1互聯(lián)網(wǎng)行業(yè)
- 互聯(lián)網(wǎng)行業(yè):在分布式系統(tǒng)中,各個(gè)節(jié)點(diǎn)之間需要遠(yuǎn)程服務(wù)調(diào)用,高性能的 RPC 框架必不可少,Netty 作為 異步高性能的通信框架,往往作為基礎(chǔ)通信組件被這些 RPC 框架使用。
- 典型的應(yīng)用有:阿里分布式服務(wù)框架 Dubbo 的 RPC 框架使用 Dubbo 協(xié)議進(jìn)行節(jié)點(diǎn)間通信,Dubbo 協(xié)議默 認(rèn)使用 Netty 作為基礎(chǔ)通信組件,用于實(shí)現(xiàn)各進(jìn)程節(jié)點(diǎn)之間的內(nèi)部通信
1.3.2游戲行業(yè) - 無(wú)論是手游服務(wù)端還是大型的網(wǎng)絡(luò)游戲,Java 語(yǔ)言得到了越來(lái)越廣泛的應(yīng)用
- Netty 作為高性能的基礎(chǔ)通信組件,提供了 TCP/UDP 和 HTTP 協(xié)議棧,方便定制和開發(fā)私有協(xié)議棧,賬號(hào)登 錄服務(wù)器
- 地圖服務(wù)器之間可以方便的通過(guò) Netty 進(jìn)行高性能的通信
1.3.3大數(shù)據(jù)領(lǐng)域 - 經(jīng)典的 Hadoop 的高性能通信和序列化組件 Avro 的 RPC 框架,默認(rèn)采用 Netty 進(jìn)行跨界點(diǎn)通信
- 它的 Netty Service 基于 Netty 框架二次封裝實(shí)現(xiàn)。
第 5 章 Netty 高性能架構(gòu)設(shè)計(jì)
5.1 線程模型基本介紹
- 不同的線程模式,對(duì)程序的性能有很大影響,為了搞清 Netty 線程模式,我們來(lái)系統(tǒng)的講解下 各個(gè)線程模式, 最后看看 Netty 線程模型有什么優(yōu)越性。
- 目前存在的線程模型有: 傳統(tǒng)阻塞 I/O 服務(wù)模型 Reactor 模式
- 根據(jù) Reactor 的數(shù)量和處理資源池線程的數(shù)量不同,
有 3 種典型的實(shí)現(xiàn)
單 Reactor 單線程;
單 Reactor 多線程;
主從 Reactor 多線程 - Netty 線程模式(Netty 主要基于主從 Reactor 多線程模型做了一定的改進(jìn),其中主從 Reactor 多線程模型有多 個(gè) Reactor)
5.2 傳統(tǒng)阻塞 I/O 服務(wù)模型
5.2.1工作原理圖
- 黃色的框表示對(duì)象, 藍(lán)色的框表示線程
- 白色的框表示方法(API)
5.2.2模型特點(diǎn)
- 采用阻塞 IO 模式獲取輸入的數(shù)據(jù)
- 每個(gè)連接都需要獨(dú)立的線程完成數(shù)據(jù)的輸入,業(yè)務(wù)處理, 數(shù)據(jù)返回
5.2.3問(wèn)題分析
- 當(dāng)并發(fā)數(shù)很大,就會(huì)創(chuàng)建大量的線程,占用很大系統(tǒng)資源
-
連接創(chuàng)建后,如果當(dāng)前線程暫時(shí)沒有數(shù)據(jù)可讀,該線程 會(huì)阻塞在 read 操作,造成線程資源浪費(fèi).
image.png
5.3 Reactor 模式
5.3.1針對(duì)傳統(tǒng)阻塞 I/O 服務(wù)模型的 2 個(gè)缺點(diǎn),解決方案:
- 基于 I/O 復(fù)用模型:多個(gè)連接共用一個(gè)阻塞對(duì)象,應(yīng)用程序只需要在一個(gè)阻塞對(duì)象等待,無(wú)需阻塞等待所有連 接。當(dāng)某個(gè)連接有新的數(shù)據(jù)可以處理時(shí),操作系統(tǒng)通知應(yīng)用程序,線程從阻塞狀態(tài)返回,開始進(jìn)行業(yè)務(wù)處理
Reactor 對(duì)應(yīng)的叫法: 1. 反應(yīng)器模式 2. 分發(fā)者模式(Dispatcher) 3. 通知者模式(notifier) -
基于線程池復(fù)用線程資源:不必再為每個(gè)連接創(chuàng)建線程,將連接完成后的業(yè)務(wù)處理任務(wù)分配給線程進(jìn)行處理, 一個(gè)線程可以處理多個(gè)連接的業(yè)務(wù)。
image.png
5.3.2I/O 復(fù)用結(jié)合線程池,就是 Reactor 模式基本設(shè)計(jì)思想,如圖

image.png
? 對(duì)上圖說(shuō)明:
- Reactor 模式通過(guò)一個(gè)或多個(gè)輸入同時(shí)傳遞給服務(wù)處理器的模式(基于事件驅(qū)動(dòng)) 。
- 服務(wù)器端程序處理傳入的多個(gè)請(qǐng)求,并將它們同步分派到相應(yīng)的處理線程, 因此 Reactor 模式也叫 Dispatcher 模式 。
- Reactor 模式使用 IO 復(fù)用監(jiān)聽事件, 收到事件后,分發(fā)給某個(gè)線程(進(jìn)程), 這點(diǎn)就是網(wǎng)絡(luò)服務(wù)器高并發(fā)處理關(guān)鍵。
5.3.3Reactor 模式中 核心組成:
- Reactor:Reactor 在一個(gè)單獨(dú)的線程中運(yùn)行,負(fù)責(zé)監(jiān)聽和分發(fā)事件,分發(fā)給適當(dāng)?shù)奶幚沓绦騺?lái)對(duì) IO 事件做出 反應(yīng)。 它就像公司的電話接線員,它接聽來(lái)自客戶的電話并將線路轉(zhuǎn)移到適當(dāng)?shù)穆?lián)系人;
- Handlers:處理程序執(zhí)行 I/O 事件要完成的實(shí)際事件,類似于客戶想要與之交談的公司中的實(shí)際官員。Reactor 通過(guò)調(diào)度適當(dāng)?shù)奶幚沓绦騺?lái)響應(yīng) I/O 事件,處理程序執(zhí)行非阻塞操作。
5.3.4Reactor 模式分類:
根據(jù) Reactor 的數(shù)量和處理資源池線程的數(shù)量不同,有 3 種典型的實(shí)現(xiàn)
- 單 Reactor 單線程
- 單 Reactor 多線程
- 主從 Reactor 多線程
5.4 單 Reactor 單線程
原理圖,并使用 NIO 群聊系統(tǒng)驗(yàn)證

image.png
5.4.1方案說(shuō)明:
- Select 是前面 I/O 復(fù)用模型介紹的標(biāo)準(zhǔn)網(wǎng)絡(luò)編程 API,可以實(shí)現(xiàn)應(yīng)用程序通過(guò)一個(gè)阻塞對(duì)象監(jiān)聽多路連接請(qǐng)求
- Reactor 對(duì)象通過(guò) Select 監(jiān)控客戶端請(qǐng)求事件,收到事件后通過(guò) Dispatch 進(jìn)行分發(fā)
- 如果是建立連接請(qǐng)求事件,則由 Acceptor 通過(guò) Accept 處理連接請(qǐng)求,然后創(chuàng)建一個(gè) Handler 對(duì)象處理連接 完成后的后續(xù)業(yè)務(wù)處理
- 如果不是建立連接事件,則 Reactor 會(huì)分發(fā)調(diào)用連接對(duì)應(yīng)的 Handler 來(lái)響應(yīng)
- Handler 會(huì)完成 Read→業(yè)務(wù)處理→Send 的完整業(yè)務(wù)流程
結(jié)合實(shí)例:服務(wù)器端用一個(gè)線程通過(guò)多路復(fù)用搞定所有的 IO 操作(包括連接,讀、寫等),編碼簡(jiǎn)單,清晰明了, 但是如果客戶端連接數(shù)量較多,將無(wú)法支撐,前面的 NIO 案例就屬于這種模型。
5.4.2方案優(yōu)缺點(diǎn)分析:
- 優(yōu)點(diǎn):模型簡(jiǎn)單,沒有多線程、進(jìn)程通信、競(jìng)爭(zhēng)的問(wèn)題,全部都在一個(gè)線程中完成
- 缺點(diǎn):性能問(wèn)題,只有一個(gè)線程,無(wú)法完全發(fā)揮多核 CPU 的性能。Handler 在處理某個(gè)連接上的業(yè)務(wù)時(shí),整 個(gè)進(jìn)程無(wú)法處理其他連接事件,很容易導(dǎo)致性能瓶頸
- 缺點(diǎn):可靠性問(wèn)題,線程意外終止,或者進(jìn)入死循環(huán),會(huì)導(dǎo)致整個(gè)系統(tǒng)通信模塊不可用,不能接收和處理外部 消息,造成節(jié)點(diǎn)故障
- 使用場(chǎng)景:客戶端的數(shù)量有限,業(yè)務(wù)處理非??焖?,比如 Redis 在業(yè)務(wù)處理的時(shí)間復(fù)雜度 O(1) 的情況
5.5 單 Reactor 多線程
5.5.1原理圖

image.png
5.5.2對(duì)上圖的小結(jié)
- Reactor 對(duì)象通過(guò) select 監(jiān)控客戶端請(qǐng)求 事件, 收到事件后,通過(guò) dispatch 進(jìn)行分發(fā)
- 如果建立連接請(qǐng)求, 則右 Acceptor 通過(guò) accept 處理連接請(qǐng)求, 然后創(chuàng)建一個(gè) Handler 對(duì)象處理完成連接后的各種事件
- 如果不是連接請(qǐng)求,則由 reactor 分發(fā)調(diào)用連接對(duì)應(yīng)的 handler 來(lái)處理
- handler 只負(fù)責(zé)響應(yīng)事件,不做具體的業(yè)務(wù)處理, 通過(guò) read 讀取數(shù)據(jù)后,會(huì)分發(fā)給后面的 worker 線程池的某個(gè) 線程處理業(yè)務(wù)
- worker 線程池會(huì)分配獨(dú)立線程完成真正的業(yè)務(wù),并將結(jié)果返回給 handler
- handler 收到響應(yīng)后,通過(guò) send 將結(jié)果返回給 client
5.5.3方案優(yōu)缺點(diǎn)分析:
- 優(yōu)點(diǎn):可以充分的利用多核 cpu 的處理能力
- 缺點(diǎn):多線程數(shù)據(jù)共享和訪問(wèn)比較復(fù)雜, reactor 處理所有的事件的監(jiān)聽和響應(yīng),在單線程運(yùn)行, 在高并發(fā)場(chǎng) 景容易出現(xiàn)性能瓶頸.
5.6 主從 Reactor 多線程
5.6.1工作原理圖
針對(duì)單 Reactor 多線程模型中,Reactor 在單線程中運(yùn)行,高并發(fā)場(chǎng)景下容易成為性能瓶頸,可以讓 Reactor 在 多線程中運(yùn)行

image.png
5.6.2上圖的方案說(shuō)明
- Reactor 主線程 MainReactor 對(duì)象通過(guò) select 監(jiān)聽連接事件, 收到事件后,通過(guò) Acceptor 處理連接事件
- 當(dāng) Acceptor 處理連接事件后,MainReactor 將連接分配給 SubReactor
- subreactor 將連接加入到連接隊(duì)列進(jìn)行監(jiān)聽,并創(chuàng)建 handler 進(jìn)行各種事件處理
- 當(dāng)有新事件發(fā)生時(shí), subreactor 就會(huì)調(diào)用對(duì)應(yīng)的 handler 處理
- handler 通過(guò) read 讀取數(shù)據(jù),分發(fā)給后面的 worker 線程處理
- worker 線程池分配獨(dú)立的 worker 線程進(jìn)行業(yè)務(wù)處理,并返回結(jié)果
- handler 收到響應(yīng)的結(jié)果后,再通過(guò) send 將結(jié)果返回給 client
- Reactor 主線程可以對(duì)應(yīng)多個(gè) Reactor 子線程, 即 MainRecator 可以關(guān)聯(lián)多個(gè) SubReactor
5.6.3Scalable IO in Java 對(duì) Multiple Reactors 的原理圖解:

image.png
5.6.4方案優(yōu)缺點(diǎn)說(shuō)明:
- 優(yōu)點(diǎn):父線程與子線程的數(shù)據(jù)交互簡(jiǎn)單職責(zé)明確,父線程只需要接收新連接,子線程完成后續(xù)的業(yè)務(wù)處理。
- 優(yōu)點(diǎn):父線程與子線程的數(shù)據(jù)交互簡(jiǎn)單,Reactor 主線程只需要把新連接傳給子線程,子線程無(wú)需返回?cái)?shù)據(jù)。
- 缺點(diǎn):編程復(fù)雜度較高
- 結(jié)合實(shí)例:這種模型在許多項(xiàng)目中廣泛使用,包括 Nginx 主從 Reactor 多進(jìn)程模型,Memcached 主從多線程, Netty 主從多線程模型的支持
5.7 Reactor 模式小結(jié)
5.7.13 種模式用生活案例來(lái)理解
- 單 Reactor 單線程,前臺(tái)接待員和服務(wù)員是同一個(gè)人,全程為顧客服
- 單 Reactor 多線程,1 個(gè)前臺(tái)接待員,多個(gè)服務(wù)員,接待員只負(fù)責(zé)接待
- 主從 Reactor 多線程,多個(gè)前臺(tái)接待員,多個(gè)服務(wù)生
5.7.2 Reactor 模式具有如下的優(yōu)點(diǎn):
- 響應(yīng)快,不必為單個(gè)同步時(shí)間所阻塞,雖然 Reactor 本身依然是同步的
- 可以最大程度的避免復(fù)雜的多線程及同步問(wèn)題,并且避免了多線程/進(jìn)程的切換開銷
- 擴(kuò)展性好,可以方便的通過(guò)增加 Reactor 實(shí)例個(gè)數(shù)來(lái)充分利用 CPU 資源
- 復(fù)用性好,Reactor 模型本身與具體事件處理邏輯無(wú)關(guān),具有很高的復(fù)用性


