Apache的三種工作模式及相關配置

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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章