日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

高并發(fā)Web服務(wù)的演變

 gljin_cn 2015-04-20

四、節(jié)約Web服務(wù)器的CPU

對(duì)Web服務(wù)器而言,CPU是另一個(gè)非常核心的系統(tǒng)資源。雖然一般情況下,我們認(rèn)為業(yè)務(wù)程序的執(zhí)行消耗了我們主要CPU。但是,就Web服務(wù)程序而言,多線程/多進(jìn)程的上下文切換,也是比較消耗CPU資源的。一個(gè)進(jìn)程/線程通常不能長(zhǎng)期占有CPU,當(dāng)發(fā)生阻塞或者時(shí)間片用完,就無(wú)法繼續(xù)占用CPU,這個(gè)時(shí)候,就會(huì)發(fā)生上下文切換,CPU時(shí)間片從老進(jìn)程/線程切換到新的。除此之外,在并發(fā)連接數(shù)目很高的場(chǎng)景下,對(duì)這些用戶建立的連接(socket文件描述符)狀態(tài)的輪詢和檢測(cè),也是比較消耗CPU的。

而Apache和Nginx的發(fā)展和演變,也在努力減少CPU開(kāi)銷。

1. Select/Poll(Apache早期版本的I/O多路復(fù)用)

通常,Web服務(wù)都要維護(hù)很多個(gè)和用戶通信的socket文件描述符,I/O多路復(fù)用,其實(shí)就是為了方便對(duì)這些文件描述符的管理和檢測(cè)。Apache早期版本,是使用select的模式,簡(jiǎn)單的說(shuō),就是將這些我們關(guān)注的socket文件描述符交給內(nèi)核,讓內(nèi)核告訴我們,那些描述符可操作。Poll與select原理基本相同,因此放在一起,它們之間的區(qū)別,就不贅敘了哈。

select/poll返回的是一個(gè)我們之前提交的文件描述符集合(內(nèi)核將其中可讀、可寫(xiě)或者異常狀態(tài)的socket文件描述符的標(biāo)識(shí)位修改了),我們需要通過(guò)輪詢檢查才能獲得我們可以操作的文件描述符。在這個(gè)過(guò)程中,不斷重復(fù)執(zhí)行。在實(shí)際應(yīng)用場(chǎng)景中,大部分被我們監(jiān)控的socket文件描述符,都是”空閑的“,也就是說(shuō),不能操作。我們對(duì)整個(gè)集合輪詢,就是為了找了少部分我們可以操作的socket文件描述符。于是,當(dāng)我們監(jiān)控的socket文件描述符越多(用戶并發(fā)連接數(shù)越來(lái)越多),這個(gè)輪詢工作,也就越來(lái)越沉重,進(jìn)而導(dǎo)致增大了CPU的開(kāi)銷。

 

如果我們監(jiān)控的socket文件描述符,幾乎都是”活躍的“,反而使用這種模式更合適一點(diǎn)。

2. Epoll(新版的Apache的event MPM,Nginx等支持)

Epoll是Linux2.6開(kāi)始正式支持的I/O多路復(fù)用,我們可以理解為它是對(duì)select/poll的改進(jìn)。首先,我們同樣將我們關(guān)注的socket文件描述符集合告訴給內(nèi)核,同時(shí),給它們注冊(cè)”回調(diào)函數(shù)“,如果某個(gè)socket文件準(zhǔn)備好了,就通過(guò)回調(diào)函數(shù)通知我們。于是,我們就不需要專門(mén)去輪詢整個(gè)全量的socket文件描述符集合,直接可以得到已經(jīng)可操作的socket文件描述符。那么,那些大部分”空閑“的描述符,我們就不遍歷了。即使我們監(jiān)控的socket文件描述越來(lái)越多,我們輪詢的也只是”活躍可操作“的socket文件描述符。

 

其實(shí),有一種極端點(diǎn)的場(chǎng)景,就是我們?nèi)课募枋龇麕缀醵际恰被钴S“的,這樣反而導(dǎo)致了大量回調(diào)函數(shù)的執(zhí)行,又增加了CPU的開(kāi)銷。但是,就Web服務(wù)的真實(shí)場(chǎng)景,絕大部分時(shí)候,都是連接集合中都存在很多”空閑“連接。

3. 線程/進(jìn)程的創(chuàng)建銷毀和上下文切換

