<-
Apache > HTTP伺服器 > 文件 > 版本 2.4 > 雜項文件

Apache效能最佳化

可用的語言:  en  |  fr  |  ko  |  tr 

Apache 2.x 是一款通用網頁伺服器,專門提供靈活性、可攜性與效能的平衡。儘管並未特別設計為設定基準紀錄,但 Apache 2.x 仍可在許多實際情況下達到高水準的效能。

與 Apache 1.3 相較,2.x 版本包含許多額外的最佳化功能,用以增加傳輸量和可擴充性。這些改善功能大部分都已納入預設值。然而,仍有編譯時間和執行時期的組態選項可能大幅影響效能。本文說明伺服器管理員可設定哪些選項,以調整 Apache 2.x 安裝的效能。這些組態設定選項中有一些能讓 httpd 更有效地利用硬體和作業系統的功能,而另一些則讓管理員能夠捨棄某些功能以換取更快的速度。

Support Apache!

另請參閱

top

硬體和作業系統問題

影響網頁伺服器效能最大的硬體問題是 RAM。網頁伺服器不應該進行換頁,因為換頁會將每個要求的延遲時間增加到使用者認為「夠快」的程度以上。這會導致使用者停止並重新載入,進而進一步增加負載。您可以,而且應該控制 MaxRequestWorkers 設定,讓您的伺服器不再產生那麼多子程序而開始換頁。這樣做的步驟很簡單:透過像是 top 的工具檢視您的程序清單,找出 Apache 程序的平均大小,並將這個數字除以您的總可用記憶體,並為其他程序留下一些空間。

除此以外,其他的事項都屬於例行事項:取得足夠快的 CPU、足夠快的網路卡和足夠快的磁碟機,而「足夠快」的定義則需要靠實驗來確認。

作業系統的選擇在很大程度上取決於個別情況。但有一些已證實普遍適用的大原則:

top

執行階段設定問題

HostnameLookups 與其他 DNS 考量

在 Apache 1.3 之前,HostnameLookups 採用預設 On。由於此設定在要求完成之前,需要執行 DNS 查詢功能,因此會為每個要求增加延遲。在 Apache 1.3 中,此設定已預設為 Off。如果您需要將記錄檔中的位址解析為主機名稱,請使用 Apache 附帶的 logresolve 程式,或任何一種可用的多種記錄報告套件。

建議您在生產用網路伺服器機器以外的機器上做此類記錄檔後處理,避免該活動對伺服器效能造成負面影響。

如果您使用任何 Allow 的 domainDeny 的 domain 指令(也就是使用主機名稱或網域名稱,而非 IP 位址),您會需要執行兩次 DNS 查詢(反向查詢,接著是正向查詢,確認反向查詢未偽造)。因此,如果您能使用 IP 位址,而非名稱,則使用這些指令時,就能獲得最佳效能。

請注意,可以設定指令範圍,例如在 <Location "/server-status"> 中。在這種情況下,DNS 查詢只會執行在符合條件的要求上。以下是只針對 .html.cgi 檔案停用查詢的範例:

HostnameLookups off
<Files ~ "\.(html|cgi)$">
  HostnameLookups on
</Files>

但是,即使如此,如果您只需要某些 CGI 中的 DNS 名稱,您可以考慮在需要它的特定 CGI 中執行 gethostbyname 呼叫。

FollowSymLinks 和 SymLinksIfOwnerMatch

在您的 URL 空間中,如果任何地方沒有 Options FollowSymLinks,或您有 Options SymLinksIfOwnerMatch,Apache 就必須發出額外的系統呼叫來檢查符號連結。(針對每一個檔案名稱元件發出一個額外的呼叫)例如,如果您有:

DocumentRoot "/www/htdocs"
<Directory "/">
  Options SymLinksIfOwnerMatch
</Directory>

並對 URI /index.html 提出要求,接著 Apache 會對 /www/www/htdocs/www/htdocs/index.html 執行 lstat(2)。這些 lstat 的結果從未快取,因此它們會發生在每個單一要求上。如果您真的想要符號連結安全檢查,您可以執行類似以下動作

