運行時的配置主要涉及到的相關模塊為:mod_dir、mpm_common、mod_status,涉及到的相關指令為:AllowOverride、HostnameLookups、DirectoryIndex、EnableMMAP、EnableSendfile、KeepAliveTimeout、MaxSpareServers、MinSpareServers、Options、StartServers。

1) AllowOverride

AllowOverride兩種設置All或None,如果網站空間允許覆蓋(通常是用.htaccess文件),則Apache會試圖對文件名的每一個組成部分都打開.htaccess ,例如:

DocumentRoot /www/htdocs

<Directory />

AllowOverride All

</Directory>

如果請求「/index.html」,則Apache會試圖打開「/.htaccess」、「/www/.htaccess」、「/www/htdocs/.htaccess」。為了得到最佳性能,應當對文件系統中所有的地方都使用AllowOverride None設置。

2) HostnameLookups和其它DNS

在Apache1.3以前的版本中,HostnameLookups默認被設為On,這樣會帶來延遲,因為對每一個請求都需要作一次DNS查詢。在Apache2.2中,它被默認地設置為Off。如果需要日誌文件提供主機名信息以生成分析報告,則可以使用日誌後處理程序logresolve,以完成DNS查詢,而客戶端無須等待。

一般情況下應該是在其它的機器上,而不是在web伺服器上執行後處理和其他日誌統計操作,以免影響伺服器的性能。

如果你使用了任何「Allow from domain」或「Deny from domain」指令(也就是domain使用的是主機名而不是IP地址),則代價是要進行兩次DNS查詢(一次正向和一次反向,以確認沒有作假)。所以,為了得到最高的性能,應該避免使用這些指令(不用域名而用IP地址也是可以的)。

注意:可以把這些指令包含在<Location /server-status>段中使之局部化。在這種情況下,只有對這個區域的請求才會發生DNS查詢。下例禁止除了.html和.cgi以外的所有DNS查詢:

HostnameLookups off

<Files ~ ".(html|cgi)$">

HostnameLookups on

</Files>

如果在某些CGI中偶爾需要DNS名稱,則可以調用gethostbyname來解決。

3) FollowSymLinks和SymLinksIfOwnerMatch

如果網站空間中沒有使用Options FollowSymLinks,或使用了 Options SymLinksIfOwnerMatch ,Apache就必須執行額外的系統調用以驗證符號連接。文件名的每一個組成部分都需要一個額外的調用。例如,如果設置了:

DocumentRoot /www/htdocs

<Directory />

Options SymLinksIfOwnerMatch

</Directory>

在請求「/index.html」時,Apache將對「/www」、「/www/htdocs」、「/www/htdocs/index.html」執行lstat()調用,而且lstat()的執行結果不被緩存,因此對每一個請求都要執行一次,如果確實需要驗證符號連接的安全性,則可以這樣:

DocumentRoot /www/htdocs

<Directory />

Options FollowSymLinks

</Directory>

<Directory /www/htdocs>

Options -FollowSymLinks +SymLinksIfOwnerMatch

</Directory>

這樣,至少可以避免對DocumentRoot路徑的多餘的驗證。

注意:如果Alias或RewriteRule中含有DocumentRoot以外的路徑,那麼同樣需要增加這樣的段。為了得到最佳性能,應當放棄對符號連接的保護,在所有地方都設置FollowSymLinks ,並放棄使用SymLinksIfOwnerMatch。

4) 內容協商(Content Negotiation)

一個資源可能會有多種不同的表現形式,比如,可能會有不同語言或者媒體類型的版本甚至其組合。最常用的選擇方法是提供一個索引頁以供選擇。但是由於瀏覽器可以在請求頭信息中提供其首選項的表現形式,因此就有可能讓伺服器進行自動選擇。比如,瀏覽器可以表明希望看見法語的信息,如果沒有,英語的也行。如需僅請求法語的表現形式,瀏覽器可以發出:

Accept-Language: fr

注意:此首選項信息僅當存在多種可選的語言表現形式時纔有效。

下面是一個更複雜的請求,瀏覽器表明,可以接受法語和英語,但最好是法語;接受各種媒體類型,最好是HTML,但純文件或其他文本類型也可以;最好是GIF或JPEG,但其他媒體類型也可以,並允許其他媒體類型作為最終表現形式:

Accept-Language: fr; q=1.0, en; q=0.5

Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1

