日期:2004-10-22 人氣:381 出處:http://www.cnfug.org 作者: fei
作者說明:
本文內容基本來自Apache2.0官方文檔,並結合了作者的日常工作經驗。事實上對於任何一項開源技術來說,官方文檔都是最好的技術資料,個人覺得網上90%的技術文檔都可以在官方的技術文檔中找到。不過很多人都沒有意識到這一點,我想這和其中的大多數都沒有中文版本有關。如果你在學習某項技術時遇到了問題,不妨先去其主站看看最新的官方文檔。讓我們一起為開源努力吧。
一談到Apache,相信大多數系統管理員使用的還是其穩定版1.3——雖然2.0系列的開發版早已由Alpha,Beta發展到了現在的GA(General Availability )版,不過大家潛意識裡還是認為開發中的版本並不是可用於生產環境的穩定版本,尤其是1.3的API與2.0的不兼容而使得大量的模塊必須要重寫才能在2.0上用。坦白地說,這種擔心並不是多餘的,Apache1.3和2.0之間的內部變化實在是太大了(這一開發已經歷了5年)。用Apache創始人Brian Behlendorf自己的話來說:「這個版本包括了數百個新的特性,所以這個產品可能應該具有3.1或者8i這樣的產品編號,而不是2.0!」。
在Apache2.0中加入了很多的核心改進和新功能,如Unix線程、多協議支持、新的構建系統、更好的支持非Unix平台、IPv6支持、新的Apache API、過濾器、多語言錯誤響應、原生的Windows NT Unicode支持、更簡單化的配置、以及升級了的正則表達式庫等,當然還包括對許多模塊的重要改進,同時也加入了一些新的模塊。如此多的變化,會使得大多數Apache管理員在剛接觸2.0時會不知所措,筆者也不例外。
不過現在的情況有了很大變化,Apache開發團隊做了很多工作使得從1.3升級到2.0更加平滑,同時很多重要的模塊也已經很好地支持2.0了,如PHP、FastCGI、Mod_perl、Mod_python等。在httpd.conf的指令配置語法上,目前的2.0版本(筆者寫作時是2.0.46)和1.3版本的兼容性已做得相當好了(比如早期的2.0版本如果要使用PHP的話,一般是用過濾器,不過現在的PHP官方文檔中已經使用1.3中的LoadModule語句做為加載PHP的推薦方式)。只要略微瞭解一下2.0的新特性,從1.3升級到2.0就是一件非常容易的事情了。畢竟使用Apache2.0是大勢所趨,而且筆者個人感覺,Apache的開發團隊已經把開發重心轉移到2.0上(1.3自2002年10月發佈了1.3.27後,至今沒有新版本推出,而2.0卻在與1.3.27同時發佈2.0.43後在2003年1月發佈了2.0.44,3月末發佈了2.0.45,5月末發佈了2.0.46,並包含了很多改進和修正)。
儘管Apache2.0在許多方面有了不小的進步,但相信最吸引系統管理員的還是性能上的改善。毫不誇張地說,MPM(Multi-Processing Modules,多道處理模塊)的引入是Apache2.0最重要的變化。大家知道,Apache是基於模塊化的設計,而Apache 2.0更擴展了模塊化設計到web服務器的最基本功能。服務器裝載了一種多道處理模塊,它負責綁定本機網絡端口,接受請求並調度子進程來處理請求。擴展模塊化設計到這個層次有兩個重要好處:
1. Apache可以更簡潔有效地支持多種操作系統;
2. 服務器可以按站點的特殊需要進行自定制。
在用戶級, MPM看起來和其他Apache模塊非常類似。主要區別是在任一時刻只能有一種MPM被裝載到服務器中。
在支持POSIX線程的Unix系統上, Apache現在可以通過不同的MPM運行在一種多進程與多線程相混合的模式下,這就增強了許多(但不是所有)配置的可擴充性能。相比於Apache 1.3, 2.0版本作了大量的優化來提升處理能力和可伸縮性,並且大多數改進在默認狀態下就可以生效。但是我不得不很遺憾的說在FreeBSD上基於線程的產品級MPM worker--還存在著很大的問題。這主要是因為FreeBSD自身的線程庫還遠遠比不上Linux和Solaris成熟。
在我實際的工作中,Linux和Solaris上使用worker MPM都運行得不錯,性能確實有提高,雖然在Linux(Redhat9)上出現過負載突然增大數倍時,Apache線程無法正常工作的情形,但發現主要原因還是配置參數過度優化,並加載了一些有衝突的模塊,並不是Linux系統本身的問題。而Solaris 9 for SPARC是工作得最好的平台,可以完全按照筆者的配置工作,沒有出現任何問題。
下面我以FreeBSD4.8為平台,說明在Apache2.0中如何指定MPM 。先解壓縮源代碼包httpd-2.0.46.tar.gz生成httpd-2.0.46目錄,(BTW:Apache1.3源代碼包的命名規則是apache_1.3.NN.tar.gz,而2.0則是httpd-2.0.NN.tar.gz——其中NN是次版本號)。
進入httpd-2.0.46錄,運行:
./configure --help|grep mpm
會顯示
--with-mpm=MPM Choose the process model for Apache to use.
MPM={beos|worker|prefork|mpmt_os2|perchild|leader|threadpool}
這裡就是用來選擇要使用的進程模型,也就是哪種MPM模塊。beos,mpmt_os2分別是BeOS和OS/2上的缺省MPM,perchild的主要設計目的是以不同的用戶和組的身份來運行不同的子進程,這在運行多個需要CGI的虛擬主機時特別有用,Apache官方文檔說它會比1.3中的SuExec機制做的更好。leader和threadpool都是基於worker的變體,還處於實驗性階段,某些情況下並不會按照預期設想的那樣工作,所以Apache官方也並不推薦使用。( 有關其他的MPM的詳細說明,請參見Apache官方文檔:http://httpd.apache.org/docs-2.0/mod/)。
如果不用--with-mpm顯式指定某種MPM的話,那麼prefork就是Unix平台上的缺省MPM.它所採用的方式是預派生子進程的方式,這事實上也就是Apache1.3中所採用的模式。它本身並沒有使用到線程,2.0使用它是為了與1.3保持兼容性,另一方面,prefork用單獨的子進程來處理不同的請求,進程之間是彼此獨立的,這也使得它成為最穩定的MPM.對比prefork,worker是2.0 中全新的支持多線程和多進程混合模型的MPM。由於使用線程來處理請求,所以,可以處理相對海量的請求,而系統資源的開銷小於基於進程的服務器。但是,它也使用了多進程,每個進程又生成多個線程,以獲得基於進程的服務器的穩定性。筆者認為這種MPM的工作方式將是Apache 2.0以後的發展趨勢。
若使用prefork,在make編譯和make install安裝後,使用httpd –l來確定當前使用的MPM,應該會看到prefork.c(如果看到worker.c就說明使用的是worker MPM,依此類推)
注意:不像在Linux和Solaris,在FreeBSD上用正常方式--with-mpm=worker是無效的!!即使這麼做在安裝後也只能看到prefork.c即prefork模式!!如果你細心的話在configure過程中你會看到
Applying APR hints file rules for i386-unknown-freebsd4.8
setting enable_threads to "no"
APR will be non-threaded
The currently selected MPM requires threads which your system seems to lack
不過這並不說明一定不能在FreeBSD上使用線程,其實在configure時有個未公開的選項--enable-threads ,它在configure --help時是看不到的。顯式加上它就可以以worker MPM來配置編譯Apache2.0了,但是雖然編譯沒有問題,可是Apache起動後根本無法正常工作,瀏覽器會一直等待回應(在FreeBSD4.8,5.1上均不行),個人認為FreeBSD在高端還有很長的路要走,線程,PAE,SMP--雖然5.1有了不小的改進但仍然不是十分完善。
因此,對於FreeBSD來說,prefork幾乎還是目前的唯一MPM,我在下面主要還是討論它的工作原理和相關指令調整。
查看缺省生成的httpd.conf配置文件,會發現裡面包含如下的配置段:
<IfModule prefork.c>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule>
prefork的工作原理是這樣的:控制進程在最初建立StartServers個子進程後, 為了滿足MinSpareServers設置的需要,創建一個進程,等待一秒鐘,繼續創建第二個,等待一秒鐘,繼而創建四個,如此按指數級增加創建的進程數,最多達到每秒32個,直到滿足MinSpareServers設置的值為止,這也就是預派生(prefork)的由來。這種模式可以使得不必在請求到來時再產生新的進程,從而減小了系統開銷以增加性能。
MaxSpareServers 設置了最大的空閒進程數,如果空閒進程數大於這個值,Apache會自動kill某些多餘進程。這個值一般不要設的過大,但如果設的比MinSpareServers小,Apache會自動把它調整為MinSpareServers+1。如果站點負載較大的話,可考慮同時加大MinSpareServers和MaxSpareServers。
MaxRequestsPerChild設置的是每個子進程可以處理的請求數。每個子進程在處理了MaxRequestsPerChild個請求後將自動銷毀。0意味著無限,即子進程永不銷毀。雖然缺省設為0可以使每個子進程處理更多的請求,但如果設成非零值也有兩點重要的好處:
1. 可防止意外的內存卸漏;
2. 在服務器負載下降的時侯會自動減少子進程數。
因此,可根據服務器的負載來調整這個值,如果非零的話,筆者認為10000左右是比較合適的。事實上這個值對Apache的性能影響不是很大。
MaxClients 是這些指令中最為重要的一個,它設定的就是Apache可以同時處理的請求,這是對Apache性能影響最大的參數.在我個人看來,缺省的150是遠遠不夠的,如果請求總數已達到這個值(可通過ps –ef|grep httpd|wc –l來確認),那麼下面的請求就要排隊,直到某個已處理請求完畢。這就是為什麼系統資源還剩下很多,而http訪問卻很慢的主要原因。系統管理員可以根據硬件配置和負載情況來動態調整這個值,雖然理論上這個值越大,可以處理的請求就越多,但Apache默認的限制是不能大於256。如果把這個值設為大於256那麼Apache將無法起動。事實上,256對於負載稍重的站點也是很不夠的。在Apache1.3中這是個硬限制,如果要加大這個值,必須在configure前手工修改源代碼樹下的src/include/httpd.h,查找256,會發現#define HARD_SERVER_LIMIT 256這行,把256改為你要增大的值如4000,然後重新編譯Apache即可。我想這個方法稍有些經驗的Apache系統管理員都知道,不過我相信在Apache2.0中知道如何加大這個值的人就不會太多了。
在Apache2.0中新加入了ServerLimit指令,使得無須重編譯Apache就可以加大MaxClients。下面是筆者的prefork配置段。
<IfModule prefork.c>
StartServers 10
MinSpareServers 10
MaxSpareServers 15
ServerLimit 2000
MaxClients 1500
MaxRequestsPerChild 10000
</IfModule>
BTW: ServerLimit的最大值是20000,這對於大多數站點是足夠了,但如果你一定要再加大的話,那麼這個值位於源代碼樹下的server/mpm/prefork/prefork.c中。裡面的
#define DEFAULT_SERVER_LIMIT 256
#define MAX_SERVER_LIMIT 20000
這兩行就對應著MaxClients和ServerLimit的限制值。但我相信很少有人可以用到20000的並發連接數。
如果你有耐性看完了我這篇文檔,我相信您對Apache2.0 缺省的prefork的工作原理有所熟悉了,理解了它的工作過程後,就可以根據您的實際情況在FreeBSD下來配置Apache相關的核心參數以獲得最大的性能。當然---在Apache2.0中還有不少以功能換取速度的指令,如HostnameLookups等,這就不在本文的敘述範圍裡了,有興趣的讀者可以去看Apache官方文檔,(還有別忘了用strip去掉httpd中的多餘符號,這點很容易被人遺忘,其實會使httpd大小大約減少30-50%!!從而使你的Apache更快!)另外如果您是Linux和Solaris系統管理員,想要使用worker MPM的話,請參見
http://httpd.apache.org/do...worker.html ,還是老話,多看看官方文檔吧。