DocumentRoot "/www/htdocs"
<Directory "/">
  Options FollowSymLinks
</Directory>

<Directory "/www/htdocs">
  Options -FollowSymLinks +SymLinksIfOwnerMatch
</Directory>

至少可以避免針對 DocumentRoot 路徑的額外檢查。請注意,如果您在文檔根目錄外有任何 AliasRewriteRule 路徑,您需要新增類似的區段。為了獲得最高的效能,且沒有符號連結保護,請在所有位置設定 FollowSymLinks,而且不要設定 SymLinksIfOwnerMatch

AllowOverride

在 URL 空間中允許覆寫的地方(通常是 .htaccess 檔案),Apache 會嘗試為每個檔案名稱元件開啟 .htaccess。例如,

DocumentRoot "/www/htdocs"
<Directory "/">
  AllowOverride all
</Directory>

並對 URI /index.html 提出要求。接著 Apache 會嘗試開啟 /.htaccess/www/.htaccess/www/htdocs/.htaccess。解決方案類似於先前的 Options FollowSymLinks 案例。要獲得最高的效能,請在檔案系統中的每個位置使用 AllowOverride None

協商

如果真的對最後一滴效能感興趣,請儘可能避免內容協商。實際上,協商的好處大於效能罰則。有一個案例,您可以在其中加速伺服器。不要使用萬用字元,例如

DirectoryIndex index

使用完整的選項清單

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

在其中把最常見的選項列在第一位。

另外請注意,與使用 MultiViews 相較,明確建立 type-map 檔案能提供更好的效能,因為不需要掃描目錄的檔案,只要讀取這個單一檔案就能夠判斷必要的資料。

如果您的網站需要內容協商,請考慮使用 type-map 檔案,而不是 Options MultiViews 指令來達成協商。請參閱 內容協商 文件,以取得協商方法的完整說明和建立 type-map 檔案的說明。

記憶體對應

在 Apache 2.x 需要檢視正在傳遞檔案的內容的情況下——例如,在進行伺服器端包含處理時——如果作業系統支援某種形式的 mmap(2),它通常會將檔案記憶體對應。

在某些平台上,這個記憶體對應會改善效能。但是,在某些情況下,記憶體對應會損害 httpd 的效能,甚至穩定性。

對於這兩種因素都適用的安裝,您應使用 EnableMMAP off 停用已傳送檔案的記憶體對應。(註:該指令可以個別針對目錄覆寫。)

Sendfile

在 Apache 2.x 可以忽略要傳送檔案的內容的情況中,例如,傳送靜態檔案內容時,如果作業系統支援 sendfile(2) 操作,它通常會對該檔案使用 kernel sendfile 支援。

在大多數平台上,使用 sendfile 可透過消除單獨的讀取與傳送機制來改善效能。但是,有一些情況會造成使用 sendfile 會損害 httpd 的穩定性。

對於這兩種因素都適用的安裝,您應使用 EnableSendfile off 停用 sendfile 傳送檔案內容。(註:該指令可以個別針對目錄覆寫。)

處理程序建立

在 Apache 1.3 之前,MinSpareServersMaxSpareServersStartServers 設定都會對基準測試結果產生巨大的影響。特別是,Apache 需要一個「引導」期間才能達到足夠的子程序,以傳送所套用的負載。在最初產生 StartServers 子程序後,每秒只會產生一個子程序滿足 MinSpareServers 設定。因此,由 100 個同時用戶端存取的伺服器使用預設 StartServers5 會花費約 95 秒的時間產生足夠的子程序來處理負載。這在實際的伺服器上運作良好,因為不會頻繁重新啟動。但對於只有十分鐘運作時間的基準測試來說,表現很差。

