就最新版本的Web服務(wù)器Apache2.4來說,一共有三種穩(wěn)定的MPM(Multi-Processing Module,多進(jìn)程處理模塊)模式。它們分別是prefork,worker和event,它們同時(shí)也代表這Apache的演變和發(fā)展。
首先簡(jiǎn)單介紹一下prefork、worker、event三種工作模式:
prefork,多進(jìn)程模式,1個(gè)進(jìn)程服務(wù)于1個(gè)用戶請(qǐng)求,成本比較高。但是,穩(wěn)定性最高,不需要支持線程安全。
worker,多進(jìn)程多線程模式,1個(gè)進(jìn)程含有多個(gè)worker線程,1個(gè)worker線程服務(wù)于1個(gè)用戶請(qǐng)求,因?yàn)榫€程更輕量,成本比較低。但是,在KeepAlive場(chǎng)景下,worker資源會(huì)被client占據(jù),無法響應(yīng)其他請(qǐng)求(空等待)。
event,多進(jìn)程多線程模式,1個(gè)進(jìn)程也含有多個(gè)worker線程,1個(gè)worker線程服務(wù)于1個(gè)用戶請(qǐng)求。但是,它解決了KeepAlive場(chǎng)景下的worker線程被占據(jù)問題,它通過專門的線程來管理這些KeepAlive連接,然后再分配“工作”給具體處理的worker,工作worker不會(huì)因?yàn)镵eepAlive而導(dǎo)致空等待。
查看我們Apache的模式,可以使用httpd -V命令來查看:
[root@localhost ~]# httpd -V
Server version: Apache/2.4.23 (Unix)
Server built: Nov 15 2016 10:43:13
Server's Module Magic Number: 20120211:61
Server loaded: APR 1.5.2, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture: 64-bit
Server MPM: event
編譯的時(shí)候,可以通過configure的參數(shù)來指定:
--with-mpm=prefork|worker|event
也可以編譯為三種都支持,通過修改配置來更換:
--enable-mpms-shared=all
在httpd.conf中修改Apache的多處理模式MPM可以通過(modules文件夾下,會(huì)自動(dòng)編譯出三個(gè)MPM的so):
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
LoadModule mpm_event_module modules/mod_mpm_event.so
1. mpm_prefork模式
prefork模式可以算是很古老但是非常穩(wěn)定的Apache模式。Apache在啟動(dòng)之初,就預(yù)先fork一些子進(jìn)程,然后等待請(qǐng)求進(jìn)來。之所以這樣做,是為了減少頻繁創(chuàng)建和銷毀進(jìn)程的開銷。每個(gè)子進(jìn)程只有一個(gè)線程,在一個(gè)時(shí)間點(diǎn)內(nèi),只能處理一個(gè)請(qǐng)求。
優(yōu)點(diǎn):成熟穩(wěn)定,兼容所有新老模塊。同時(shí),不需要擔(dān)心線程安全的問題。(我們常用的mod_php,PHP的拓展不需要支持線程安全)
缺點(diǎn):一個(gè)進(jìn)程相對(duì)占用更多的系統(tǒng)資源,消耗更多的內(nèi)存。而且,它并不擅長(zhǎng)處理高并發(fā)請(qǐng)求,在這種場(chǎng)景下,它會(huì)將請(qǐng)求放進(jìn)隊(duì)列中,一直等到有可用進(jìn)程,請(qǐng)求才會(huì)被處理。
Apache2.4在/etc/httpd/extra/httpd-manual.conf中配置參數(shù)(httpd.conf默認(rèn)沒有啟用,需要#Include /etc/httpd/extra/httpd-mpm.conf取消這行的注釋,重啟httpd):
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250
MaxConnectionsPerChild 0
</IfModule>
2. mpm_worker模式
worker模式比起上一個(gè),是使用了多進(jìn)程和多線程的混合模式。它也預(yù)先fork了幾個(gè)子進(jìn)程(數(shù)量比較少),然后每個(gè)子進(jìn)程創(chuàng)建一些線程,同時(shí)包括一個(gè)監(jiān)聽線程。每個(gè)請(qǐng)求過來,會(huì)被分配到1個(gè)線程來服務(wù)。線程比起進(jìn)程會(huì)更輕量,因?yàn)榫€程通常會(huì)共享父進(jìn)程的內(nèi)存空間,因此,內(nèi)存的占用會(huì)減少一些。在高并發(fā)的場(chǎng)景下,因?yàn)楸绕餻refork有更多的可用線程,表現(xiàn)會(huì)更優(yōu)秀一些。
有些人會(huì)覺得奇怪,那么這里為什么不完全使用多線程呢,還要引入多進(jìn)程?
原因主要是需要考慮穩(wěn)定性,如果一個(gè)線程異常掛了,會(huì)導(dǎo)致父進(jìn)程連同其他正常的子線程都掛了(它們都是同一個(gè)進(jìn)程下的)。為了防止這場(chǎng)異常場(chǎng)景出現(xiàn),就不能全部使用線程,使用多個(gè)進(jìn)程再加多線程,如果某個(gè)線程出現(xiàn)異常,受影響的只是Apache的一部分服務(wù),而不是整個(gè)服務(wù)。
優(yōu)點(diǎn):占據(jù)更少的內(nèi)存,高并發(fā)下表現(xiàn)更優(yōu)秀。
缺點(diǎn):必須考慮線程安全的問題,因?yàn)槎鄠€(gè)子線程是共享父進(jìn)程的內(nèi)存地址的。如果使用keep-alive的長(zhǎng)連接方式,某個(gè)線程會(huì)一直被占據(jù),也許中間幾乎沒有請(qǐng)求,需要一直等待到超時(shí)才會(huì)被釋放。如果過多的線程,被這樣占據(jù),也會(huì)導(dǎo)致在高并發(fā)場(chǎng)景下的無服務(wù)線程可用。(該問題在prefork模式下,同樣會(huì)發(fā)生)
注:keep-alive的長(zhǎng)連接方式,是為了讓下一次的socket通信復(fù)用之前創(chuàng)建的連接,從而,減少連接的創(chuàng)建和銷毀的系統(tǒng)開銷。保持連接,會(huì)讓某個(gè)進(jìn)程或者線程一直處于等待狀態(tài),即使沒有數(shù)據(jù)過來。
也是在/etc/httpd/extra/httpd-manual.conf中設(shè)置參數(shù):
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
3. mpm_event模式
這個(gè)是Apache中最新的模式,在現(xiàn)在版本里的已經(jīng)是穩(wěn)定可用的模式。它和worker模式很像,最大的區(qū)別在于,它解決了keep-alive場(chǎng)景下,長(zhǎng)期被占用的線程的資源浪費(fèi)問題(某些線程因?yàn)楸籯eep-alive,空掛在哪里等待,中間幾乎沒有請(qǐng)求過來,甚至等到超時(shí))。event MPM中,會(huì)有一個(gè)專門的線程來管理這些keep-alive類型的線程,當(dāng)有真實(shí)請(qǐng)求過來的時(shí)候,將請(qǐng)求傳遞給服務(wù)線程,執(zhí)行完畢后,又允許它釋放。這樣增強(qiáng)了高并發(fā)場(chǎng)景下的請(qǐng)求處理能力。
event MPM在遇到某些不兼容的模塊時(shí),會(huì)失效,將會(huì)回退到worker模式,一個(gè)工作線程處理一個(gè)請(qǐng)求。官方自帶的模塊,全部是支持event MPM的。
注意一點(diǎn),event MPM需要Linux系統(tǒng)(Linux 2.6+)對(duì)EPoll的支持,才能啟用。
還有,需要補(bǔ)充的是HTTPS的連接(SSL),它的運(yùn)行模式仍然是類似worker的方式,線程會(huì)被一直占用,知道連接關(guān)閉。部分比較老的資料里,說event MPM不支持SSL,那個(gè)說法是幾年前的說法,現(xiàn)在已經(jīng)支持了。
同樣也在/etc/httpd/extra/httpd-manual.conf中設(shè)置參數(shù):
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
三種模式下,我通過ab做了一下性能測(cè)試,在常規(guī)滿負(fù)載的場(chǎng)景下,并未發(fā)現(xiàn)有大的差異。
測(cè)試語句:
ab -k -c 200 -n 200000 http://www.zhongjima.net/index.html
測(cè)試結(jié)果:
prefork:9556QPS
worker :11038QPS
event :10224QPS
測(cè)試語句:
ab -k -c 200 -n 200000 http://www.zhongjima.net/index.php(echo "hello world";)
測(cè)試結(jié)果:
prefork:6094QPS
worker :7411QPS
event :7089QPS
就使用PHP而言,fastCGI和php-fpm是更推薦的使用模式。
現(xiàn)在的最新瀏覽器,在單個(gè)域名下的連接數(shù)變得越來越多(通常都是使用keep-alive),主流瀏覽器是2-6個(gè)(還有繼續(xù)增長(zhǎng)趨勢(shì),為了加快頁(yè)面的并發(fā)下載速度)。高并發(fā)場(chǎng)景,會(huì)越來越成為Web系統(tǒng)的一種常態(tài)。Apache很成熟,同時(shí)也背負(fù)了比較重的歷史代碼和模塊,因此,在Web系統(tǒng)比較方面,Nginx在不少場(chǎng)景下,表現(xiàn)比起Apache更為出色。