Apache的三種工作模式
作為老牌服務器,Apache仍在不斷地發展,就目前來說,它一共有三種穩定的MPM(Multi-Processing Module,多進程處理模塊)。它們分別是 prefork、worker 和 event 。
1、Prefork MPM
關鍵字:多進程
prefork模式可以算是很古老但是非常穩定的模式。Apache在啟動之初,就預派生 fork一些子進程,然后等待請求進來,並且總是視圖保持一些備用的子進程。之所以這樣做,是為了減少頻繁創建和銷毀進程的開銷。每個子進程中只有一個線程,在一個時間點內,只能處理一個請求。
在Unix系統中,父進程通常以root身份運行以便邦定80端口,而 Apache產生的子進程通常以一個低特權的用戶運行。User和Group指令用於配置子進程的低特權用戶。運行子進程的用戶必須要對他所服務的內容有讀取的權限,但是對服務內容之外的其他資源必須擁有盡可能少的權限。
優點:成熟,兼容所有新老模塊。進程之間完全獨立,使得它非常穩定。同時,不需要擔心線程安全的問題。(我們常用的mod_php,PHP的拓展不需要支持線程安全)
缺點:一個進程相對占用更多的系統資源,消耗更多的內存。而且,它並不擅長處理高並發請求,在這種場景下,它會將請求放進隊列中,一直等到有可用進程,請求才會被處理。
httpd-mpm.conf 中的相關配置:
<IfModule mpm_prefork_module> #服務器啟動時建立的子進程數量 StartServers 5 #空閑子進程的最小數量,默認5;如果當前空閑子進程數少於MinSpareServers ,那么Apache將會產生新的子進程。此參數不要設的太大。 MinSpareServers 5 #空閑子進程的最大數量,默認10;如果當前有超過MaxSpareServers數量的空閑子進程,那么父進程會殺死多余的子進程。此參數也不需要設置太大,如果你將其設置比 MinSpareServers 小,Apache會自動將其修改為MinSpareServers+1。 MaxSpareServers 10 #限定服務器同一時間內客戶端最大接入的請求數量,默認是150;任何超過了該限制的請求都要進入等待隊列,一旦一個個連接被釋放,隊列中的請求才將得到服務。 MaxClients 150 #每個子進程在其生命周期內允許最大的請求數量,如果請求總數已經達到這個數值,子進程將會結束,如果設置為0,子進程將永遠不會結束。若該值設置為非0值,可以防止運行PHP導致的內存泄露。 MaxRequestsPerChild 0 </IfModule>
創建的進程數,最多達到每秒32個,直到滿足MinSpareServers設置的值為止。這就是預派生(prefork)的由來。這種模式可以不必在請求到來時再產生新的進程,從而減小了系統開銷以增加性能。
並發量請求數到達MaxClients(如256)時,而空閑進程只有10個。apache為繼續增加創建進程。直到進程數到達256個。
當並發量高峰期過去了,並發請求數可能只有一個時,apache逐漸刪除進程,直到進程數到達MaxSpareServers為止。
2、Worker MPM
關鍵字:多進程+多線程
worker模式比起上一個,是使用了多進程+多線程的模式。它也預先fork了幾個子進程(數量比較少),每個子進程能夠生成一些服務線程和一個監聽線程,該監聽線程監聽接入請求並將其傳遞給服務線程處理和應答。
Apache總是試圖維持一個備用(spare)或是空閑的服務線程池。這樣,客戶端無須等待新線程或新進程的建立即可得到處理。在Unix中,為了能夠綁定80端口,父進程一般都是以root身份啟動,隨后,Apache以較低權限的用戶建立子進程和線程。User和Group指令用於配置Apache子進程的權限。雖然子進程必須對其提供的內容擁有讀權限,但應該盡可能給予他較少的特權。另外,除非使用了suexec ,否則,這些指令配置的權限將被CGI腳本所繼承。
線程比起進程會更輕量,因為線程通常會共享父進程的內存空間,因此,內存的占用會減少一些,在高並發的場景下,表現得比 prefork模式好。
有些人會覺得奇怪,那么這里為什么不直接使用多線程呢(即在一個進程內實現多進程),還要引入多進程?
原因主要是需要考慮穩定性,如果一個線程異常掛了,會導致父進程連同其他正常的子線程都掛了(它們都是同一個進程下的)。多進程+多線程模式中,各個進程之間都是獨立的,如果某個線程出現異常,受影響的只是Apache的一部分服務,而不是整個服務。其他進程仍然可以工作。
優點:占據更少的內存,高並發下表現更優秀。
缺點:必須考慮線程安全的問題,因為多個子線程是共享父進程的內存地址的。如果使用keep-alive的長連接方式,也許中間幾乎沒有請求,這時就會發生阻塞,線程被掛起,需要一直等待到超時才會被釋放。如果過多的線程,被這樣占據,也會導致在高並發場景下的無服務線程可用。(該問題在prefork模式下,同樣會發生)
Ps:http1.1的keep-alive的長連接方式,是為了讓下一次的socket通信復用之前創建的連接,從而,減少連接的創建和銷毀的系統開銷。保持連接,會讓某個進程或者線程一直處於等待狀態,即使沒有數據過來。
<IfModule mpm_worker_module> #服務器啟動時建立的子進程數量 StartServers 2 #限定服務器同一時間內客戶端最大接入的請求數量,默認是150;任何超過了該限制的請求都要進入等待隊列,一旦一個個連接被釋放,隊列中的請求才將得到服務。 MaxClients 150 #空閑子進程的最小數量 MinSpareThreads 25 #空閑子進程的最大數量 MaxSpareThreads 75 #每個子進程產生的線程數量 ThreadsPerChild 25 #每個子進程在其生命周期內允許最大的請求數量,如果請求總數已經達到這個數值,子進程將會結束,如果設置為0,子進程將永遠不會結束。將該值設置為非0值,可以防止運行PHP導致的內存泄露。 MaxRequestsPerChild 0 </IfModule>
理解配置:由主控制進程生成“StartServers”個子進程,每個子進程中包含固定的ThreadsPerChild線程數,各個線程獨立地處理請求。同樣,為了盡量避免在請求到來才生成線程,MinSpareThreads和MaxSpareThreads設置了最少和最多的空閑線程數;而MaxClients設置了所有子進程中的線程總數。如果現有子進程中的線程總數不能滿足負載,控制進程將派生新的子進程。
3、Event MPM
關鍵字:多進程+多線程+epoll
這個是 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,那個說法是幾年前的說法,現在已經支持了。
<IfModule mpm_worker_module> #服務器啟動時建立的子進程數量 StartServers 3 #空閑子進程的最小數量 MinSpareThreads 75 #空閑子進程的最小數量 MaxSpareThreads 250 #每個子進程產生的線程數量 ThreadsPerChild 25 #限定服務器同一時間內客戶端最大接入的請求數量,默認是150;任何超過了該限制的請求都要進入等待隊列,一旦一個個連接被釋放,隊列中的請求才將得到服務。 MaxRequestWorkers 400 #每個子進程在其生命周期內允許最大的請求數量,如果請求總數已經達到這個數值,子進程將會結束,如果設置為0,子進程將永遠不會結束。將該值設置為非0值,可以防止運行PHP導致的內存泄露。 MaxRequestsPerChild 0 </IfModule>
本文轉自:http://blog.csdn.net/STFPHP/article/details/52954303