做爲老牌服務器,Apache仍在不斷地發展,就目前來講,它一共有三種穩定的MPM(Multi-Processing Module,多進程處理模塊)。它們分別是 prefork、worker 和 event 。php
關鍵字:多進程linux
prefork模式能夠算是很古老可是很是穩定的模式。Apache在啓動之初,就預派生 fork一些子進程,而後等待請求進來,而且老是視圖保持一些備用的子進程。之因此這樣作,是爲了減小頻繁建立和銷燬進程的開銷。每一個子進程中只有一個線程,在一個時間點內,只能處理一個請求。apache
在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個。socket
當併發量高峯期過去了,併發請求數可能只有一個時,apache逐漸刪除進程,直到進程數到達MaxSpareServers爲止。高併發
關鍵字:多進程+多線程
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設置了全部子進程中的線程總數。若是現有子進程中的線程總數不能知足負載,控制進程將派生新的子進程。
關鍵字:多進程+多線程+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>