每秒一個規則是為了避免透過啟動新的子程序來淹沒機器。如果機器忙於產生子程序,它無法為要求提供服務。但它對 Apache 所感知的效能有如此重大的影響,它不得不被更換。從 Apache 1.3 開始,程式碼會放寬每秒一個的規則。它會產生一個,等待一秒,然後產生兩個,等待一秒,再產生四個,並且會持續呈指數成長,直到它每秒產生 32 個子程序。滿足 MinSpareServers 設定後,它就會停止。

похоже, он и так достаточно отзывчивый, поэтому не нужно постоянно подстраивать MinSpareServers, MaxSpareServers и StartServers. Если за секунду создается больше 4 дочерних элементов, то выводится сообщение в ErrorLog. Если вы видите много таких ошибок, подумайте о настройке этих параметров. Используйте в качестве руководства вывод mod_status.

К созданию процессов относится также и завершение процессов, которое вызвано параметром MaxConnectionsPerChild. По умолчанию это значение равно 0, а это значит, что нет ограничений на количество обрабатываемых соединений на дочерний элемент. Если в вашей конфигурации этот параметр в настоящее время установлен на очень низкое число, например 30, вы можете смело значительно его повысить. Если вы используете SunOS или старую версию Solaris, ограничьте число, приблизительно до 10000 из-за потерь памяти.

Когда используются сохраняемые соединения, дочерние элементы будут заняты простаиванием и ожиданием новых запросов на уже открытом соединении. Значение по умолчанию KeepAliveTimeout равно 5 секундам, это значение призвано минимизировать такой эффект. Придется искать компромисс между сетевой пропускной способностью и ресурсами сервера. Ни в коем случае не устанавливайте значение больше приблизительно 60 секунд, т. к. практически вся выгода теряется.

top

Проблемы с настройкой времени компиляции

Выбор MPM

Apache 2.x поддерживает модули взаимодействия с несколькими потоками, которые называются модулями многопроцессорной обработки (MPM). При сборке Apache вы должны выбрать, какой MPM будет использоваться. Существуют MPM для конкретных платформ: mpm_netware, mpmt_os2 и mpm_winnt. Для общих систем типа Unix имеется несколько MPM, из которых можно выбирать. Выбор MPM может влиять на скорость и масштабируемость httpd

如需取得這些及其他 MPM 的更多資訊,請參閱 MPM 文件

模組

由於記憶體使用量是效能最重要的考量因素,因此您應該嘗試移除實際上未使用的模組。如果您已將模組建置為 DSO,移除模組只是一個將該模組的相關 LoadModule 指令註解掉的問題。這樣可以讓您嘗試移除模組,看看您的網站是否還能在沒有該模組的情況下運作。

反之,如果您已將模組靜態連結到您的 Apache 二進位檔,則必須重新編譯 Apache 才能移除不需要的模組。

這裡出現了一個相關問題,當然,哪些模組是您需要的,哪些不是。答案會依不同的網站而有所不同。然而,您能運作的最小模組清單通常會包含 mod_mimemod_dirmod_log_config。當然,`mod_log_config` 是可選的,因為您可以執行沒有記錄檔案的網站。然而,這不建議這麼做。

原子操作

某些模組,例如 mod_cache 和工人 MPM 的最新開發版本,使用 APR 的原子 API。此 API 提供可供輕量級執行緒同步使用的原子操作。

預設情況下,APR 會使用每個目標作業系統 / CPU 平台上可用的最有效率的機制來實作這些操作。例如,許多現代 CPU 都有一個在硬體中執行原子比較與交換 (CAS) 作業的指令。然而,在某些平台上,APR 預設會改用速度較慢、基於互斥鎖的原子 API 實作,以確保與缺乏此類指令的舊 CPU 型號相容。如果您要為這些平台之一建置 Apache,且您計畫只在較新的 CPU 上執行,您可以在建置時設定 Apache,並使用 `--enable-nonportable-atomics` 選項選擇一個較快的原子實作

./buildconf
./configure --with-mpm=worker --enable-nonportable-atomics=yes

以下平台適用 `--enable-nonportable-atomics` 選項

