隨著互聯(lián)網(wǎng)的發(fā)展逻悠,面對(duì)海量用戶高并發(fā)業(yè)務(wù)唉工,傳統(tǒng)的阻塞式的服務(wù)端架構(gòu)模式已經(jīng)無(wú)能為力,由此止吁,本文旨在為大家提供有用的概覽以及網(wǎng)絡(luò)服務(wù)模型的比較,以揭開(kāi)設(shè)計(jì)和實(shí)現(xiàn)高性能網(wǎng)絡(luò)架構(gòu)的神秘面紗
1 服務(wù)端處理網(wǎng)絡(luò)請(qǐng)求
首先看看服務(wù)端處理網(wǎng)絡(luò)請(qǐng)求的典型過(guò)程:
可以看到燎悍,主要處理步驟包括:
- 1敬惦、獲取請(qǐng)求數(shù)據(jù)
客戶端與服務(wù)器建立連接發(fā)出請(qǐng)求,服務(wù)器接受請(qǐng)求(1-3) - 2间涵、構(gòu)建響應(yīng)
當(dāng)服務(wù)器接收完請(qǐng)求仁热,并在用戶空間處理客戶端的請(qǐng)求,直到構(gòu)建響應(yīng)完成(4) - 3勾哩、返回?cái)?shù)據(jù)
服務(wù)器將已構(gòu)建好的響應(yīng)再通過(guò)內(nèi)核空間的網(wǎng)絡(luò)I/O發(fā)還給客戶端(5-7)
設(shè)計(jì)服務(wù)端并發(fā)模型時(shí)抗蠢,主要有如下兩個(gè)關(guān)鍵點(diǎn):
- 服務(wù)器如何管理連接,獲取輸入數(shù)據(jù)
- 服務(wù)器如何處理請(qǐng)求
以上兩個(gè)關(guān)鍵點(diǎn)最終都與操作系統(tǒng)的I/O模型以及線程(進(jìn)程)模型相關(guān)思劳,下面詳細(xì)介紹這兩個(gè)模型
2 I/O模型
2.1 概念理論
介紹操作系統(tǒng)的I/O模型之前迅矛,先了解一下幾個(gè)概念:
- 阻塞調(diào)用與非阻塞調(diào)用
- 阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起潜叛。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回
- 非阻塞調(diào)用指在不能立刻得到結(jié)果之前秽褒,該調(diào)用不會(huì)阻塞當(dāng)前線程
兩者的最大區(qū)別在于被調(diào)用方在收到請(qǐng)求到返回結(jié)果之前的這段時(shí)間內(nèi)壶硅,調(diào)用方是否一直在等待。阻塞是指調(diào)用方一直在等待而且別的事情什么都不做销斟。非阻塞是指調(diào)用方先去忙別的事情
-
同步處理與異步處理
- 同步處理是指被調(diào)用方得到最終結(jié)果之后才返回給調(diào)用方
- 異步處理是指被調(diào)用方先返回應(yīng)答庐椒,然后再計(jì)算調(diào)用結(jié)果,計(jì)算完最終結(jié)果后再通知并返回給調(diào)用方
阻塞蚂踊、非阻塞和同步约谈、異步的區(qū)別
阻塞、非阻塞和同步犁钟、異步其實(shí)針對(duì)的對(duì)象是不一樣的:
阻塞棱诱、非阻塞的討論對(duì)象是調(diào)用者
同步、異步的討論對(duì)象是被調(diào)用者recvfrom函數(shù)
recvfrom函數(shù)(經(jīng)socket接收數(shù)據(jù))涝动,這里把它視為系統(tǒng)調(diào)用
一個(gè)輸入操作通常包括兩個(gè)不同的階段
- 等待數(shù)據(jù)準(zhǔn)備好
- 從內(nèi)核向進(jìn)程復(fù)制數(shù)據(jù)
對(duì)于一個(gè)套接字上的輸入操作迈勋,第一步通常涉及等待數(shù)據(jù)從網(wǎng)絡(luò)中到達(dá)。當(dāng)所等待分組到達(dá)時(shí)醋粟,它被復(fù)制到內(nèi)核中的某個(gè)緩沖區(qū)靡菇。第二步就是把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)
實(shí)際應(yīng)用程序在系統(tǒng)調(diào)用完成上面2步操作時(shí),調(diào)用方式的阻塞昔穴、非阻塞镰官,操作系統(tǒng)在處理應(yīng)用程序請(qǐng)求時(shí)處理方式的同步、異步處理的不同吗货,參考《UNIX網(wǎng)絡(luò)編程卷1》,可以分為5種I/O模型
2.2 阻塞式I/O模型(blocking I/O)
簡(jiǎn)介
在阻塞式I/O模型中狈网,應(yīng)用程序在從調(diào)用recvfrom開(kāi)始到它返回有數(shù)據(jù)報(bào)準(zhǔn)備好這段時(shí)間是阻塞的宙搬,recvfrom返回成功后,應(yīng)用進(jìn)程開(kāi)始處理數(shù)據(jù)報(bào)
比喻
一個(gè)人在釣魚(yú)拓哺,當(dāng)沒(méi)魚(yú)上鉤時(shí)勇垛,就坐在岸邊一直等
優(yōu)點(diǎn)
程序簡(jiǎn)單,在阻塞等待數(shù)據(jù)期間進(jìn)程/線程掛起士鸥,基本不會(huì)占用CPU資源
缺點(diǎn)
每個(gè)連接需要獨(dú)立的進(jìn)程/線程單獨(dú)處理闲孤,當(dāng)并發(fā)請(qǐng)求量大時(shí)為了維護(hù)程序,內(nèi)存烤礁、線程切換開(kāi)銷較大讼积,這種模型在實(shí)際生產(chǎn)中很少使用
2.3 非阻塞式I/O模型(non-blocking I/O)
簡(jiǎn)介
在非阻塞式I/O模型中,應(yīng)用程序把一個(gè)套接口設(shè)置為非阻塞就是告訴內(nèi)核脚仔,當(dāng)所請(qǐng)求的I/O操作無(wú)法完成時(shí)勤众,不要將進(jìn)程睡眠,而是返回一個(gè)錯(cuò)誤鲤脏,應(yīng)用程序基于I/O操作函數(shù)將不斷的輪詢數(shù)據(jù)是否已經(jīng)準(zhǔn)備好们颜,如果沒(méi)有準(zhǔn)備好吕朵,繼續(xù)輪詢,直到數(shù)據(jù)準(zhǔn)備好為止
比喻
邊釣魚(yú)邊玩手機(jī)窥突,隔會(huì)再看看有沒(méi)有魚(yú)上鉤努溃,有的話就迅速拉桿
優(yōu)點(diǎn)
不會(huì)阻塞在內(nèi)核的等待數(shù)據(jù)過(guò)程,每次發(fā)起的I/O請(qǐng)求可以立即返回阻问,不用阻塞等待茅坛,實(shí)時(shí)性較好
缺點(diǎn)輪詢將會(huì)不斷地詢問(wèn)內(nèi)核,這將占用大量的CPU時(shí)間则拷,系統(tǒng)資源利用率較低贡蓖,所以一般Web服務(wù)器不使用這種I/O模型
2.4 I/O復(fù)用模型(I/O multiplexing)
簡(jiǎn)介
在I/O復(fù)用模型中,會(huì)用到select或poll函數(shù)或epoll函數(shù)(Linux2.6以后的內(nèi)核開(kāi)始支持)煌茬,這兩個(gè)函數(shù)也會(huì)使進(jìn)程阻塞斥铺,但是和阻塞I/O所不同的的,這兩個(gè)函數(shù)可以同時(shí)阻塞多個(gè)I/O操作坛善,而且可以同時(shí)對(duì)多個(gè)讀操作晾蜘,多個(gè)寫(xiě)操作的I/O函數(shù)進(jìn)行檢測(cè),直到有數(shù)據(jù)可讀或可寫(xiě)時(shí)眠屎,才真正調(diào)用I/O操作函數(shù)
比喻
放了一堆魚(yú)竿剔交,在岸邊一直守著這堆魚(yú)竿,直到有魚(yú)上鉤
優(yōu)點(diǎn)
可以基于一個(gè)阻塞對(duì)象改衩,同時(shí)在多個(gè)描述符上等待就緒岖常,而不是使用多個(gè)線程(每個(gè)文件描述符一個(gè)線程),這樣可以大大節(jié)省系統(tǒng)資源
缺點(diǎn)
當(dāng)連接數(shù)較少時(shí)效率相比多線程+阻塞I/O模型效率較低葫督,可能延遲更大竭鞍,因?yàn)閱蝹€(gè)連接處理需要2次系統(tǒng)調(diào)用,占用時(shí)間會(huì)有增加
2.5 信號(hào)驅(qū)動(dòng)式I/O模型(signal-driven I/O)
簡(jiǎn)介
在信號(hào)驅(qū)動(dòng)式I/O模型中橄镜,應(yīng)用程序使用套接口進(jìn)行信號(hào)驅(qū)動(dòng)I/O偎快,并安裝一個(gè)信號(hào)處理函數(shù),進(jìn)程繼續(xù)運(yùn)行并不阻塞洽胶。當(dāng)數(shù)據(jù)準(zhǔn)備好時(shí)晒夹,進(jìn)程會(huì)收到一個(gè)SIGIO信號(hào),可以在信號(hào)處理函數(shù)中調(diào)用I/O操作函數(shù)處理數(shù)據(jù)
比喻
魚(yú)竿上系了個(gè)鈴鐺姊氓,當(dāng)鈴鐺響丐怯,就知道魚(yú)上鉤,然后可以專心玩手機(jī)
優(yōu)點(diǎn)
線程并沒(méi)有在等待數(shù)據(jù)時(shí)被阻塞他膳,可以提高資源的利用率
缺點(diǎn)
- 信號(hào)I/O在大量IO操作時(shí)可能會(huì)因?yàn)樾盘?hào)隊(duì)列溢出導(dǎo)致沒(méi)法通知
- 信號(hào)驅(qū)動(dòng)I/O盡管對(duì)于處理UDP套接字來(lái)說(shuō)有用响逢,即這種信號(hào)通知意味著到達(dá)一個(gè)數(shù)據(jù)報(bào),或者返回一個(gè)異步錯(cuò)誤棕孙。但是舔亭,對(duì)于TCP而言些膨,信號(hào)驅(qū)動(dòng)的I/O方式近乎無(wú)用,因?yàn)閷?dǎo)致這種通知的條件為數(shù)眾多钦铺,每一個(gè)來(lái)進(jìn)行判別會(huì)消耗很大資源订雾,與前幾種方式相比優(yōu)勢(shì)盡失
2.6 異步I/O模型(asynchronous I/O)
簡(jiǎn)介
由POSIX規(guī)范定義,應(yīng)用程序告知內(nèi)核啟動(dòng)某個(gè)操作矛洞,并讓內(nèi)核在整個(gè)操作(包括將數(shù)據(jù)從內(nèi)核拷貝到應(yīng)用程序的緩沖區(qū))完成后通知應(yīng)用程序洼哎。這種模型與信號(hào)驅(qū)動(dòng)模型的主要區(qū)別在于:信號(hào)驅(qū)動(dòng)I/O是由內(nèi)核通知應(yīng)用程序何時(shí)啟動(dòng)一個(gè)I/O操作,而異步I/O模型是由內(nèi)核通知應(yīng)用程序I/O操作何時(shí)完成
優(yōu)點(diǎn)
異步 I/O 能夠充分利用 DMA 特性沼本,讓 I/O 操作與計(jì)算重疊
缺點(diǎn)
要實(shí)現(xiàn)真正的異步 I/O噩峦,操作系統(tǒng)需要做大量的工作。目前 Windows 下通過(guò) IOCP 實(shí)現(xiàn)了真正的異步 I/O抽兆,而在 Linux 系統(tǒng)下识补,Linux2.6才引入,目前 AIO 并不完善辫红,因此在 Linux 下實(shí)現(xiàn)高并發(fā)網(wǎng)絡(luò)編程時(shí)都是以 IO復(fù)用模型模式為主
2.5 5種I/O模型總結(jié)
從上圖中我們可以看出凭涂,可以看出,越往后贴妻,阻塞越少切油,理論上效率也是最優(yōu)。其五種I/O模型中名惩,前四種屬于同步I/O澎胡,因?yàn)槠渲姓嬲腎/O操作(recvfrom)將阻塞進(jìn)程/線程,只有異步I/O模型才于POSIX定義的異步I/O相匹配
3 線程模型
介紹完服務(wù)器如何基于I/O模型管理連接绢片,獲取輸入數(shù)據(jù)滤馍,下面介紹基于進(jìn)程/線程模型,服務(wù)器如何處理請(qǐng)求
值得說(shuō)明的是底循,具體選擇線程還是進(jìn)程,更多是與平臺(tái)及編程語(yǔ)言相關(guān)槐瑞,例如C語(yǔ)言使用線程和進(jìn)程都可以(例如Nginx使用進(jìn)程熙涤,Memcached使用線程),Java語(yǔ)言一般使用線程(例如Netty)困檩,為了描述方便祠挫,下面都使用線程來(lái)進(jìn)進(jìn)行描述
3.1 傳統(tǒng)阻塞I/O服務(wù)模型
特點(diǎn)
- 采用阻塞式I/O模型獲取輸入數(shù)據(jù)
- 每個(gè)連接都需要獨(dú)立的線程完成數(shù)據(jù)輸入,業(yè)務(wù)處理悼沿,數(shù)據(jù)返回的完整操作
存在問(wèn)題
- 當(dāng)并發(fā)數(shù)較大時(shí)等舔,需要?jiǎng)?chuàng)建大量線程來(lái)處理連接,系統(tǒng)資源占用較大
- 連接建立后糟趾,如果當(dāng)前線程暫時(shí)沒(méi)有數(shù)據(jù)可讀慌植,則線程就阻塞在read操作上甚牲,造成線程資源浪費(fèi)
3.2 Reactor模式
針對(duì)傳統(tǒng)傳統(tǒng)阻塞I/O服務(wù)模型的2個(gè)缺點(diǎn),比較常見(jiàn)的有如下解決方案:
- 基于I/O復(fù)用模型蝶柿,多個(gè)連接共用一個(gè)阻塞對(duì)象丈钙,應(yīng)用程序只需要在一個(gè)阻塞對(duì)象上等待,無(wú)需阻塞等待所有連接交汤。當(dāng)某條連接有新的數(shù)據(jù)可以處理時(shí)雏赦,操作系統(tǒng)通知應(yīng)用程序,線程從阻塞狀態(tài)返回芙扎,開(kāi)始進(jìn)行業(yè)務(wù)處理
- 基于線程池復(fù)用線程資源星岗,不必再為每個(gè)連接創(chuàng)建線程,將連接完成后的業(yè)務(wù)處理任務(wù)分配給線程進(jìn)行處理戒洼,一個(gè)線程可以處理多個(gè)連接的業(yè)務(wù)
I/O復(fù)用結(jié)合線程池俏橘,這就是Reactor模式基本設(shè)計(jì)思想
Reactor模式,是指通過(guò)一個(gè)或多個(gè)輸入同時(shí)傳遞給服務(wù)處理器的服務(wù)請(qǐng)求的事件驅(qū)動(dòng)處理模式施逾。 服務(wù)端程序處理傳入多路請(qǐng)求敷矫,并將它們同步分派給請(qǐng)求對(duì)應(yīng)的處理線程,Reactor模式也叫Dispatcher模式汉额,即I/O多了復(fù)用統(tǒng)一監(jiān)聽(tīng)事件曹仗,收到事件后分發(fā)(Dispatch給某進(jìn)程),是編寫(xiě)高性能網(wǎng)絡(luò)服務(wù)器的必備技術(shù)之一
Reactor模式中有2個(gè)關(guān)鍵組成:
Reactor
Reactor在一個(gè)單獨(dú)的線程中運(yùn)行蠕搜,負(fù)責(zé)監(jiān)聽(tīng)和分發(fā)事件怎茫,分發(fā)給適當(dāng)?shù)奶幚沓绦騺?lái)對(duì)IO事件做出反應(yīng)。 它就像公司的電話接線員妓灌,它接聽(tī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í)行非阻塞操作
根據(jù)Reactor的數(shù)量和處理資源池線程的數(shù)量不同祥山,有3種典型的實(shí)現(xiàn):
- 單Reactor單線程
- 單Reactor多線程
- 主從Reactor多線程
下面詳細(xì)介紹這3種實(shí)現(xiàn)
3.2.1 單Reactor單線程
其中,select是前面I/O復(fù)用模型介紹的標(biāo)準(zhǔn)網(wǎng)絡(luò)編程API掉伏,可以實(shí)現(xiàn)應(yīng)用程序通過(guò)一個(gè)阻塞對(duì)象監(jiān)聽(tīng)多路連接請(qǐng)求缝呕,其他方案示意圖類似
方案說(shuō)明
- 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ù)流程
優(yōu)點(diǎn)
模型簡(jiǎn)單鸡捐,沒(méi)有多線程栈暇、進(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)致性能瓶頸 - 可靠性問(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)
3.2.2 單Reactor多線程
方案說(shuō)明
- 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ù)各種事件
- 如果不是建立連接事件,則Reactor會(huì)分發(fā)調(diào)用連接對(duì)應(yīng)的Handler來(lái)響應(yīng)
- Handler只負(fù)責(zé)響應(yīng)事件痪蝇,不做具體業(yè)務(wù)處理鄙陡,通過(guò)read讀取數(shù)據(jù)后,會(huì)分發(fā)給后面的Worker線程池進(jìn)行業(yè)務(wù)處理
- Worker線程池會(huì)分配獨(dú)立的線程完成真正的業(yè)務(wù)處理躏啰,如何將響應(yīng)結(jié)果發(fā)給Handler進(jìn)行處理
- Handler收到響應(yīng)結(jié)果后通過(guò)send將響應(yīng)結(jié)果返回給client
優(yōu)點(diǎn)
可以充分利用多核CPU的處理能力
缺點(diǎn)
- 多線程數(shù)據(jù)共享和訪問(wèn)比較復(fù)雜
- Reactor承擔(dān)所有事件的監(jiān)聽(tīng)和響應(yīng)趁矾,在單線程中運(yùn)行,高并發(fā)場(chǎng)景下容易成為性能瓶頸
3.2.3 主從Reactor多線程
針對(duì)單Reactor多線程模型中给僵,Reactor在單線程中運(yùn)行毫捣,高并發(fā)場(chǎng)景下容易成為性能瓶頸,可以讓Reactor在多線程中運(yùn)行
方案說(shuō)明
- Reactor主線程MainReactor對(duì)象通過(guò)select監(jiān)控建立連接事件帝际,收到事件后通過(guò)Acceptor接收蔓同,處理建立連接事件
- Accepto處理建立連接事件后,MainReactor將連接分配Reactor子線程給SubReactor進(jìn)行處理
- SubReactor將連接加入連接隊(duì)列進(jìn)行監(jiān)聽(tīng)蹲诀,并創(chuàng)建一個(gè)Handler用于處理各種連接事件
- 當(dāng)有新的事件發(fā)生時(shí)斑粱,SubReactor會(huì)調(diào)用連接對(duì)應(yīng)的Handler進(jìn)行響應(yīng)
- Handler通過(guò)read讀取數(shù)據(jù)后,會(huì)分發(fā)給后面的Worker線程池進(jìn)行業(yè)務(wù)處理
- Worker線程池會(huì)分配獨(dú)立的線程完成真正的業(yè)務(wù)處理脯爪,如何將響應(yīng)結(jié)果發(fā)給Handler進(jìn)行處理
- Handler收到響應(yīng)結(jié)果后通過(guò)send將響應(yīng)結(jié)果返回給client
優(yōu)點(diǎn)
- 父線程與子線程的數(shù)據(jù)交互簡(jiǎn)單職責(zé)明確珊佣,父線程只需要接收新連接,子線程完成后續(xù)的業(yè)務(wù)處理
- 父線程與子線程的數(shù)據(jù)交互簡(jiǎn)單披粟,Reactor主線程只需要把新連接傳給子線程,子線程無(wú)需返回?cái)?shù)據(jù)
這種模型在許多項(xiàng)目中廣泛使用冷冗,包括Nginx主從Reactor多進(jìn)程模型守屉,Memcached主從多線程,Netty主從多線程模型的支持
3.2.4 總結(jié)
3種模式可以用個(gè)比喻來(lái)理解:
餐廳常常雇傭接待員負(fù)責(zé)迎接顧客蒿辙,當(dāng)顧客入坐后拇泛,侍應(yīng)生專門為這張桌子服務(wù)
- 單Reactor單線程
接待員和侍應(yīng)生是同一個(gè)人滨巴,全程為顧客服務(wù) - 單Reactor多線程
1個(gè)接待員,多個(gè)侍應(yīng)生俺叭,接待員只負(fù)責(zé)接待 - 主從Reactor多線程
多個(gè)接待員恭取,多個(gè)侍應(yīng)生
Reactor模式具有如下的優(yōu)點(diǎn):
- 響應(yīng)快,不必為單個(gè)同步時(shí)間所阻塞熄守,雖然Reactor本身依然是同步的
- 編程相對(duì)簡(jiǎn)單蜈垮,可以最大程度的避免復(fù)雜的多線程及同步問(wèn)題,并且避免了多線程/進(jìn)程的切換開(kāi)銷裕照;
- 可擴(kuò)展性攒发,可以方便的通過(guò)增加Reactor實(shí)例個(gè)數(shù)來(lái)充分利用CPU資源
- 可復(fù)用性,Reactor模型本身與具體事件處理邏輯無(wú)關(guān)晋南,具有很高的復(fù)用性
3.3 Proactor模型
在Reactor模式中惠猿,Reactor等待某個(gè)事件或者可應(yīng)用或個(gè)操作的狀態(tài)發(fā)生(比如文件描述符可讀寫(xiě),或者是socket可讀寫(xiě))负间,然后把這個(gè)事件傳給事先注冊(cè)的Handler(事件處理函數(shù)或者回調(diào)函數(shù))偶妖,由后者來(lái)做實(shí)際的讀寫(xiě)操作,其中的讀寫(xiě)操作都需要應(yīng)用程序同步操作政溃,所以Reactor是非阻塞同步網(wǎng)絡(luò)模型趾访。如果把I/O操作改為異步,即交給操作系統(tǒng)來(lái)完成就能進(jìn)一步提升性能玩祟,這就是異步網(wǎng)絡(luò)模型Proactor
Proactor是和異步I/O相關(guān)的腹缩,詳細(xì)方案如下:
- ProactorInitiator創(chuàng)建Proactor和Handler對(duì)象,并將Proactor和Handler都通過(guò)AsyOptProcessor(Asynchronous Operation Processor)注冊(cè)到內(nèi)核
- AsyOptProcessor處理注冊(cè)請(qǐng)求空扎,并處理I/O操作
- AsyOptProcessor完成I/O操作后通知Proactor
- Proactor根據(jù)不同的事件類型回調(diào)不同的Handler進(jìn)行業(yè)務(wù)處理
- Handler完成業(yè)務(wù)處理
可以看出Proactor和Reactor的區(qū)別:Reactor是在事件發(fā)生時(shí)就通知事先注冊(cè)的事件(讀寫(xiě)在應(yīng)用程序線程中處理完成)藏鹊;Proactor是在事件發(fā)生時(shí)基于異步I/O完成讀寫(xiě)操作(由內(nèi)核完成),待I/O操作完成后才回調(diào)應(yīng)用程序的處理器來(lái)處理進(jìn)行業(yè)務(wù)處理
理論上Proactor比Reactor效率更高转锈,異步I/O更加充分發(fā)揮DMA(Direct Memory Access盘寡,直接內(nèi)存存取)的優(yōu)勢(shì),但是有如下缺點(diǎn):
- 編程復(fù)雜性
由于異步操作流程的事件的初始化和事件完成在時(shí)間和空間上都是相互分離的撮慨,因此開(kāi)發(fā)異步應(yīng)用程序更加復(fù)雜竿痰。應(yīng)用程序還可能因?yàn)榉聪虻牧骺囟兊酶与y以Debug - 內(nèi)存使用
緩沖區(qū)在讀或?qū)懖僮鞯臅r(shí)間段內(nèi)必須保持住,可能造成持續(xù)的不確定性砌溺,并且每個(gè)并發(fā)操作都要求有獨(dú)立的緩存影涉,相比Reactor模式,在socket已經(jīng)準(zhǔn)備好讀或?qū)懬肮娣ィ遣灰箝_(kāi)辟緩存的 - 操作系統(tǒng)支持
Windows 下通過(guò) IOCP 實(shí)現(xiàn)了真正的異步 I/O蟹倾,而在 Linux 系統(tǒng)下,Linux2.6才引入,目前異步I/O還不完善
因此在Linux下實(shí)現(xiàn)高并發(fā)網(wǎng)絡(luò)編程都是以Reactor模型為主
參考
從0開(kāi)始學(xué)架構(gòu) —— Alibaba技術(shù)專家李運(yùn)華
技術(shù): Linux網(wǎng)絡(luò)IO模型
UNIX網(wǎng)絡(luò)編程卷1:套接字聯(lián)網(wǎng)API(第3版)