Apache支持HTTP/1.1規範中定義的「伺服器驅動」的內容協商, 可以完全地支持Accept、Accept-Language、Accept-Charset、Accept-Encoding請求頭,這些是RFC2295和RFC2296中定義的實驗協商協議,但是不支持這些RFC中定義的「功能協商」。

資源(resource)是一個在URI(RFC2396)中定義的概念上的實體,一個HTTP伺服器,比如Apache,以表現形式(representation)提供對其命名空間中資源的訪問,各種表現形式由已定義的媒體類型、字符集和編碼的位元組流構成。任何一個特定的時刻,一個資源可以沒有,或者有一個,或者有多個表現形式。如果有多個表現形式存在,則稱該資源是可協商的(negotiable),其各種表現形式稱為變種(variant),而一個可協商的資源的各種變種的區別途徑稱為變元(dimension)。

可以使用下述兩種途徑之一向伺服器提供有關各變種的信息,以實現對資源的協商:

? 使用類型表(也就是一個 *.var文件)明確指定各變種的文件名。

? 使用「MultiViews」搜索,即伺服器執行一個隱含的文件名模式匹配,並在其結果中選擇。

使用類型表文件

類型表是一個與type-map處理器關聯的文檔(或者兼容早期Apache配置的MIME類型:application/x-type-map),要使用這個功能,必須在配置中建立處理器,以定義一個文件後綴為type-map,最好的方法是在配置文件中這樣設置:

AddHandler type-map .var

類型表文件應該與所描述的資源同名,且對每個有效變種都有一個塊(entry),每個塊由若干連續的HTTP頭行組成,不同變種的塊用空行分開,塊中不允許有空行,通常類型表都以一個描述總體性質的組合塊作為開始(這不是必須的,如果有也會被忽略)。下例是一個描述資源foo的命名為foo.var的類型表文件:

URI: foo

URI: foo.en.html

Content-type: text/html

Content-language: en

URI: foo.fr.de.html

Content-type: text/html;charset=iso-8859-2

Content-language: fr, de

注意:即使將MultiViews設置為On ,類型表仍然優先於文件後綴名,如果不同的變種具有不同的資源品質,就可以對媒體類型使用「qs」參數來表示這種不同。實例:一個圖片的jpeg、gif、ASCII-art三個有效變種:

URI: foo

URI: foo.jpeg

Content-type: image/jpeg; qs=0.8

URI: foo.gif

Content-type: image/gif; qs=0.5

URI: foo.txt

Content-type: text/plain; qs=0.01

qs的取值範圍是0.000到1.000,取值為0.000的變種永遠不會被選擇,沒有指定qs值的變種其qs值為1.0。qs值表示一個變種相對於其他變種的"品質",比如在表現一張照片時,jpeg通常比字元構圖有更高的品質;而如果要表現的本來就是一個ASCII-art ,那麼當然字元構圖就會比jpeg文件有更高的品質。因此,qs的值取決於變種所表現的資源本身。mod_negotation類型表文檔中有完整的HTTP頭的列表。

Multiviews

MultiViews是一個針對每個目錄的選項,也就是說可以在httpd.conf或.htaccess(如果正確設置了AllowOverride)文件中的<Directory>、<Location>、<Files>配置段中,用Options指令來指定。注意,Options All並不會設置MultiViews,你必須明確地指定。

MultiViews的效果是:如果伺服器收到對/some/dir/foo的請求,而/some/dir/foo並不存在,但是如果/some/dir啟用了MultiViews,則伺服器會查找這個目錄下所有的foo.* 文件,並有效地偽造一個說明這些foo.* 文件的類型表,分配給他們相同的媒體類型及內容編碼,並選擇其中最合適的匹配返回給客戶。

MultiViews還可以在伺服器檢索一個目錄時,用於DirectoryIndex指令搜索的文件名。如果設置了:

DirectoryIndex index

而index.html和index.html3並存,則伺服器會作一個權衡;如果都沒有,但是有index.cgi,則伺服器會執行它。

如果一個目錄中沒有任何文件具有mod_mime可以識別的表示其字符集、內容類型、語言和編碼的後綴,那麼其結果將取決於MultiViewsMatch指令的設置,這個指令決定了在MultiViews協商中將使用的處理器、過濾器和其他後綴類型。

實踐中,內容協商的好處大於性能的損失,如果你很在意那一點點的性能損失,則可以禁止使用內容協商。但是仍然有個方法可以提高伺服器的速度,就是不要使用通配符,如:

