從設(shè)計架構(gòu)上來說嚣伐,Nginx服務(wù)器是與眾不同的赂毯。不同之處一方面體現(xiàn)在它的模塊化設(shè)計战虏,另一方面,也是更重要的一方面党涕,體現(xiàn)在它對客戶端請求的處理機(jī)制上烦感。
Web服務(wù)器和客戶端是一對多的關(guān)系,Web服務(wù)器必須有能力同時為多個客戶端提供服務(wù)膛堤。一般來說手趣,完成并行處理請求工作有三種方式可供選擇:多進(jìn)程方式、多線程方式和異步方式骑祟。
多進(jìn)程方式
多進(jìn)程方式是指回懦,服務(wù)器每當(dāng)接收到一個客戶端時,就由服務(wù)器主進(jìn)程生成一個子進(jìn)程出來和該客戶端建立連接進(jìn)行交互次企,直到連接斷開,該子進(jìn)程就結(jié)束了潜圃。
多進(jìn)程方式的優(yōu)點在于缸棵,設(shè)計和實現(xiàn)相對簡單,各個子進(jìn)程之間相互獨立谭期,處理客戶端請求的過程彼此不受到干擾堵第,并且當(dāng)一個子進(jìn)程產(chǎn)生問題時,不容易將影響漫延到其他進(jìn)程中隧出,這保證了提供服務(wù)的穩(wěn)定性踏志。當(dāng)子線程退出時,其占用資源會被操作系統(tǒng)回收胀瞪,也不會留下任何垃圾针余。而其缺點也是很明顯的。操作系統(tǒng)中生成一個子進(jìn)程需要進(jìn)行內(nèi)存復(fù)制等操作凄诞,在資源和時間上會產(chǎn)生一定的額外開銷圆雁,因此,如果Web服務(wù)器接收大量并發(fā)請求帆谍,就會對系統(tǒng)資源造成壓力伪朽,導(dǎo)致系統(tǒng)性能下降。
初期的Apache服務(wù)器就是采用這種方式對外提供服務(wù)的汛蝙。為了應(yīng)對大量并發(fā)請求烈涮,Apache服務(wù)器采用“預(yù)生成進(jìn)程”的機(jī)制對多進(jìn)程方式進(jìn)行了改進(jìn)朴肺。“預(yù)生成進(jìn)程”的工作方式很好理解坚洽。它將生成子進(jìn)程的時機(jī)提前宇挫,在客戶端請求還沒有到來之前就預(yù)先生成好,當(dāng)請求到來時酪术,主進(jìn)程分配一個子進(jìn)程和該客戶端進(jìn)行交互器瘪,交互完成之后,該進(jìn)程也不結(jié)束绘雁,而被主進(jìn)程管理起來等待下一個客戶端請求的到來橡疼。改進(jìn)的多進(jìn)程方式在一定程度上緩解了大量并發(fā)請求情形下Web服務(wù)器對系統(tǒng)資源造成的壓力。但是由于Apache服務(wù)器在最初的架構(gòu)設(shè)計上采用了多進(jìn)程方式庐舟,因此這不能從根本上解決問題欣除。
多線程方式
多線程方式和多進(jìn)程方式相似,它是指挪略,服務(wù)器每當(dāng)接收到一個客戶端時历帚,會由服務(wù)器主進(jìn)程派生一個線程出來和該客戶端進(jìn)行交互。
由于操作系統(tǒng)產(chǎn)生一個線程的開銷遠(yuǎn)遠(yuǎn)小于產(chǎn)生一個進(jìn)程的開銷杠娱,所以多線程方式在很大程度上減輕了Web服務(wù)器對系統(tǒng)資源的要求挽牢。該方式使用線程進(jìn)行任務(wù)調(diào)度,開發(fā)方面可以遵循一定的標(biāo)準(zhǔn)摊求,這相對來說比較規(guī)范和有利于協(xié)作禽拔。但在線程管理方面,該方式有一定的不足室叉。多個線程位于同一個進(jìn)程內(nèi)睹栖,可以訪問同樣的內(nèi)存空間,彼此之間相互影響茧痕;同時野来,在開發(fā)過程中不可避免地要由開發(fā)者自己對內(nèi)存進(jìn)行管理,其增加了出錯的風(fēng)險踪旷。服務(wù)器系統(tǒng)需要長時間連續(xù)不停地運轉(zhuǎn)曼氛,錯誤的逐漸積累可能最終對整個服務(wù)器產(chǎn)生重大影響。
IIS服務(wù)器使用了多線程方式對外提供服務(wù)埃脏,它的穩(wěn)定性相對來說還是不錯的搪锣,但對于經(jīng)驗豐富的Web服務(wù)器管理人員而言,他們通常還是會定期檢查和重啟服務(wù)器彩掐,以預(yù)防不可預(yù)料的故障發(fā)生构舟。
異步方式
異步方式是和多進(jìn)程方式及多線程方式完全不同的一種處理客戶端請求的方式。在介紹該方式之前,我們先復(fù)習(xí)一下同步狗超、異步以及阻塞弹澎、非阻塞的概念。
網(wǎng)絡(luò)通信中的同步機(jī)制和異步機(jī)制是描述通信模式的概念努咐。同步機(jī)制苦蒿,是指發(fā)送方發(fā)送請求后,需要等待接收到接收方發(fā)回的響應(yīng)后渗稍,才接著發(fā)送下一個請求佩迟;異步機(jī)制,和同步機(jī)制正好相反竿屹,在異步機(jī)制中报强,發(fā)送方發(fā)出一個請求后,不等待接收方響應(yīng)這個請求拱燃,就繼續(xù)發(fā)送下個請求秉溉。在同步機(jī)制中,所有的請求在服務(wù)器端得到同步碗誉,發(fā)送方和接收方對請求的處理步調(diào)是一致的召嘶;在異步機(jī)制中,所有來自發(fā)送方的請求形成一個隊列哮缺,接收方處理完成后通知發(fā)送方弄跌。
阻塞和非阻塞用來描述進(jìn)程處理調(diào)用的方式,在網(wǎng)絡(luò)通信中蝴蜓,主要指網(wǎng)絡(luò)套接字Socket的阻塞和非阻塞方式碟绑,而Socket的實質(zhì)也就是IO操作。Socket的阻塞調(diào)用方式為茎匠,調(diào)用結(jié)果返回之前,當(dāng)前線程從運行狀態(tài)被掛起押袍,一直等到調(diào)用結(jié)果返回之后诵冒,才進(jìn)入就緒狀態(tài),獲取CPU后繼續(xù)執(zhí)行谊惭;Socket的非阻塞調(diào)用方式和阻塞調(diào)用方式正好相反汽馋,在非阻塞方式中,如果調(diào)用結(jié)果不能馬上返回圈盔,當(dāng)前線程也不會被掛起豹芯,而是立即返回執(zhí)行下一個調(diào)用。
在網(wǎng)絡(luò)通信中驱敲,經(jīng)程福可以看到有人將同步和阻塞等同、異步和非阻塞等同众眨。事實上握牧,這兩對概念有一定的區(qū)別容诬,不能混淆。兩對概念的組合沿腰,就會產(chǎn)生四個新的概念览徒,同步阻塞、異步阻塞颂龙、同步非阻塞习蓬、異步非阻塞。
- 同步阻塞方式
發(fā)送方向接收方發(fā)送請求后措嵌,一直等待響應(yīng)躲叼;接收方處理請求時進(jìn)行的IO操作如果不能馬上得到結(jié)果,就一直等到返回結(jié)果后铅匹,才響應(yīng)發(fā)送方押赊,期間不能進(jìn)行其他工作。比如包斑,在超市排隊付賬時流礁,客戶(發(fā)送方)向收款員(接收方)付款(發(fā)送請求)后需要等待收款員找零,期間不能做其他的事情罗丰;而收款員要等待收款機(jī)返回結(jié)果(IO操作)后才能把零錢取出來交給客戶(響應(yīng)請求)神帅,期間也只能等待,不能做其他事情萌抵。這種方式實現(xiàn)簡單找御,但是效率不高。
- 同步非阻塞方式
發(fā)送方向接收方發(fā)送請求后绍填,一直等待響應(yīng)霎桅;接收方處理請求時進(jìn)行的IO操作如果不能馬上得到結(jié)果,就立即返回讨永,去做其他事情滔驶,但由于沒有得到請求處理結(jié)果,不響應(yīng)發(fā)送方卿闹,發(fā)送方一直等待揭糕。一直到IO操作完成后,接收方獲得結(jié)果響應(yīng)發(fā)送方后锻霎,接收方才進(jìn)入下一次請求過程著角。在實際中不使用這種方式。
- 異步阻塞方式
發(fā)送方向接收方發(fā)送請求后旋恼,不用等待響應(yīng)吏口,可以接著進(jìn)行其他工作;接收方處理請求時進(jìn)行的IO操作如果不能馬上得到結(jié)果,就一直等到返回結(jié)果后锨侯,才響應(yīng)發(fā)送方嫩海,期間不能進(jìn)行其他工作。這種方式在實際中也不使用囚痴。
- 異步非阻塞方式
發(fā)送方向接收方發(fā)送請求后叁怪,不用等待響應(yīng),可以繼續(xù)其他工作深滚;接收方處理請求時進(jìn)行的IO操作如果不能馬上得到結(jié)果奕谭,也不等待,而是馬上返回去做其他事情痴荐。當(dāng)IO操作完成以后血柳,將完成狀態(tài)和結(jié)果通知接收方,接收方再響應(yīng)發(fā)送方生兆。繼續(xù)使用在超市排隊付賬的例子难捌。客戶(發(fā)送方)向收款員(接收方)付款(發(fā)送請求)后在等待收款員找零的過程中鸦难,還可以做其他事情根吁,比如打電話、聊天等合蔽;而收款員在等待收款機(jī)處理交易(IO操作)的過程中可以幫助客戶將商品打包击敌,當(dāng)收款機(jī)產(chǎn)生結(jié)果后,收款員給客戶結(jié)賬(響應(yīng)請求)拴事。在四種方式中沃斤,這種方式是發(fā)送方和接收方通信效率最高的一種。
Nginx服務(wù)器如何處理請求
Nginx服務(wù)器的一個顯著優(yōu)勢是能夠同時處理大量并發(fā)請求刃宵。它結(jié)合多進(jìn)程機(jī)制和異步機(jī)制對外提供服務(wù)衡瓶。異步機(jī)制使用的是異步非阻塞方式。
Nginx服務(wù)器啟動后牲证,可以產(chǎn)生一個主進(jìn)程(master process)和多個工作進(jìn)程(worker processes)鞍陨,其中可以在配置文件中指定產(chǎn)生的工作進(jìn)程數(shù)量。Nginx服務(wù)器的所有工作進(jìn)程都用于接收和處理客戶端的請求从隆。這類似于Apache使用的改進(jìn)的多進(jìn)程機(jī)制,預(yù)先生成多個工作進(jìn)程缭裆,等待處理客戶端請求键闺。
實際上,Nginx服務(wù)器的進(jìn)程模型有兩種:Single模型和Master-Worker模型澈驼。Single模型為單進(jìn)程方式辛燥,性能較差,一般在實際工作中不使用。Master-Worker模型實際上被更廣泛地稱為Master-Slave模型挎塌。在Nginx服務(wù)器中徘六,充當(dāng)Slave角色的是工作進(jìn)程。
每個工作進(jìn)程使用了異步非阻塞方式榴都,可以處理多個客戶端請求待锈。當(dāng)某個工作進(jìn)程接收到客戶端的請求以后,調(diào)用IO進(jìn)行處理嘴高,如果不能立即得到結(jié)果竿音,就去處理其他的請求;而客戶端在此期間也無需等待響應(yīng)拴驮,可以去處理其他的事情春瞬;當(dāng)IO調(diào)用返回結(jié)果時,就會通知此工作進(jìn)程套啤;該進(jìn)程得到通知宽气,暫時掛起當(dāng)前處理的事務(wù),去響應(yīng)客戶端請求潜沦。
客戶端請求數(shù)量增長萄涯、網(wǎng)絡(luò)負(fù)載繁重時,Nginx服務(wù)器使用多進(jìn)程機(jī)制能夠保證不增長對系統(tǒng)資源的壓力止潮;同時使用異步非阻塞方式減少了工作進(jìn)程在I/O調(diào)用上的阻塞延遲窃判,保證了不降低對請求的處理能力。
Nginx服務(wù)器的工作進(jìn)程調(diào)用IO后喇闸,就去進(jìn)行其他工作了袄琳;當(dāng)IO調(diào)用返回后,會通知工作進(jìn)程燃乍。這里有一個問題唆樊,IO調(diào)用是如何把自己的狀態(tài)通知給工作進(jìn)程的呢?
一般解決這個問題的方案有兩種刻蟹。一是逗旁,讓工作進(jìn)程在進(jìn)行其他工作的過程中間隔一段時間就去檢查一下IO的運行狀態(tài),如果完成舆瘪,就去響應(yīng)客戶端片效,如果未完成,就繼續(xù)正在進(jìn)行的工作英古;二是淀衣, IO調(diào)用在完成后能主動通知工作進(jìn)程。對于前者召调,雖然工作進(jìn)程在IO調(diào)用過程中沒有等待膨桥,但不斷的檢查仍然在時間和資源上導(dǎo)致了不小的開銷蛮浑,最理想的解決方案是第二種。
具體來說只嚣,select/poll/epoll/kqueue等這樣的系統(tǒng)調(diào)用就是用來支持第二種解決方案的沮稚。這些系統(tǒng)調(diào)用,也常被稱為事件驅(qū)動模型册舞,它們提供了一種機(jī)制蕴掏,讓進(jìn)程可以同時處理多個并發(fā)請求,不用關(guān)心IO調(diào)用的具體狀態(tài)环础。IO調(diào)用完全由事件驅(qū)動模型來管理囚似,事件準(zhǔn)備好之后就通知工作進(jìn)程事件已經(jīng)就緒。