在Inte.net中的Web服務器領域內,Apache占有無可爭議的領先地位。根據Netcraft ( ) 的調查,有60%的Web服務器是使用的Apache,當然由于這個統計是基于域名進行的,由于Apache的強大功能,很多ISP使用它來提供服務,因此如果基于IP地址來計算服務器數量,那么這個占有率會低一些,當然這不會改變Apache在Web領域的領先地位。
然而,由于Apache服務器為一種自由軟件,它的性能及穩定性問題一直受到質疑。由于Apache服務器支撐著半數的Internet,對它的穩定性任何人都無法提出異議,然而,性能問題則就不那么明顯可以看出來的了。因為一個網站可以擁有多個Web服務器,通過負載均衡的方式來在這多個服務器之間分擔負載,那么不同的服務器之間的性能差異,只要不是太明顯,是不容易看出的,因此就需要使用測試軟件對它們的性能進行評測。其中與微軟關系密切的Mindcraft()去年發布的對Apache和IIS的評測,結果表明,在基本的提供靜態網頁方面,IIS的性能是Apache的3.7倍,而另一個德國網站()使用另一個測試軟件進行的評測,卻得到Apache的性能要超過IIS的結論。為什么Apache服務器在不同的評測中會得到不同的結果呢?我們必須討論一下Web服務器的實現機理。
服務器提供服務的方式
網絡服務器由于要同時為多個客戶提供服務,就必須使用某種方式來支持這種多任務的服務方式。一般情況下可以有三種方式來選擇,多進程方式、多線程方式及異步方式。其中,多進程方式中服務器對一個客戶要使用一個進程來提供服務,由于在操作系統中,生成一個進程需要進程內存復制等額外的開銷,這樣在客戶較多時的性能就會降低。為了克服這種生成進程的額外開銷,可以使用多線程方式或異步方式。在多線程方式中,使用進程中的多個線程提供服務,由于線程的開銷較小,性能就會提高。事實上,不需要任何額外開銷的方式還是異步方式,它使用非阻塞的方式與每個客戶通信,服務器使用一個進程進行輪詢就行了。
雖然異步方式最為高效,但它也有自己的缺點。因為異步方式下,多個任務之間的調度是由服務器程序自身來完成的,而且一旦一個地方出現問題則整個服務器就會出現問題。因此,向這種服務器增加功能,一方面要遵從該服務器自身特定的任務調度方式,另一方面要確保代碼中沒有錯誤存在,這就限制了服務器的功能,使得異步方式的Web服務器的效率最高,但功能簡單。例如Unix平臺上的thttpd就是這樣的一種服務器,然而由于它提供的功能少,只能是滿足少部分人的需要。即便如此,thttpd每隔一段時間還會出現一些問題,幸運的是,它出問題時從不是進入死循環,而是被操作系統殺死,這樣就可以使用一個shell循環立即重啟動thttpd,從而基本不影響Web服務。
由于多線程方式使用線程進行任務調度,這樣服務器的開發由于遵從標準,從而變得簡單并有利于多人協作。然而多個線程位于同一個進程內,可以訪問同樣的內存空間,因此存在線程之間的影響,并且申請的內存必須確保申請和釋放。對于服務器系統來講,由于它要數天、數月甚至數年連續不停的運轉,一點點錯誤就會逐漸積累而最終導致影響服務器的正常運轉,因此很難編寫一個高穩定性的多線程服務器程序。微軟的IIS就是使用的多線程方式,由于微軟聚集了相當多優秀程序員,所以IIS基本上還是值得信賴的,當然我也遇到過很多系統管理員,他們根據經驗定期啟動所管理的NT服務器,以預防不可預料的Web服務停止現象。
多進程方式的優勢就在于穩定性,因為一個進程退出的時候,操作系統會回收其占用的資源,從而使它不會留下任何垃圾。即便程序中出現錯誤,由于進程是相互隔離的,那么這個錯誤不會積累起來,而是隨著這個進程的退出而得到清除。
預生成進程方式的性能
由于Apache是采用的多進程方式提供服務,為了提高性能,Apache采用了一種特別的方式,即預生成進程模型。分析多進程方式比其他兩種方式開銷大的主要原因,是對每一次客戶請求,都要生成一個子進程以便進行處理,因此為了避免這種開銷,可以使用預先生成的進程來提供服務,并且每個進程在提供一次服務之后也不會立即退出,而是仍然保留在系統中,等待下一次請求。
這里就可以看出,在理想情況下,預先生成的多個進程可以全速回應相應數量的瀏覽器客戶請求,而沒有額外的性能開銷,因此就完全可以和線程或異步方式相媲美。然而在實際運行當中,由于預先生成的進程畢竟要占用系統資源,如系統內存和CPU處理能力,這樣如果預先生成的進程超過需要,性能反而會降低。因此Apache就采用了這樣的一種策略,在系統中保持一定的空閑進程,當空閑進程較少時就自動生成,當空閑進程較多時就讓一些進程退出。
由于Apache采用這樣的預生成進程模型,就導致預先要生成多少進程、保留多少空閑進程、一個進程提供多少次服務等等成為與性能密切相關的問題,然而,這些設置都是與具體條件密切相關的。例如,越多的進程需要占用越多的內存,所分得的CPU處理時間就越少,因此系統的物理內存和CPU處理能力就決定了進程的最大數量。而Apache提供的基本配置是為了適應大多數情況,在客戶請求較少時也不占用過多資源,因此并不是最高性能的設置。而大多數Web服務器測試的條件下,服務器的內存、CPU處理能力都不是問題,甚至內存大到足以將所有要訪問的文檔都可以放在系統緩沖中,因而無須考慮磁盤處理能力,這種情況和實際應用完全不同。因此,SGI的一位開發者通過調整設置,并使用他自己對Apache代碼的一些改動,在同一個SGI Origin 200服務器上使用SPECweb96進行測試,調整后的服務器可以比原始設置提高10倍的速度(),當然這是針對SPECweb96這個測試程序進行的調整,在實際使用中不可能會有這樣巨大的差別。這至少從側面說明了測試結果并不是絕對的。
此外,Apache的另一個特點是它的功能特別豐富,而每種功能通常就需要進行特別的處理,這會影響Apache的性能,然而對于具體的情況,卻不是每種特性都是必要的,因此可以通過減少這些功能來增加性能。此外,操作系統的調整對于增強Apache的性能也是非常重要的。如何根據服務器的實際情況調整操作系統以及Apache的參數,這些內容在Apache的文檔中都有非常詳細的描述。這些文檔包含在每個Apache安裝文件中,也可以直接從它的主頁得到()。
Apache 2.0展望
雖然Apache服務器使用預生成進程的方式提高了服務器的性能,然而,進程方式本身的不足仍然存在,隨著訪問數量的增多,進程方式比其他兩種方式需要消耗更多的內存和CPU處理能力,這就限制了單臺計算機提供更大負載的能力。如果在低端計算機上想服務更多的請求的話,使用異步方式的thttpd更為適合。例如,一臺512MB內存雙CPU的Linux服務器提供1000個并發訪問時,其負載就會變得相當高,常常會由于內存用光而無法運行程序,這種情況是由于Linux重視物理內存,不重視交換空間的原因,如果使用同樣配置的FreeBSD作操作系統,情況會有所改變,然而此時由于需要進行內存交換,就無法達到最優性能了。
因此,這些情況下為了支持更改的負載,完全采用進程方式就不太合適了,而應該利用線程節約資源的優點。
然而,在即將到來的Apache 2.0中,一切都會變得更完美,Apache 2.0將充分考慮到進程帶來的穩定性特征,以及線程帶來高效率的特點。它會預生成多個進程,而每個進程中使用多個線程提供Web服務。由于存在多個進程,即使一個進程死了也不會影響整個Web服務。對于不支持進程的操作系統,如Windows,那么就使用多個線程提供服務,反之也是一樣。然而,只有同時支持線程和進程的操作系統,才能充分利用Apache 2.0帶來的穩定性和高負載能力。
事實上當前的Apache并不是與線程無關,Windows版本的Apache是使用線程的,但按照Apache文檔的說法,Windows版本的Apache性能并不好,主要原因是它在移植過程中是使用的Windows的POSIX子系統,而Windows本身的有些特性效率更高。而在Apache 2.0中,使用了APR(Apache Portable Run-time)特性,這種特性對不同的操作系統提供了一個抽象層,以便Apache能利用Windows的一些非POSIX的特性。
Apache 2.0將是對現在的Apache 1.3版本的一個飛躍,然而,當前它仍然處于Alpha狀態,可以預期,當Apache 2.0正式推出之后,將有更多的用戶接受它。