通常,Apache某一個(gè)時(shí)間內(nèi),是一個(gè)進(jìn)程/線程服務(wù)于一個(gè)連接。于是,Apache就有很多的進(jìn)程/線程,服務(wù)于很多的連接。Web服務(wù)在高峰期,會(huì)建立很多的進(jìn)程/線程,也就帶來(lái)很多的上下文切換開(kāi)銷。而Nginx,它通常只有1個(gè)master主進(jìn)程和幾個(gè)worker子進(jìn)程,然后,1個(gè)worker進(jìn)程服務(wù)很多個(gè)連接,進(jìn)而節(jié)省了CPU的上下文切換開(kāi)銷。

 

兩種模式雖然不同,但實(shí)際上不能直接出分好壞,綜合來(lái)說(shuō),各有各自的優(yōu)勢(shì),就不妄議了哈。

4. 多線程下的鎖對(duì)CPU的開(kāi)銷

Apache中的worker和event模式,都有采用多線程。多線程因?yàn)楣蚕砀高M(jìn)程的內(nèi)存空間,在訪問(wèn)共享數(shù)據(jù)的時(shí)候,就會(huì)產(chǎn)生競(jìng)爭(zhēng),也就是線程安全問(wèn)題。因此通常會(huì)引入鎖(Linux下比較常用的線程相關(guān)的鎖有互斥量metux,讀寫(xiě)鎖rwlock等),成功獲取鎖的線程可以繼續(xù)執(zhí)行,獲取失敗的通常選擇阻塞等待。引入鎖的機(jī)制,程序的復(fù)雜度往往增加不少,同時(shí)還有線程“死鎖”或者“餓死”的風(fēng)險(xiǎn)(多進(jìn)程在訪問(wèn)進(jìn)程間共享資源的時(shí)候,也有同樣的問(wèn)題)。

死鎖現(xiàn)象(兩個(gè)線程彼此鎖住對(duì)方想要獲取的資源,相互阻塞等待,永遠(yuǎn)無(wú)法達(dá)不到滿足條件):

 

餓死現(xiàn)象(某個(gè)線程,一直獲取不到它想要鎖資源,永遠(yuǎn)無(wú)法執(zhí)行下一步):

 

為了避免這些鎖導(dǎo)致的問(wèn)題,就不得不加大程序的復(fù)雜度,解決方案一般有:

(1)對(duì)資源的加鎖,根據(jù)約定好的順序,大家都先對(duì)共享資源X加鎖,加鎖成功之后才能加鎖共享資源Y。

(2)如果線程占有資源X,卻加鎖資源Y失敗,則放棄加鎖,同時(shí)也釋放掉之前占有的資源X。

在使用PHP的時(shí)候,在Apache的worker和event模式下,也必須兼容線程安全。通常,新版本的PHP官方庫(kù)是沒(méi)有線程安全方面的問(wèn)題,需要關(guān)注的是第三方擴(kuò)展。PHP實(shí)現(xiàn)線程安全,不是通過(guò)鎖的方式實(shí)現(xiàn)的。而是為每個(gè)線程獨(dú)立申請(qǐng)一份全局變量的副本,相當(dāng)于線程的私人內(nèi)存空間,但是這樣做相對(duì)消耗多一些內(nèi)存。不過(guò),這樣的好處,是不需要引入復(fù)雜的鎖機(jī)制實(shí)現(xiàn),也避免了鎖機(jī)制對(duì)CPU的開(kāi)銷。

這里順便提到一下,經(jīng)常和Nginx搭配工作的PHP-FPM(FastCGI)使用的是多進(jìn)程,因此不會(huì)有線程安全的問(wèn)題。

 

五、 小結(jié)

可能有些同學(xué)看完之后,會(huì)得出結(jié)論,Nginx+PHP-FPM的工作方式,似乎是最節(jié)省系統(tǒng)資源的Web系統(tǒng)工作方式。某種程度上說(shuō),的確是可以這么說(shuō)的,但是Web系統(tǒng)的搭建,需要從實(shí)際業(yè)務(wù)應(yīng)用的角度出發(fā),具體問(wèn)題需要具體分析,尋求最合適的技術(shù)方案。

Web服務(wù)的不斷演變和發(fā)展,努力地追求用盡可能少的系統(tǒng)資源,來(lái)支撐更多的用戶請(qǐng)求,這是一條波瀾壯闊的前進(jìn)之路。這些技術(shù)方案,匯聚了很多值得學(xué)習(xí)和借鑒的解決問(wèn)題的思路。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多