mod_status 及 ExtendedStatus 開啟

如果你包含 mod_status,且你在建置及執行 Apache 時設定 ExtendedStatus On,那麼在每個要求中,Apache 會針對 gettimeofday(2)(或視你的作業系統而定的 times(2))執行兩次呼叫,以及(在 1.3 版之前)針對 time(2) 執行多次額外呼叫。這些動作都是為了讓狀態報告包含時間指示。為獲得最高的效能,請設定 ExtendedStatus off(這是預設值)。

驗收序列化 - 多重 Socket

警告

本小節尚未針對 Apache HTTP Server 2.x 版本中所做的變更進行完全更新。部分資訊可能仍然相關,但請小心使用。

以下討論 Unix socket API 的一個缺點。假設你的網路伺服器使用多個 Listen 陳述式在多個埠口或多個位址上進行監聽。為了測試每個 socket 以查看是否有準備好的連線,Apache 會使用 select(2)select(2) 指示 socket 中有至少一個正在等待的連線。Apache 的模型包括多個子處理序,所有閒置的子處理序都會同時測試新的連線。一個簡陋的實作類似以下(此範例不符合程式碼,為了教學目的而構思):

        for (;;) {
          for (;;) {
            fd_set accept_fds;

            FD_ZERO (&accept_fds);
            for (i = first_socket; i <= last_socket; ++i) {
              FD_SET (i, &accept_fds);
            }
            rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
            if (rc < 1) continue;
            new_connection = -1;
            for (i = first_socket; i <= last_socket; ++i) {
              if (FD_ISSET (i, &accept_fds)) {
                new_connection = accept (i, NULL, NULL);
                if (new_connection != -1) break;
              }
            }
            if (new_connection != -1) break;
          }
          process_the(new_connection);
        }

但這個簡陋的實作有嚴重的飢餓問題。請回想,多個子處理序會同時執行這個迴圈,因此當它們在要求間時,多個子處理序會在 select 中封鎖。當任何 socket 上出現單一要求時,所有那些封鎖的子處理序會喚醒並從 select 返回。(喚醒的子處理序數量會視作業系統及時間問題而有所不同。)然後,它們都會進入迴圈,並嘗試「驗收」連線。但只有一個會成功(假設依然只有一個連線準備好)。其餘會在 accept封鎖。這有效地將那些子處理序鎖定為只為該一個 socket 提供要求,而不是其他 socket,而且它們會在那裏陷住,直到該 socket 上出現足夠新的要求將它們全部喚醒為止。這個飢餓問題最早記錄在 PR#467 中。至少有兩種解決方案。

解決方法之一是建立非封鎖式 soket。如此一來,accept 將不會封鎖子程序,且子程序能繼續立即執行。但這會造成浪費 CPU 時間。假設你在 select 中有 10 個閒置子程序,並且有一個連線進入。那這 9 個子程序會喚醒、嘗試以 accept 接受連線、失敗,並迴圈返回 select,最終一事無成。同時,在這些子程序回到 select 之前,沒有任何子程序會處理其他 soket 產生的要求。總體而言,除非你有與閒置子程序數量一樣多的閒置 CPU (在多處理器環境中)(這不太可能發生),否則這項解決方法似乎不太有效。

另一項解決方法,即 Apache 使用的方法,是讓內部迴圈串列化進入。迴圈如下所示 (差異已標示)

        for (;;) {
          accept_mutex_on ();
          for (;;) {
            fd_set accept_fds;
            
            FD_ZERO (&accept_fds);
            for (i = first_socket; i <= last_socket; ++i) {
              FD_SET (i, &accept_fds);
            }
            rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
            if (rc < 1) continue;
            new_connection = -1;
            for (i = first_socket; i <= last_socket; ++i) {
              if (FD_ISSET (i, &accept_fds)) {
                new_connection = accept (i, NULL, NULL);
                if (new_connection != -1) break;
              }
            }
            if (new_connection != -1) break;
          }
          accept_mutex_off ();
          process the new_connection;
        }

