就最新版本的Web服務器Apache(版本是Apache 2.4.10,發布于2014年7月21日)來說,一共有三種穩定的MPM(Multi-PRocessing Module,多進程處理模塊)模式。它們分別是prefork,worker和event,它們同時也代表這Apache的演變和發展。
查看我們Apache的模式,可以使用httpd -V命令來查看:
Shell
1 2 3 4 5 6 7 8 9 10 | # httpd -V Server version:Apache/2.4.10 (Unix) Server built: Dec 29 2014 11:23:13 Server's Module MagicNumber:20120211:36 Server loaded: APR 1.5.1, APR-UTIL 1.5.3 Compiled using:APR 1.5.1, APR-UTIL 1.5.3 Architecture: 64-bit Server MPM: event threaded: yes (fixed threadcount) forked: yes (variable processcount) |
編譯的時候,可以通過configure的參數來指定:
Shell
1 | --with-mpm=prefork|worker|event |
也可以編譯為三種都支持,通過修改配置來更換
Shell
1 | --enable-mpms-shared=all |
在httpd.conf中修改Apache的多處理模式MPM可以通過(modules文件夾下,會自動編譯出三個MPM的so):
Shell
1 2 3 | #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. prefork MPM
prefork模式可以算是很古老但是非常穩定的Apache模式。Apache在啟動之初,就預先fork一些子進程,然后等待請求進來。之所以這樣做,是為了減少頻繁創建和銷毀進程的開銷。每個子進程只有一個線程,在一個時間點內,只能處理一個請求。優點:成熟穩定,兼容所有新老模塊。同時,不需要擔心線程安全的問題。(我們常用的mod_php,PHP的拓展不需要支持線程安全)缺點:一個進程相對占用更多的系統資源,消耗更多的內存。而且,它并不擅長處理高并發請求,在這種場景下,它會將請求放進隊列中,一直等到有可用進程,請求才會被處理。
Apache的httpd.conf中的配置方式:
Shell
1 2 3 4 5 6 7 | <IfModulempm_prefork_module> StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxRequestWorkers 250 MaxConnectionsPerChild 0 </IfModule> |
2. worker MPM
worker模式比起上一個,是使用了多進程和多線程的混合模式。它也預先fork了幾個子進程(數量比較少),然后每個子進程創建一些線程,同時包括一個監聽線程。每個請求過來,會被分配到1個線程來服務。線程比起進程會更輕量,因為線程通常會共享父進程的內存空間,因此,內存的占用會減少一些。在高并發的場景下,因為比起prefork有更多的可用線程,表現會更優秀一些。有些人會覺得奇怪,那么這里為什么不完全使用多線程呢,還要引入多進程?原因主要是需要考慮穩定性,如果一個線程異常掛了,會導致父進程連同其他正常的子線程都掛了(它們都是同一個進程下的)。為了防止這場異常場景出現,就不能全部使用線程,使用多個進程再加多線程,如果某個線程出現異常,受影響的只是Apache的一部分服務,而不是整個服務。
優點:占據更少的內存,高并發下表現更優秀。
缺點:必須考慮線程安全的問題,因為多個子線程是共享父進程的內存地址的。如果使用keep-alive的長連接方式,某個線程會一直被占據,也許中間幾乎沒有請求,需要一直等待到超時才會被釋放。如果過多的線程,被這樣占據,也會導致在高并發場景下的無服務線程可用。(該問題在prefork模式下,同樣會發生)
注:keep-alive的長連接方式,是為了讓下一次的socket通信復用之前創建的連接,從而,減少連接的創建和銷毀的系統開銷。保持連接,會讓某個進程或者線程一直處于等待狀態,即使沒有數據過來。
Apache的httpd.conf中的配置方式:
1 2 3 4 5 6 7 8 | <IfModulempm_worker_module> StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 0 </IfModule> |
3. event MPM
這個是Apache中最新的模式,在現在版本里的已經是穩定可用的模式。它和worker模式很像,最大的區別在于,它解決了keep-alive場景下,長期被占用的線程的資源浪費問題(某些線程因為被keep-alive,空掛在哪里等待,中間幾乎沒有請求過來,甚至等到超時)。event MPM中,會有一個專門的線程來管理這些keep-alive類型的線程,當有真實請求過來的時候,將請求傳遞給服務線程,執行完畢后,又允許它釋放。這樣增強了高并發場景下的請求處理能力。
event MPM在遇到某些不兼容的模塊時,會失效,將會回退到worker模式,一個工作線程處理一個請求。官方自帶的模塊,全部是支持event MPM的。
注意一點,event MPM需要linux系統(Linux 2.6+)對EPoll的支持,才能啟用。
還有,需要補充的是HTTPS的連接(SSL),它的運行模式仍然是類似worker的方式,線程會被一直占用,知道連接關閉。部分比較老的資料里,說event MPM不支持SSL,那個說法是幾年前的說法,現在已經支持了。
Apache的httpd.conf中的配置方式:
Shell
1 2 3 4 5 6 7 8 | <IfModulempm_event_module> StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 0 </IfModule> |
三種模式下,我通過ab做了一下性能測試,在常規滿負載的場景下,并未發現有大的差異。測試語句:
C
1 | ./ab -k -c 200 -n 200000 192.168.0.11/index.html |
測試結果:
C
1 2 3 | prefork:9556QPS worker :11038QPS event :10224QPS |
測試語句:
C
1 | ./ab -k -c 200 -n 200000 192.168.0.11/index.php(echo "hello world";) |
測試結果:
C
1 2 3 | prefork:6094QPS worker :7411QPS event :7089QPS |
就使用PHP而言,fastCGI和php-fpm是更推薦的使用模式。
現在的最新瀏覽器,在單個域名下的連接數變得越來越多(通常都是使用keep-alive),主流瀏覽器是2-6個(還有繼續增長趨勢,為了加快頁面的并發下載速度)。高并發場景,會越來越成為Web系統的一種常態。Apache很成熟,同時也背負了比較重的歷史代碼和模塊,因此,在Web系統比較方面,Nginx在不少場景下,表現比起Apache更為出色。
|
新聞熱點
疑難解答