雖然異步方式最爲高效,但它也有本身的缺點。由於異步方式下,多個任務之間的調度是由服務器程序自身來完成的,並且一旦一個地方出現問題則整個服務器就會出現問題。所以,向這種服務器增長功能,一方面要聽從該服務器自身特定的任務調度方式,另外一方面要確保代碼中沒有錯誤存在,這就限制了服務器的功能,使得異步方式的 Web 服務器的效率最高,但功能簡單。例如Unix 平臺上的thttpd 就是這樣的一種服務器,然而因爲它提供的功能少,只能是知足少部分人的須要。即使如此,thttpd 每隔一段時間還會出現一些問題,幸運的是,它出問題時從不是進入死循環,而是被操做系統殺死,這樣就可使用一個shell 循環當即重啓動thttpd,從而基本不影響Web 服務。 程序員
因爲多線程方式使用線程進行任務調度,這樣服務器的開發因爲聽從標準,從而變得簡單並有利於多人協做。然而多個線程位於同一個進程內,能夠訪問一樣的內存空間,所以存在線程之間的影響,而且申請的內存必須確保申請和釋放。對於服務器系統來說,因爲它要數天、數月甚至數年連續不停的運轉,一點點錯誤就會逐漸積累而最終致使影響服務器的正常運轉,所以很難編寫一個高穩定性的多線程服務器程序。微軟的IIS 就是使用的多線程方式,因爲微軟彙集了至關多優秀程序員,因此IIS 基本上仍是值得信賴的,固然我也遇到過不少系統管理員,他們根據經驗按期啓動所管理的NT 服務器,以預防不可預料的Web 服務中止現象。
web
多進程方式的優點就在於穩定性,由於一個進程退出的時候,操做系統會回收其佔用的資源,從而使它不會留下任何垃圾。即使程序中出現錯誤,因爲進程是相互隔離的,那麼這個錯誤不會積累起來,而是隨着這個進程的退出而獲得清除。 shell
預生成進程方式的性能
因爲Apache 是採用的多進程方式提供服務,爲了提升性能,Apache 採用了一種特別的方式,即預生成進程模型。分析多進程方式比其餘兩種方式開銷大的主要緣由,是對每一次客戶請求,都要生成一個子進程以便進行處理,所以爲了不這種開銷,可使用預先生成的進程來提供服務,而且每一個進程在提供一次服務以後也不會當即退出,而是仍然保留在系統中,等待下一次請求。
這裏就能夠看出,在理想狀況下,預先生成的多個進程能夠全速回應相應數量的瀏覽器客戶請求,而沒有額外的性能開銷,所以就徹底能夠和線程或異步方式相媲美。然而在實際運行當中,因爲預先生成的進程畢竟要佔用系統資源,如系統內存和CPU 處理能力,
這樣若是預先生成的進程超過須要,性能反而會下降。所以Apache 就採用了這樣的一種策略,在系統中保持必定的空閒進程,當空閒進程較少時就自動生成,當空閒進程較多時就讓一些進程退出。 瀏覽器
因爲Apache 採用這樣的預生成進程模型,就致使預先要生成多少進程、保留多少空閒進程、一個進程提供多少次服務等等成爲與性能密切相關的問題,然而,這些設置都是與具 體條件密切相關的。例如,越多的進程須要佔用越多的內存,所分得的CPU 處理時間就越少,所以系統的物理內存和CPU 處理能力就決定了進程的最大數量。而Apache 提供的基本配置是爲了適應大多數狀況,在客戶請求較少時也不佔用過多資源,所以並非最高性能的設置。而大多數Web 服務器測試的條件下,服務器的內存、CPU 處理能力都不是問題,甚至內存大到足以將全部要訪問的文檔均可以放在系統緩衝中,於是無須考慮磁盤處理能力,這種狀況和實際應用徹底不一樣。所以,SGI 的一位開發者經過調整設置,並使用他本身對Apache 代碼的一些改動,在同一個SGI Origin 200 服務器上使用SPECweb96 進行測試,調整後的服務器能夠比原始設置提升10 倍的速度,固然這是針對SPECweb96 這個測試程序進行的調整,在實際使用中不可能會有這樣巨大的差異。這至少從側面說明了測試結果並非絕對的。 服務器
此外,Apache 的另外一個特色是它的功能特別豐富,而每種功能一般就須要進行特別的處理,這會影響Apache 的性能,然而對於具體的狀況,卻不是每種特性都是必要的,所以能夠經過減小這些功能來增長性能。此外,操做系統的調整對於加強Apache 的性能也是很是重要的。如何根據服務器的實際狀況調整操做系統以及Apache 的參數,這些內容在Apache 的文檔中都有很是詳細的描述。這些文檔包含在每一個Apache 安裝文件中,也能夠直接從它的主頁獲得。 多線程
worker的工做原理是,由主控制進程生成「StartServers」個子進程,每一個子進 程中包含固定的ThreadsPerChild線程數,各個線程獨立地處理請求.一樣,爲了避免在請求到來時再生成線程,MinSpareThreads和 MaxSpareThreads設置了最少和最多的空閒線程數;而MaxClients設置了全部子進程中的線程總數.若是現有子進程中的線程總數不能滿 足負載,控制進程將派生新的子進程. 異步
Worker模式下所能同時處理的請求總數是由子進程總 數乘以ThreadsPerChild值決定的,應該大於等於MaxClients.若是負載很大,現有的子進程數不能知足時,控制進程會派生新的子進 程.默認最大的子進程總數是16,加大時也須要顯式聲明ServerLimit(最大值是20000) 須要注意的是,若是顯式聲明瞭ServerLimit, 那麼它乘以ThreadsPerChild的值必須大於等於MaxClients,並且MaxClients必須是ThreadsPerChild的整數 倍,不然Apache將會自動調節到一個相應值(多是個非指望值). 性能
ServerLimit 服務器容許配置的進程數上限。這個指令和ThreadLimit結合使用配置了MaxClients最大容許配置的數值。任何在重啓期間對這個指令的改變都將被忽略,但對MaxClients的修改卻會生效。 測試
ThreadLimit 每一個子進程可配置的線程數上限。這個指令配置了每一個子進程可配置的線程數ThreadsPerChild上限。任何在重啓期間對這個指令的改變都將被忽略,但對ThreadsPerChild的修改卻會生效。默認值是"64". spa
StartServers 服務器啓動時創建的子進程數,默認值是"3"。
MinSpareThreads 最小空閒線程數,默認值是"75"。這個MPM將基於整個服務器監控空閒線程數。假如服務器中總的空閒線程數太少,子進程將產生新的空閒線程。
MaxSpareThreads 配置最大空閒線程數。默認值是"250"。這個MPM將基於整個服務器監控空閒線程數。假如服 務器中總的空閒線程數太多,子進程將殺死多餘的空閒線 程。MaxSpareThreads的取值範圍是有限制的。Apache將按照以下限制自動修正您配置的值:worker須要其大於等於 MinSpareThreads加上ThreadsPerChild的和。
MaxClients 容許同時伺服的最大接入請求數量(最大線程數量)。任何超過MaxClients限制的請求都將進入等候 隊列。默認值是"400",16 (ServerLimit)乘以25(ThreadsPerChild)的結果。所以要增長MaxClients的時候,您必須同時增長 ServerLimit的值。
ThreadsPerChild 每一個子進程創建的常駐的執行線程數。默認值是25。子進程在啓動時創建這些線程後就再也不創建新的線程了。
MaxRequestsPerChild 置每一個子進程在其生存期內容許伺服的最大請求數量。到達MaxRequestsPerChild的限制後,子進程將會結束。假如MaxRequestsPerChild爲"0",子進程將永遠不會結束。
將MaxRequestsPerChild配置成非零值有兩個好處:
1.可以防止(偶然的)內存泄漏無限進行,從而耗盡內存。
2.給進程一個有限壽命,從而有助於當服務器負載減輕的時候減小活動進程的數量。
注意
對於KeepAlive連接,只有第一個請求會被計數。事實上,他改變了每一個子進程限制最大連接數量的行爲。
工做方式:
每一個進程可以擁有的線程數量是固定的。服務器會根據負載狀況增長或減小進程數量。一個單獨的控制進程(父進程)負責子進程的建 立。每一個子進程可以創建 ThreadsPerChild數量的服務線程和一個監聽線程,該監聽線程監聽接入請求並將其傳遞給服務線程處理和應答。Apache老是試圖維持一個備 用(spare)或是空閒的服務線程池。這樣,客戶端無須等待新線程或新進程的創建便可獲得處理。在Unix中,爲了可以綁定80端口,父進程通常都是以 root身份啓動,隨後,Apache以較低權限的用戶創建子進程和線程。User和Group指令用於配置Apache子進程的權限。雖然子進程必須對 其提供的內容擁有讀權限,但應該儘量給予他較少的特權。另外,除非使用了suexec ,不然,這些指令配置的權限將被CGI腳本所繼承。
公式:
ThreadLimit >= ThreadsPerChild
MaxClients = MinSpareThreads+ThreadsPerChild
硬限制:
ServerLimi和ThreadLimit這兩個指令決定了活動子進程數量和每一個子進程中線程數量的硬限制。要想改變這個硬限制必須徹底中止服務器而後再啓動服務器(直接重啓是不行的)。
Apache在編譯ServerLimit時內部有一個硬性的限制,您不能超越這個限制。
prefork MPM最大爲"ServerLimit 200000"
其餘MPM(包括work MPM)最大爲"ServerLimit 20000
Apache在編譯ThreadLimit時內部有一個硬性的限制,您不能超越這個限制。
mpm_winnt是"ThreadLimit 15000"
其餘MPM(包括work prefork)爲"ThreadLimit 20000
注意 使用ServerLimit和ThreadLimit時要特別小心。假如將ServerLimit和ThreadLimit配置成一個高出實際須要許多的值,將會有過多的共享內存被分配。當配置成超過系統的處理能力,Apache可能沒法啓動,或系統將變得不穩定。