函數 accept_mutex_onaccept_mutex_off 實作一個互斥鎖。任何時間內只有一個子程序可以擁有互斥鎖。有數種方法可實作這些互斥鎖。可以在 src/conf.h (1.3 之前) 或 src/include/ap_config.h (1.3 或更新版本) 中定義選擇項目。有些架構沒有任何鎖定選項,在這些架構上,不建議使用多個 Listen 指令。

Mutex 指令可用於在執行階段變更 mpm-accept 互斥鎖的互斥鎖實作。有關不同互斥鎖實作方式的特殊考量,會記錄在該指令中。

曾考慮過但未實作的另一項解決方法,是讓迴圈部分串列化,也就是說,讓一定數量的程序進入。這僅適用於多處理器環境,在多處理器環境中,有可能會有多個子程序同時執行,而串列化實際上不會完全利用頻寬。這是未來可以探討的領域,但優先順序較低,因為高並行網路伺服器並非常態。

如果您想要達到最高效能,理想狀況下,你應執行沒有多個 Listen 陳述式的伺服器。但請繼續往下讀。

接受串列化 - 單一 soket

上述說明完全適用於多 soket 伺服器,但單一 soket 伺服器呢?理論上,他們不應遭遇這些問題,因為所有的子程序都可以在 accept(2) 中封鎖,直到連線進入,而且不會造成執行緒飢餓。在實際狀況中,這幾乎會出現與上述非封鎖式解決方法中所探討的「旋轉」行為相同的情形。在大部分 TCP 堆疊的實作方式中,當單一連線進入時,內核實際上會喚醒所有封鎖在 accept 中的程序。其中一個程序取得連線並返回使用者空間。其餘的程序則會在內核中旋轉,並在發現沒有連線時重新進入睡眠狀態。這個旋轉的過程會隱藏在使用空間的程式碼中,但它確實存在。這可能造成與非封鎖式解決方案套用在多 soket 案例中時相同的高負載浪費行為。

因為這個原因,我們發現,如果我們序列化,甚至連單一 socket 案例都可以得到許多架構更「精良」的表現。因此,這實際上幾乎在所有案例中都是預設值。在 Linux (雙處理器 Pentium 專業版 166 w/128Mb RAM 上的 2.0.30) 上的粗糙實驗顯示,序列化單一 socket 案例會造成每秒要求在未序列化單一 socket 上減少不到 3%。但未序列化的單一 socket 在每個要求上顯示額外的 100ms 延遲。這個延遲在長途路徑線上很可能是失效的,只會在 LAN 上發生問題。如果你想要覆寫單一 socket 序列化,你可以定義 SINGLE_LISTEN_UNSERIALIZED_ACCEPT,然後單一 socket 伺服器將完全不執行序列化。

持續關閉

正如 draft-ietf-http-connection-00.txt 第 8 節所討論的,為了讓 HTTP 伺服器能可靠地執行通訊協定,它需要獨立地關閉每個溝通方向。(請記得 TCP 連線是雙向的。每個一半都獨立於另一個。)

當此功能新增至 Apache,它因為短視而造成各種版本 Unix 上出現一系列的問題。TCP 規格沒有指出 FIN_WAIT_2 狀態具有逾時,但沒有禁止它。在沒有逾時的系統上,Apache 1.2 導致許多 socket 永久停留在 FIN_WAIT_2 狀態。在許多案例中,可以透過簡單升級至供應商提供的最新 TCP/IP 修補程式來避免此問題。在供應商從未發布修補程式的案例中 ( SunOS4 -- 雖然持有原始程式碼授權的人員可以自行修補),我們決定停用此功能。

有兩種方式可以達成此目的。第一個是 socket 選項 SO_LINGER。但是事與願違,這從未在大多數 TCP/IP 堆疊中正確執行。甚至在使用正確執行的堆疊 ( Linux 2.0.31) 上,此方法證明比下一個解決方案更昂貴 (CPU 時間)。