DirectoryIndex index.*

而使用完整的列表,如:

DirectoryIndex index.cgi index.pl index.shtml index.html

其中最常用的應該放在前面。

還有,建立一個明確的type-map文件在性能上優於使用「Options MultiViews」,因為所有需要的信息都在一個單獨的文件中,而無須搜索目錄。請參考內容協商文檔以獲得更詳細的協商方法和創建type-map文件的指導。

5) 內存映射

在Apache2.2需要搜索被發送文件的內容時,比如處理伺服器端包含時,如果操作系統支持某種形式的mmap(),則會對此文件執行內存映射。在某些平臺上,內存映射可以提高性能,但是在某些情況下,內存映射會降低性能甚至影響到httpd的穩定性:

? 在某些操作系統中,如果增加了CPU,mmap還不如read()迅速。比如,在多處理器的Solaris伺服器上,關閉了mmap,Apache2.0傳送服務端解析文件有時候反而更快。

? 如果對作為NFS裝載的文件系統中的一個文件進行了內存映射,而另一個NFS客戶端的進程刪除或者截斷了這個文件,那麼進程在下一次訪問已經被映射的文件內容時,會產生一個匯流排錯誤。

如果有上述情況發生,則應該使用EnableMMAP off 關閉對發送文件的內存映射。注意:此指令可以被針對目錄的設置覆蓋。

6) Sendfile

在Apache2.2能夠忽略將要被發送的文件內容時(比如發送靜態內容),如果操作系統支持sendfile() ,則Apache將使用內核提供的sendfile()來發送文件。

在大多數平臺上,使用sendfile可以通過免除分離的讀和寫操作來提升性能,然而在某些情況下,使用sendfile會危害到httpd的穩定性

? 一些平臺可能會有Apache編譯系統檢測不到的有缺陷的sendfile支持,特別是將在其他平臺上使用交叉編譯得到的二進位文件運行於當前對sendfile支持有缺陷的平臺時。

? 對於一個掛載了NFS文件系統的內核,它可能無法可靠的通過自己的cache服務於網路文件。

如果出現以上情況,應使用「EnableSendfile off」來禁用sendfile。注意,這個指令可以被針對目錄的設置覆蓋。

7) 進程的建立

在Apache1.3以前,MinSpareServers、MaxSpareServers、StartServers的設置對性能都有很大的影響。尤其是為了應對負載而建立足夠的子進程時,Apache需要有一個「漸進」的過程,在最初建立StartServers數量的子進程後,為了滿足MinSpareServers設置的需要,每一秒鐘只能建立一個子進程。所以,對一個需要同時處理100個客戶端的伺服器,如果StartServers使用默認的設置5,則為了應對負載而建立足夠多的子進程需要95秒。在實際應用中,如果不頻繁重新啟動伺服器,這樣還可以,但是如果為了提供10分鐘的服務,這樣就很糟糕了。

「一秒鐘一個」的規定是為了避免在創建子進程過程中伺服器對請求的響應停頓,但是它對伺服器性能的影響太大了,必須予以改變,在 Apache1.3中,這個「一秒鐘一個」的規定變得寬鬆了,創建一個進程,等待一秒鐘,繼續創建第二個,再等待一秒鐘,繼而創建四個,如此按指數級增加 創建的進程數,最多達到每秒32個,直到滿足MinSpareServers設置的值為止。

從多數反映看來,似乎沒有必要調整MinSpareServers、MaxSpareServers、StartServers 。如果每秒鐘創建的進程數超過4個,則會在ErrorLog中產生一條消息,如果產生大量此消息,則可以考慮修改這些設置,可以使用mod_status的輸出作為參考。

與進程創建相關的是由MaxRequestsPerChild引發的進程的銷毀。其默認值是「0」,意味著每個進程所處理的請求數是不受限制的。如果此值設置得很小,比如30,則可能需要大幅增加。在SunOS或者Solaris的早期版本上,其最大值為10000以免內存泄漏。

如果啟用了持久鏈接,子進程將保持忙碌狀態以等待被打開連接上的新請求,為了最小化其負面影響,KeepAliveTimeout的默認值被設置為5秒,以謀求網路帶寬和伺服器資源之間的平衡,在任何情況下此值都不應當大於60秒。


推薦閱讀:
查看原文 >>
相關文章