目前存在的線程模型主要有:
●傳統(tǒng)阻塞I/O服務(wù)模型
●Reactor模式
傳統(tǒng)阻塞I/O服務(wù)模型
模型特點(diǎn):
●采用阻塞IO模式獲取輸入的數(shù)據(jù)
●每個(gè)鏈接都需要獨(dú)立的線程完成數(shù)據(jù)的輸入,業(yè)務(wù)處理当叭、數(shù)據(jù)返回。
存在的問題:
●當(dāng)并發(fā)數(shù)很大,就會(huì)創(chuàng)建大量的線程,占用很大系統(tǒng)資源灵再,所以它是沒辦法處理高并發(fā)的笼蛛。
●連接創(chuàng)建后,如果當(dāng)前線程暫時(shí)沒有數(shù)據(jù)可讀顾画,該線程會(huì)阻塞在read操作取劫,造成線程資源浪費(fèi)。
Reactor模式
Reactor 的叫法: 1. 反應(yīng)器模式 2. 分發(fā)者模式(Dispatcher) 3. 通知者模式(notifier)
針對(duì)傳統(tǒng)阻塞I/O服務(wù)模型的2個(gè)缺點(diǎn)研侣,解決方案如下:
●基于 I/O 復(fù)用模型:多個(gè)連接共用一個(gè)阻塞對(duì)象谱邪,應(yīng)用程序只需要在一個(gè)阻塞對(duì)象等待,無需阻塞等待所有連接庶诡。當(dāng)某個(gè)連接有新的數(shù)據(jù)可以處理時(shí)惦银,操作系統(tǒng)通知應(yīng)用程序,線程從阻塞狀態(tài)返回末誓,開始進(jìn)行業(yè)務(wù)處理扯俱。
●基于線程池復(fù)用線程資源:不必再為每個(gè)連接創(chuàng)建線程,將連接完成后的業(yè)務(wù)處理任務(wù)分配給線程進(jìn)行處理喇澡,一個(gè)線程可以處理多個(gè)連接的業(yè)務(wù)迅栅。
Reactor 總體設(shè)計(jì)理念
●Reactor模式,通過一個(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)鍵榨惰。
Reactor模式中的核心組成部分:
●Reactor:Reactor在一個(gè)單獨(dú)的線程中運(yùn)行拜英,負(fù)責(zé)監(jiān)聽和分發(fā)事件,分發(fā)給適當(dāng)?shù)奶幚沓绦騺韺?duì)IO事件作出反應(yīng)琅催。即上圖的ServiceHandler
●Handlers:處理程序執(zhí)行I/O事件要完成的實(shí)際事件居凶,類似于客戶想要與之交談的公司中的實(shí)際官員。Reactor通過調(diào)度適當(dāng)?shù)奶幚沓绦騺眄憫?yīng)I/O事件藤抡,處理程序執(zhí)行非阻塞操作侠碧。
單Reactor單線程
●Select 是前面 I/O 復(fù)用模型介紹的標(biāo)準(zhǔn)網(wǎng)絡(luò)編程 API,可以實(shí)現(xiàn)應(yīng)用程序通過一個(gè)阻塞對(duì)象監(jiān)聽多路連接請(qǐng)求
●Reactor 對(duì)象通過 Select 監(jiān)控客戶端請(qǐng)求事件缠黍,收到事件后通過 Dispatch 進(jìn)行分發(fā)
●如果是建立連接請(qǐng)求事件弄兜,則由 Acceptor 通過 Accept 處理連接請(qǐng)求,然后創(chuàng)建一個(gè) Handler 對(duì)象處理連接完成后的后續(xù)業(yè)務(wù)處理
●如果不是建立連接事件瓷式,則 Reactor 會(huì)分發(fā)調(diào)用連接對(duì)應(yīng)的 Handler 來響應(yīng)
●Handler 會(huì)完成 Read→業(yè)務(wù)處理→Send 的完整業(yè)務(wù)流程
優(yōu)點(diǎn):模型簡單替饿,沒有多線程、進(jìn)程通信贸典、競爭的問題视卢,全部都在一個(gè)線程中完成
缺點(diǎn):
●性能問題,只有一個(gè)線程廊驼,無法完全發(fā)揮多核 CPU 的性能据过。Handler 在處理某個(gè)連接上的業(yè)務(wù)時(shí)惋砂,整個(gè)進(jìn)程無法處理其他連接事件,很容易導(dǎo)致性能瓶頸
●可靠性問題绳锅,線程意外終止西饵,或者進(jìn)入死循環(huán),會(huì)導(dǎo)致整個(gè)系統(tǒng)通信模塊不可用榨呆,不能接收和處理外部消息罗标,造成節(jié)點(diǎn)故障
使用場景:客戶端的數(shù)量有限庸队,業(yè)務(wù)處理非郴撸快速,比如 Redis在業(yè)務(wù)處理的時(shí)間復(fù)雜度 O(1) 的情況
單Reactor多線程
●Reactor 對(duì)象通過select 監(jiān)控客戶端請(qǐng)求事件, 收到事件后彻消,通過dispatch進(jìn)行分發(fā)
●如果建立連接請(qǐng)求, 則右Acceptor 通過accept 處理連接請(qǐng)求, 然后創(chuàng)建一個(gè)Handler對(duì)象處理完成連接后的各種事件
●如果不是連接請(qǐng)求竿拆,則由reactor分發(fā)調(diào)用連接對(duì)應(yīng)的handler 來處理
handler 只負(fù)責(zé)響應(yīng)事件,不做具體的業(yè)務(wù)處理, 通過read 讀取數(shù)據(jù)后宾尚,會(huì)分發(fā)給后面的worker線程池的某個(gè)線程處理業(yè)務(wù)
●worker 線程池會(huì)分配獨(dú)立線程完成真正的業(yè)務(wù)丙笋,并將結(jié)果返回給handler
handler收到響應(yīng)后,通過send 將結(jié)果返回給client
優(yōu)點(diǎn):可以充分的利用多核cpu 的處理能力
缺點(diǎn):多線程數(shù)據(jù)共享和訪問比較復(fù)雜煌贴, reactor 處理所有的事件的監(jiān)聽和響應(yīng)御板,在單線程運(yùn)行, 在高并發(fā)場景容易出現(xiàn)性能瓶頸.
主從Reactor多線程
●Reactor主線程 MainReactor 對(duì)象就只注冊(cè)一個(gè)用于監(jiān)聽連接請(qǐng)求的ServerSocketChannel牛郑,通過select 監(jiān)聽連接事件, 收到事件后怠肋,通過Acceptor 處理連接事件
●當(dāng) Acceptor 處理連接事件后,MainReactor 通過accept獲取新的連接淹朋,并將連接注冊(cè)到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 通過read 讀取數(shù)據(jù),分發(fā)給后面的worker 線程處理
●worker 線程池分配獨(dú)立的worker 線程進(jìn)行業(yè)務(wù)處理础芍,并返回結(jié)果
●handler 收到響應(yīng)的結(jié)果后杈抢,再通過send 將結(jié)果返回給client
●Reactor 主線程當(dāng)然是可以對(duì)應(yīng)多個(gè)Reactor 子線程的,這也就解決了并發(fā)的問題
優(yōu)點(diǎn):
●父線程與子線程的數(shù)據(jù)交互簡單職責(zé)明確仑性,父線程只需要接收新連接惶楼,子線程完成后續(xù)的業(yè)務(wù)處理。
●父線程與子線程的數(shù)據(jù)交互簡單诊杆,Reactor 主線程只需要把新連接傳給子線程歼捐,子線程無需返回?cái)?shù)據(jù)
缺點(diǎn):編程復(fù)雜度較高
Netty就是基于此模型的