Apache 主要在稱為 lingering_close 的函數 (位於 http_main.c 中) 中執行此函數。該函數大致如下

        void lingering_close (int s)
        {
          char junk_buffer[2048];
          
          /* shutdown the sending side */
          shutdown (s, 1);

          signal (SIGALRM, lingering_death);
          alarm (30);

          for (;;) {
            select (s for reading, 2 second timeout);
            if (error) break;
            if (s is ready for reading) {
              if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {
                break;
              }
              /* just toss away whatever is here */
            }
          }
          
          close (s);
        }

這自然會在連線結束時增加一些花費,但如果要可靠地執行,這是必要的。隨著 HTTP/1.1 變得更普遍,並且所有連線都一致持續,此花費將攤銷在更多要求上。如果你想玩火並停用此功能,你可以定義 NO_LINGCLOSE,但這完全不建議這麼做。特別是,由於 HTTP/1.1 管線持續連線開始使用,lingering_close 絕對必要 (而且 管線連線較快,因此您需要支援它。)

記分板檔案

Apache 的父代及子代會透過稱為計分板的東西互相溝通。理想情況下,這部分應以共用記憶體來執行。對於我們有權限使用或已收到詳細埠的作業系統,通常會透過共用記憶體來執行。其餘的則預設使用磁碟上的檔案。磁碟上的檔案不僅速度慢,而且不可靠(且功能較少)。檢閱架構的 src/main/conf.h 檔案,並尋找 USE_MMAP_SCOREBOARDUSE_SHMGET_SCOREBOARD。定義這兩個其中一個(及其伴隨的 HAVE_MMAPHAVE_SHMGET)便能啟用已提供的共用記憶體程式碼。如果你的系統有其他類型的共用記憶體,歡迎編輯檔案 src/main/http_main.c,並加入必要掛接,以供 Apache 使用。(請也再寄還我們一個修補程式。)

歷史備注:Linux 的 Apache 埠直到 Apache 的版本 1.2 才開始使用共用記憶體。這項疏忽導致早期版本 Apache 在 Linux 上的表現極差且不穩定。

DYNAMIC_MODULE_LIMIT

如果你無意使用動態載入模組(如果你正在閱讀這篇文章且針對伺服器的每一點效能進行調整,則你可能不會),那麼你應該在建置你的伺服器時加入 -DDYNAMIC_MODULE_LIMIT=0。這將節省僅分配給支援動態載入模組的 RAM。

top

附錄:追蹤的詳細分析

以下是使用 Solaris 8 上的 worker MPM,執行 Apache 2.0.38 產生的系統呼叫追蹤。此追蹤使用

truss -l -p httpd_child_pid.

-l 選項會指示 truss 記錄呼叫每個系統呼叫的 LWP (輕量級程序,即 Solaris 型式的核心層級執行緒) 的 ID。

其他系統可能有不同的系統呼叫追蹤工具程式,例如 stracektracepar。它們都會產生類似的輸出。

在此追蹤中,客戶端已從 httpd 要求一個 10 KB 的靜態檔案。非靜態要求或要求內容協商的追蹤看起來截然不同(某些案例中非常醜陋)。

/67:    accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
/67:    accept(3, 0x00200BEC, 0x00200C0C, 1)            = 9

在此追蹤中,聆聽器執行緒正在 LWP #67 中執行。

請注意,沒有 accept(2) 串行化。在此特定平台上,除非 worker MPM 聆聽多個埠,否則它預設會使用非串行化 accept。
/65:    lwp_park(0x00000000, 0)                         = 0
/67:    lwp_unpark(65, 1)                               = 0

在接受連線後,聆聽器執行緒會喚醒一個工作執行緒來執行要求處理。在此追蹤中,處理要求的工作執行緒會對應到 LWP #65。

/65:    getsockname(9, 0x00200BA4, 0x00200BC4, 1)       = 0

為了執行虛擬主機,Apache 需要知道用於接受連線的區域 socket 位址。在許多情況下可以避免此呼叫(例如,當沒有虛擬主機,或使用不具有萬用字元位址的 Listen 指令時)。但目前尚未進行任何努力來執行這些最佳化。

/65:    brk(0x002170E8)                                 = 0
/65:    brk(0x002190E8)                                 = 0

brk(2) 呼叫會配置堆疊記憶體。在系統呼叫追蹤中,這種情況很少見,因為 httpd 在大部分的處理中使用自訂記憶體配置器(apr_poolapr_bucket_alloc)。在此追蹤中,httpd 剛啟動,因此必須呼叫 malloc(3) 來取得必要的原始記憶體區塊,以便建立自訂記憶體配置器。

/65:    fcntl(9, F_GETFL, 0x00000000)                   = 2
/65:    fstat64(9, 0xFAF7B818)                          = 0
/65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
/65:    fstat64(9, 0xFAF7B818)                          = 0
/65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
/65:    setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
/65:    fcntl(9, F_SETFL, 0x00000082)                   = 0

接下來,工作執行緒將與用戶端的連線(檔案描述符 9)設定為非封鎖模式。setsockopt(2)getsockopt(2) 呼叫是 Solaris 的 libc 處理 socket 上的 fcntl(2) 之副作用。

/65:    read(9, " G E T   / 1 0 k . h t m".., 8000)     = 97

工作執行緒從用戶端讀取要求。

/65:    stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
/65:    open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10

此 httpd 已設定為 Options FollowSymLinksAllowOverride None。因此,它不需要lstat(2) 通往請求檔案路徑中的每個目錄,也不需要檢查 .htaccess 檔案。它只需呼叫 stat(2) 來驗證檔案,確認符合下列條件:1) 檔案存在,2) 檔案是常規檔案,而不是目錄。

/65:    sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C)      = 10269

在此範例中,httpd 能夠使用單一 sendfilev(2) 系統呼叫送出 HTTP 回應標頭與請求的檔案。不同作業系統的 Sendfile 語意不同。某些其他系統需要執行 write(2)writev(2) 呼叫才能在呼叫 sendfile(2) 之前送出標頭。

/65:    write(4, " 1 2 7 . 0 . 0 . 1   -  ".., 78)      = 78

write(2) 呼叫會在存取記錄中記錄請求。請注意,此追蹤中缺少 time(2) 呼叫。與 Apache 1.3 不同,Apache 2.x 使用 gettimeofday(3) 來查詢時間。在某些作業系統(例如 Linux 或 Solaris)中,gettimeofday 具有最佳化實作,其必須具有的時間成本低於一般的系統呼叫。

/65:    shutdown(9, 1, 1)                               = 0
/65:    poll(0xFAF7B980, 1, 2000)                       = 1
/65:    read(9, 0xFAF7BC20, 512)                        = 0
/65:    close(9)                                        = 0

工作執行緒執行連線的延遲關閉。

/65:    close(10)                                       = 0
/65:    lwp_park(0x00000000, 0)         (sleeping...)

最後,工作執行緒關閉它剛剛傳遞的檔案,並封鎖執行緒,直到聆聽器將另一個連線指定給它。

/67:    accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)

與此同時,聆聽器執行緒只要將這個連線分配給工作執行緒,就能夠接受另一個連線(需符合工作人員 MPM 中某個流控邏輯,如果所有可用的工作人員都忙碌,則會限制聆聽器)。儘管此追蹤中看不出來,但下一個 accept(2) 能夠(而且通常會在高負載條件下)與工作執行緒處理剛接受的連線並行發生。

可用的語言:  en  |  fr  |  ko  |  tr 

top

意見

請注意
此部分並非問答區。應該針對此處提出的建議,改善文件或伺服器,而我們的管理員可能會在實作建議或視其無效/與主題無關時將建議移除。有關如何管理 Apache HTTP 伺服器的問題,應透過 IRC 頻道 #httpd 傳送至 Libera.chat,或寄送至我們的郵寄清單