欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Apache 性能最優(yōu)化分析
一. 簡(jiǎn)介

  Apache是把正確性放在首位、把速度放在其次的通用Web服務(wù)器。即使這樣,它的性能十分令人滿(mǎn)意。許多站點(diǎn)只有不到10M的出口帶寬。Apache能夠在這些站點(diǎn)的低端Pentium服務(wù)器上全速工作。實(shí)際上,擁有更多帶寬的站點(diǎn)出于一些原因(比如大量的CGI和數據庫事務(wù)處理)需要用一臺以上的機器滿(mǎn)足帶寬需求。這些原因導致了以往的Apache開(kāi)發(fā)工作集中在正確性和可配置性。

  不幸的是許多人過(guò)于重視某些指標,并把它們的原始數據當作評價(jià)Web服務(wù)器優(yōu)劣的標準。被普遍接受標準的是"原始最低性能(bare minimum performance)",而在這以外的其他速度指標只適用于很小部分的市場(chǎng)需求。但為了避免Apache在一些市場(chǎng)中受到排擠,我們在A(yíng)pache1.3上盡了相當的努力,將它與高端服務(wù)器的差距減至最小。

  另有一些人只是想試試這些東東能運行得多快。這些人竭力把Apache最后一滴性能擠出來(lái),他們也想看看究竟是什么影響了Apache的性能。這篇文章的其余部分就是針對他們而撰的。

  請注意本文適用于Unix上的Apache1.3,部分內容適用于NT平臺。目前的Apache尚未在NT上進(jìn)行優(yōu)化。事實(shí)上,不同的編程模型使它在NT上的性能表現相當不好。(即POSIX模型。NT借助POSIX子系統模擬這種編程標準,因此效率很低。Apache2.0拋棄了POSIX直接與操作系統打交道,性能將有所飛躍--譯者注)

二. 關(guān)于硬件平臺和操作系統

  最直接影響Web服務(wù)器性能的硬件要數RAM。一臺Web服務(wù)器從不應該訪(fǎng)問(wèn)內存交換區。交換增加了每次請求的延時(shí),用戶(hù)將因此認為"不夠快"。他們會(huì )點(diǎn)擊[停止]并重新裝載網(wǎng)頁(yè),這將進(jìn)一步增加服務(wù)器的負擔。您能夠也有必要調節M(mǎn)axClients,使您的服務(wù)器不會(huì )衍生太多的子進(jìn)程而導致交換。

  除此之外的事情就沒(méi)那么關(guān)鍵了。擁有快速的CPU、快速的網(wǎng)卡和硬盤(pán)都可以讓您的服務(wù)器"足夠快"。其實(shí)這足夠快個(gè)詞是需要憑經(jīng)驗去體會(huì )的。

  操作系統的選用也是值得斟酌的大問(wèn)題。普遍的準則是:及時(shí)得到操作系統提供商的最新TCP/IP補丁。迅速涌現的HTTP服務(wù)打破了截止到1994年乃至95年的Unix內核中設定的許多假設情況。理想的選擇包括目前的FreeBSD和Linux。

三. 關(guān)于運行時(shí)設置(Run-Time Configuration)

  1) HostnameLookups

  1.3版以前的Apache中,HostnameLookups的缺省值是On,這將導致每次請求時(shí)服務(wù)器都要進(jìn)行NDS查詢(xún),從而增加了延遲。Apache1.3將此缺省值設為Off。在1.3及以后的版本中,如果您使用了任何allow from domain或deny from domain命令,所付出的代價(jià)將是兩次DNS查詢(xún)帶來(lái)的延時(shí)(在一次逆向查詢(xún)后跟著(zhù)一次正向查詢(xún),以保證前者得到的結果是真實(shí)的)。因此為了得到最理想的性能應避免使用HostnameLookups(使用IP地址而非域名也是個(gè)好主意)。


  限制命令的使用范圍是可行的,比如使用類(lèi)似的容器。這種情況下,DNS查詢(xún)只發(fā)生在符合條件的請求中。下面的例子使查詢(xún)只發(fā)生在.html和.cgi文件的請求中:

    HostnameLookups off
    
  
一秒一個(gè)的規則防止服務(wù)器在生成子進(jìn)程時(shí)過(guò)于忙碌。如果它忙于繁殖進(jìn)程,請求將被擱置。但這個(gè)規則對直觀(guān)性能的影響太大了,它必須有所改觀(guān)。在A(yíng)pache 1.3中,一秒一個(gè)的規則被廢棄了。它首先衍生一個(gè)子進(jìn)程,等一秒,衍生兩個(gè),等一秒,再衍生兩個(gè),直到一秒衍生32個(gè)子進(jìn)程。隨后它將保持這個(gè)速度直到滿(mǎn)足MinSpareServers的要求。

  這看起來(lái)足夠好了。幾乎不用在MinSpareServers、MaxSpareServers或StartServers上費工夫了。當每秒鐘衍生的進(jìn)程數超過(guò)4時(shí),ErrorLog中會(huì )增加一條相應的記錄。如果您看到了很多這樣的提示,請調整這些參數。mod_status的輸出會(huì )給您一些提示。

  于進(jìn)程相關(guān)的問(wèn)題是由MaxRequestsPerChild導致的進(jìn)程終止。MaxRequestsPerChild缺省地設置為0,意味每個(gè)子進(jìn)程處理的請求數不受限制。如果當前的設置值非常小,您可能希望大幅度提升這個(gè)值。為了防止內存泄露,在SunOS或者低版本的Solaris上,應把此值設為10000左右。

  如果使用了持續連接(keep-alives),子進(jìn)程將繁忙等待(busy waiting)已打開(kāi)連接的后續請求而不能做其他的事。缺省的15秒種試圖使影響將至最底。您需要在網(wǎng)絡(luò )帶寬和服務(wù)器資源之間作出權衡。任何情況下,不應設置持續連接時(shí)間超過(guò)60秒。否則大部分好處將變成損失。

四. 關(guān)于編譯時(shí)設置

  1) mod_status 和 ExtendedStatus On

  如果在編譯Apache時(shí)您包含了mod_status并且將ExtendedStatus設置為On,Apache將為每個(gè)請求進(jìn)行兩次gettimeofday(2)系統調用(或者針對不同的系統調用times(2))及(在1.3以前的版本)許多次time(2)。這些都是為了在報告中含有時(shí)間戳。為了得到最佳性能,請將ExtendedStatus設為Off(這是缺省的設置)。

  2) 多socket中的accept 串行化

  這部分文章將討論Unix socket API不利的一方面。假設您的服務(wù)器用多個(gè)Listen命令偵聽(tīng)多個(gè)端口或者多個(gè)IP地址。Apache使用select(2)檢測每個(gè)socket連接(connection)是否就緒。select(2)示意有零個(gè)或至少一個(gè)連接等待某個(gè)socket。Apache含有多個(gè)子進(jìn)程,所有空閑的子進(jìn)程同時(shí)偵聽(tīng)新的連接。原始的實(shí)現如下所示(這個(gè)例子不是真正的代碼,它出于教學(xué)目的被簡(jiǎn)化了)

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;
}


  但這種實(shí)現會(huì )引起嚴重的饑餓問(wèn)題。由于多個(gè)子進(jìn)程同時(shí)執行這個(gè)循環(huán),它們將在select中阻塞。當任何socket上出現一個(gè)請求時(shí),所有被阻塞的進(jìn)程將復蘇,并從select返回(蘇醒進(jìn)程的數量取決于操作系統和時(shí)間)。它們將繼續執行并試圖接受這個(gè)連接,但只有一個(gè)進(jìn)程會(huì )成功(假設目前仍只有一個(gè)連接),其余進(jìn)程將阻塞在accept中。這將把所有失敗的進(jìn)程鎖定,使它們只為一個(gè)socket上的請求服務(wù)。它們會(huì )一直被阻塞,直到在那個(gè)socket上出現足夠的請求把它們喚醒。這一饑餓問(wèn)題首先在PR#467被提出。至少有兩種解決它的方法。

  一種方案是使用非阻塞的socket。這種情況下,accept不會(huì )阻塞子進(jìn)程,它們將會(huì )立即返回。但這種方案會(huì )造成CPU時(shí)間的浪費。假設有十個(gè)在select中的空閑進(jìn)程,而后到來(lái)了一個(gè)連接請求。九個(gè)進(jìn)程將蘇醒、試圖接受連接、失敗,并返回select,這些進(jìn)程實(shí)際什么都沒(méi)做。而且如果在這期間,其他socket上出現請求,沒(méi)有哪個(gè)進(jìn)程會(huì )為它服務(wù)??偠灾?,這種方案不是十分有效,除非您擁有和空閑子進(jìn)程數目相當的CPU--恐怕不切實(shí)際。

  另一種方案被Apache采納。這種方案串行化(serialize)對內層循環(huán)的調用。代碼如下所示(改進(jìn)的部分被加粗顯示):

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_on和accept_mutex_off 兩個(gè)函數實(shí)現了互斥量(mutual exclusion semaphore),在任意時(shí)刻只能有一個(gè)子進(jìn)程擁有互斥量。多種方法可以實(shí)現互斥量。在src/conf.h(1.3版之前)或src/include/ap_config.h(1.3版及以后)可以作出以下選擇。一些系統不提供任何互斥方法。在這些系統上使用多個(gè)Listen命令是不保險的。

  USE_FLOCK_SERIALIZED_ACCEPT

  此方法用flock(2)系統調用對一個(gè)鎖文件加鎖。(此文件在LockFile命令中指定)

  USE_FCNTL_SERIALIZED_ACCEPT

  此方法用flock(2)系統調用對一個(gè)鎖文件加鎖。(此文件在LockFile命令中指定)

  USE_SYSVSEM_SERIALIZED_ACCEPT (1.3版及以后)

  此方法借助SysV的信號量(semaphores)實(shí)現互斥。但不巧的是SysV信號量有一些負面作用。一是Apache可能在清除信號量之前非正常終止;二是在使用信號量API時(shí)需要考慮到任何與服務(wù)器UID相同的CGI程序可以進(jìn)行拒絕服務(wù)攻擊(就是說(shuō)所有的CGI程序都可以這樣做,除非使用suexec或cgiwrapper之類(lèi)的方法)。所以,這種方法并不被IRIX之外的系統廣泛采納(由于大多數IRIX系統上,使用前兩種方法的代價(jià)太大)。

  USE_USLOCK_SERIALIZED_ACCEPT

 ?。?.3版及以后)此方法僅在IRIX上可用。它調用usconfig(2)創(chuàng )建互斥量。雖然這種方法避免了對SysV信號量的種種爭議,但它不是IRIX的缺省方案。這是由于在單處理器的IRIX系統 (5.3或6.2)上,uslock代碼比SysV信號量慢兩個(gè)數量級;但在多處理器的IRIX中前者比后者快一個(gè)數量級。這無(wú)非使問(wèn)題復雜化了。所以在多處理器IRIX系統上,您需要用如下的附加參數編譯Apache:

    在EXTRA_CFLAGS中添加-DUSE_USLOCK_SERIALIZED_ACCEPT
    USE_PTHREAD_SERIALIZED_ACCEPT


  
(1.3版及以后)此方法實(shí)現了POSIX標準互斥量。它理應可以工作在任何實(shí)現了全部POSIX線(xiàn)程規范的系統上,但事實(shí)是只有在Solaris 2.5或以上的系統及特定的配置中才能工作。如果您嘗試這種方法的話(huà),需要小心服務(wù)器掛起或者沒(méi)有響應。服務(wù)器在只輸出靜態(tài)網(wǎng)頁(yè)的情況下運行得很好。

  如果您的系統上有其他串行化的方法,為它書(shū)寫(xiě)代碼(并把補丁寄給Apache)是值得的。

  有一個(gè)考慮到但從未實(shí)現的方案是對循環(huán)部分地串行化--即允許一定數目的進(jìn)程進(jìn)入循環(huán)。在同一時(shí)刻可運行若干進(jìn)程的多處理器系統上,這個(gè)主意是滿(mǎn)不錯的。而且前面提到的方案并沒(méi)有充分利用帶寬??捎捎诟叨炔⑿谢姆?wù)器實(shí)在少見(jiàn),這個(gè)方案的優(yōu)先級比較低。

  為了得到最佳性能,不用多偵聽(tīng)命令是最理想的。請繼續往下看。

  3) 單socket中的accept串行化

  以上言及的方案對多socket服務(wù)器是相當不錯的,但只有一個(gè)socket的情況又如何呢?理論上,由于在連接請求到來(lái)之前所有子進(jìn)程將阻塞在accept中,單個(gè)socket不會(huì )產(chǎn)生上述種種問(wèn)題。但實(shí)際上,上述非阻塞解決方案所帶來(lái)的"回旋(spinning)"問(wèn)題在這里只不過(guò)被掩蓋起來(lái)了。在絕大多數TCP協(xié)議棧的實(shí)現中,一個(gè)接請求到來(lái)時(shí)內核將喚醒所有阻塞在accept中的進(jìn)程。它們之一將得到此請求并返回用戶(hù)空間,其余的進(jìn)程將返回內核重新休眠。這將帶來(lái)與多socket非阻塞解決方案相同的資源浪費。

  由于這點(diǎn)原因,我們發(fā)現如果為socket串行化,許多系統表現得更"友好"--即使是一個(gè)socket的情況。這是單個(gè)socket串行化作為絕大多數情況的缺省配置的原因。在Linux上不甚精確的(Linux 2.0.30 / 雙Pentium Pro 166 w / 128Mb內存)實(shí)驗表明,對每次請求而言,串行化的單個(gè)socket僅比沒(méi)有串行化的socket損失不到3%的性能。但未串行化的socket顯示出每次連接請求100毫秒的延時(shí)。這也可能僅僅由于過(guò)長(cháng)的通訊距離造成的。如果您不想串行化單個(gè)socket,可以定義宏SINGLE_LISTEN_UNSERIALIZED_ACCEPT。這樣,僅有一個(gè)socket的服務(wù)器將不會(huì )串行化。

  4) 延遲關(guān)閉(Lingering Close)

  就象draft-ietf-http-connection-00.txt第8節討論的那樣,為了使服務(wù)器能夠可靠地實(shí)現HTTP協(xié)議,有必要獨立地關(guān)閉每個(gè)方向上的通訊(每個(gè)TCP連接有兩個(gè)方向,每個(gè)方向是分別獨立的)。這個(gè)事實(shí)往往被其他服務(wù)器所忽視,而Apache 1.2就已經(jīng)正確地處理了。

  當這個(gè)特性增加到Apache中時(shí)卻在許多版本的Unix中引起了問(wèn)題。這是TCP規范的短見(jiàn)造成的--它沒(méi)有聲明FIN_WAIT_2有超時(shí),但也沒(méi)有阻止這樣的實(shí)現。在沒(méi)有超時(shí)的系統中,Apache 1.2將導致許多socket將永遠處于FIN_WAIT_2的狀態(tài)。這可以簡(jiǎn)單地用打最新TCP/IP補丁的方法避免。然而在提供商從不發(fā)行補丁的系統上(也就是SunOS4--雖然得到源代碼許可證的人可以自己打補?。?,我們決定不直接使用這一特性。
有兩種實(shí)現這個(gè)特性的辦法:一是socket的SO_LINGER選項。但似乎是命中注定,在多數TCP/IP協(xié)議棧中它從來(lái)不能正確地實(shí)現。即使是在提供了正確實(shí)現的平臺(即Linux 2.0.31)上,這種方法也要比第二種方法代價(jià)(指CPU時(shí)間)高得多。

  大多數情況下,Apache在一個(gè)叫lingering_close的函數中實(shí)現了它(在 http_main.c)。這個(gè)函數大致如下所示:

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) {
read (s, junk_buffer, sizeof (junk_buffer));
/* just toss away whatever is here */
}
}

close (s);
}

  這自然增加了連接結束時(shí)的開(kāi)銷(xiāo),但它是可靠的實(shí)現所必需的。隨著(zhù)HTTP/1.1的日益盛行,所有連接都是持久的,這種開(kāi)銷(xiāo)將被眾多的連接請求抵消。如果您想冒險禁止這一特性的話(huà),可以定義宏NO_LINGCLOSE,但這顯然是不被推薦的。實(shí)際上,由于在HTTP/1.0中持久的管道式連接越來(lái)越普遍,lingering_close幾乎是必須的選擇。(管道式連接非常高效,所以您還是希望支持它的吧)

  5) 記分板文件

  Apache利用一種叫做記分板(scoreboard)的技術(shù)在父、子進(jìn)程間通訊。它的理想實(shí)現是在共享內存中。有的操作系統允許我們直接訪(fǎng)問(wèn)共享內存,或者提供它們的確切端口。在這些系統中的典型實(shí)現就是共享內存記分板。其他的系統則將磁盤(pán)上的文件作為缺省實(shí)現。磁盤(pán)文件不僅低效而且不穩定(又沒(méi)有什么優(yōu)勢)。請為您的操作系統仔細閱讀src/main/conf.h文件,并在其中尋找USE_MMAP_SCOREBOARD或者USE_SHMGET_SCOREBOARD。定義它們之一(以及相應的HAVE_MMAP和HAVE_SHMGET)將允許Apache使用共享內存。如果您系統的內存共享機制與眾不同,請編輯src/main/http_main.c并增加Apache所需的掛鉤函數(同時(shí)請把補丁寄給我們)

  注:直到1.2版,Apache的Linux版才開(kāi)始使用共享內存。這一疏忽使得以前版本的Apache在Linux上表現得很不理想。

  DYNAMIC_MODULE_LIMIT

  如果您不打算支持動(dòng)態(tài)加載模塊的話(huà)(準備榨出最后一滴性能的您可能希望如此),編譯服務(wù)器時(shí)請設定參數-DDYNAMIC_MODULE_LIMIT=0。這將節省出為動(dòng)態(tài)加載模塊而分配的內存。


  附錄:對某次跟蹤狀況的詳細分析

  本附錄描述了運行在Linux上的Apache 1.3系統調用的跟蹤情況。運行時(shí)(run-time)配置文件中除了必要的缺省選項外還增加了:

    
    AllowOverride none
    Options FollowSymLinks
    


  被請求的文件是一個(gè)6K的靜態(tài)網(wǎng)頁(yè),其中不包含特殊內容。對于非靜態(tài)或者伴隨有內容協(xié)商的請求,跟蹤結果將有明顯的不同(一些情況下會(huì )十分晦澀)。我們將首先列出完整的跟蹤結果,然后逐條進(jìn)行分析。(它是由strace跟蹤程序生成的,其他類(lèi)似的程序包括truss、ktrace和par)

accept(15, {sin_family=AF_INET, sin_port=htons(22283), sin_addr=inet_addr("127.0.0.1")}, [16]) = 3
flock(18, LOCK_UN) = 0
sigaction(SIGUSR1, {SIG_IGN}, {0x8059954, [], SA_INTERRUPT}) = 0
getsockname(3, {sin_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
setsockopt(3, IPPROTO_TCP1, [1], 4) = 0
read(3, "GET /6k HTTP/1.0\r\nUser-Agent: "..., 4096) = 60
sigaction(SIGUSR1, {SIG_IGN}, {SIG_IGN}) = 0
time(NULL) = 873959960
gettimeofday({873959960, 404935}, NULL) = 0
stat("/home/dgaudet/ap/apachen/htdocs/6k", {st_mode=S_IFREG|0644, st_size=6144, ...}) = 0
open("/home/dgaudet/ap/apachen/htdocs/6k", O_RDONLY) = 4
mmap(0, 6144, PROT_READ, MAP_PRIVATE, 4, 0) = 0x400ee000
writev(3, [{"HTTP/1.1 200 OK\r\nDate: Thu, 11"..., 245}, {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 6144}], 2) = 6389
close(4) = 0
time(NULL) = 873959960
write(17, "127.0.0.1 - - [10/Sep/1997:23:39"..., 71) = 71
gettimeofday({873959960, 417742}, NULL) = 0
times({tms_utime=5, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 446747
shutdown(3, 1 /* send */) = 0
oldselect(4, [3], NULL, [3], {2, 0}) = 1 (in [3], left {2, 0})
read(3, "", 2048) = 0
close(3) = 0
sigaction(SIGUSR1, {0x8059954, [], SA_INTERRUPT}, {SIG_IGN}) = 0
munmap(0x400ee000, 6144) = 0
flock(18, LOCK_EX) = 0

  accept串行化:

    flock(18, LOCK_UN) = 0
    ...
    flock(18, LOCK_EX) = 0


  這兩個(gè)調用可以被上文提到的宏SINGLE_LISTEN_UNSERIALIZED_ACCEPT去掉。

  對信號SIGUSR1的處理:

    sigaction(SIGUSR1, {SIG_IGN}, {0x8059954, [], SA_INTERRUPT}) = 0
    ...
    sigaction(SIGUSR1, {SIG_IGN}, {SIG_IGN}) = 0
    ...
    sigaction(SIGUSR1, {0x8059954, [], SA_INTERRUPT}, {SIG_IGN}) = 0


  引起它們的原因是"溫和重啟"(graceful restart --用SIGUSR1而不是SIGHUP使Apache重新啟動(dòng)。這種方式為Apache留出了自行處理的余地--譯者注)。當父進(jìn)程收到SIGUSR1后,它將把這一信號傳遞給所有子進(jìn)程(同時(shí)遞增在共享內存中更新計數器的值"generation counter")。所有空閑的子進(jìn)程(即在兩次連接之間的子進(jìn)程)收到信號后將立即終止。所有處于持續連接(keep-alive)但在兩次請求之間的子進(jìn)程也將立即終止。但處于連接中并等待第一次請求的子進(jìn)程將不會(huì )立即終止。

  為了說(shuō)明它的必要性,請考慮一個(gè)瀏覽器對已關(guān)閉連接的處理。如果已關(guān)閉的連接是持續連接,而且下一個(gè)請求不是該連接的第一個(gè)請求,瀏覽器將不動(dòng)聲色地建立另一個(gè)連接并重新發(fā)出請求。由于服務(wù)器任何時(shí)候都可能關(guān)閉一個(gè)持續連接(可能因為超時(shí)或者超過(guò)了最大請求數目),這樣處理是有必要的。但是,如果在回應第一個(gè)請求前連接就被關(guān)閉,瀏覽器通常會(huì )顯?quot;文檔中無(wú)數據"的對話(huà)框(或者顯示被折斷的圖片)。這是在假設服務(wù)器非正常終止(或者太忙)的情況下作出的反應。因此,Apache力圖避免在作出任何回應前就關(guān)閉連接。這就是處理SIGUSR1的原因。

  盡管在理論上避免那三個(gè)調用是可行的,但在粗略的測試中這樣的改進(jìn)是微不足道的。

  為了實(shí)現虛擬主機,Apache需要用本地socket地址接受連接:

    getsockname(3, {sin_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0

  在許多情況下都有可能去掉這個(gè)調用(比如沒(méi)有虛擬主機,或者在Listen命令中的地址不含通配符)。但目前尚未對此進(jìn)行優(yōu)化。

Apache關(guān)掉了Nagle算法:

  setsockopt(3, IPPROTO_TCP1, [1], 4) = 0

  考慮到John Heidemann的論文中提及的問(wèn)題,請關(guān)注兩個(gè)time調用:

    time(NULL) = 873959960
    ...
    time(NULL) = 873959960


  第一個(gè)出現在請求的開(kāi)始,另一個(gè)用于寫(xiě)入日志。前者是正確實(shí)現HTTP協(xié)議所必須的,后者的出現是因為通用日志格式指定了記錄中包含時(shí)間戳。自定義日志模塊能夠去掉這個(gè)調用?;蛘吣梢杂媚承┓椒ò褧r(shí)間移到共享內存中。參見(jiàn)補丁一節。

  正如前文描述的那樣,ExtendedStatus On將引發(fā)兩次gettimeofday調用和一次times調用:

    gettimeofday({873959960, 404935}, NULL) = 0
    ...
    gettimeofday({873959960, 417742}, NULL) = 0
    times({tms_utime=5, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 446747


  ExtendedStatus Off (即缺省值)將避免這些調用。

  這個(gè)調用看起來(lái)也許有些奇怪:

  stat("/home/dgaudet/ap/apachen/htdocs/6k", {st_mode=S_IFREG|0644, st_size=6144, ...}) = 0
它用于生成CGI程序所需的PATH_INFO環(huán)境變量。事實(shí)上,對于指向/cgi-bin/printenv/foobar的某個(gè)請求,stat將被調用兩次。第一次調用查詢(xún)/home/dgaudet/ap/apachen/cgi-bin/printenv/foobar,但它并不存在;第二次調用查詢(xún)/home/dgaudet/ap/apachen/cgi-bin/printenv,它是存在的。無(wú)論如何,對于靜態(tài)請求而言,至少需要一次調用。文件尺寸和修改時(shí)間被用來(lái)生成HTTP頭標(比如Content-Length和Last-Modified)并用來(lái)實(shí)現協(xié)議的特色部分(比如If-Modified-Since)。一個(gè)聰明的服務(wù)器能夠對非靜態(tài)的請求避免調用stat,但是這樣的實(shí)現對于模塊化的Apache來(lái)說(shuō)太難了。

  所有靜態(tài)文件使用mmap:

    mmap(0, 6144, PROT_READ, MAP_PRIVATE, 4, 0) = 0x400ee000
    ...
    munmap(0x400ee000, 6144) = 0


  在一些系統上mmap小文件的效率不如直接讀取該文件。宏MMAP_THRESHOLD用來(lái)設置應用mmap時(shí)的最小文件尺寸。缺省值是0(但在SunOS4上的缺省值是8129。實(shí)驗證明這個(gè)值在該系統上比較理想)類(lèi)似lmbench的工具可以幫助您在您的系統上進(jìn)行優(yōu)化設置。

  您也許樂(lè )意在MMAP_SEGMENT_SIZE上做個(gè)實(shí)驗(缺省值32768)。它決定了被mmap的文件將以一次多少個(gè)字節寫(xiě)出。Apache只在每次write之間重置客戶(hù)的超時(shí)時(shí)間,因此把這個(gè)值設得過(guò)大容易把帶寬較窄的用戶(hù)拒之門(mén)外--除非同時(shí)增加Timeout。

  您的系統有可能根本不用mmap。如果是這樣的話(huà),定義USE_MMAP_FILES和HAVE_MMAP也許會(huì )奏效(如果它真的有效請告訴我們)。

  Apache盡全力避免在內存中拷貝數據。對任何請求的首次寫(xiě)出都將借助writev合并頭標及第一塊數據:

    writev(3, [{"HTTP/1.1 200 OK\r\nDate: Thu, 11"..., 245},{"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 6144}], 2) = 6389

  當進(jìn)行HTTP/1.1塊狀編碼時(shí),Apache將生成最多為4個(gè)元素的writev。它的目標是將字節拷貝至內核,這是典型情況下必須做的事情(為了組裝網(wǎng)絡(luò )數據包)。2.0.31之前的Linux并不進(jìn)行合并,而是為每個(gè)元素生成一個(gè)數據包。因此升級系統是一個(gè)好主意。定義NO_WRITEV將阻止這種合并,但將使得塊狀編碼的性能很差。

  日志文件的寫(xiě)入工作

    write(17, "127.0.0.1 - - [10/Sep/1997:23:39"..., 71] = 71

  能夠被宏定義BUFFERED_LOGS推遲。這種情況下,在真正寫(xiě)入文件之前,最多PIPE_BUF個(gè)字節(POSIX標準定義的常量)的日志信息將被緩存。由于寫(xiě)入條目不是atomic的(就是說(shuō)來(lái)自不同子進(jìn)程的信息將混合在一起),因此跨越PIPE_BUF邊界的條目不會(huì )被分割。當子進(jìn)程終止時(shí),Apache用出色的方式將緩存排空。

  延遲關(guān)閉引發(fā)了四個(gè)系統調用:

    shutdown(3, 1 /* send */) = 0
    oldselect(4, [3], NULL, [3], {2, 0}) = 1 (in [3], left {2, 0})
    read(3, "", 2048) = 0
    close(3) = 0


  這些在前文已經(jīng)提及。

  當我 們使用了-DSINGLE_LISTEN_UNSERIALIZED_ACCEPT、-DBUFFERED_LOGS 和 ExtendedStatus Off 的優(yōu)化參數后,最終得到的跟蹤結果如下:

accept(15, {sin_family=AF_INET, sin_port=htons(22286), sin_addr=inet_addr("127.0.0.1")}, [16]) = 3
sigaction(SIGUSR1, {SIG_IGN}, {0x8058c98, [], SA_INTERRUPT}) = 0
getsockname(3, {sin_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
setsockopt(3, IPPROTO_TCP1, [1], 4) = 0
read(3, "GET /6k HTTP/1.0\r\nUser-Agent: "..., 4096) = 60
sigaction(SIGUSR1, {SIG_IGN}, {SIG_IGN}) = 0
time(NULL) = 873961916
stat("/home/dgaudet/ap/apachen/htdocs/6k", {st_mode=S_IFREG|0644, st_size=6144, ...}) = 0
open("/home/dgaudet/ap/apachen/htdocs/6k", O_RDONLY) = 4
mmap(0, 6144, PROT_READ, MAP_PRIVATE, 4, 0) = 0x400e3000
writev(3, [{"HTTP/1.1 200 OK\r\nDate: Thu, 11"..., 245}, {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 6144}], 2) = 6389
close(4) = 0
time(NULL) = 873961916
shutdown(3, 1 /* send */) = 0
oldselect(4, [3], NULL, [3], {2, 0}) = 1 (in [3], left {2, 0})
read(3, "", 2048) = 0
close(3) = 0
sigaction(SIGUSR1, {0x8058c98, [], SA_INTERRUPT}, {SIG_IGN}) = 0
munmap(0x400e3000, 6144) = 0

  只剩下19個(gè)系統調用了。其中有四個(gè)很容易被移走,但沒(méi)有什么必要了。

  附錄:可用的補丁

  這里有一些1.3版的性能補丁。但隨著(zhù)1.3.0版的發(fā)行它們可能有些過(guò)時(shí)。對掌握一點(diǎn)C語(yǔ)言的知識的人來(lái)說(shuō),升級它們并不是難事。特別地:
  • 有一個(gè)補丁去掉所有time(2)系統調用。
  • 有一個(gè)補丁去掉mod_include中的許多系統調用,它們僅出于向后兼容而被少數站點(diǎn)所使用。
  • 有一個(gè)補丁結合了上面兩個(gè)特性,并通過(guò)去掉一些特性使服務(wù)器加速。
  附錄:預分支(Pre-Forking)模型

  Unix上的Apache是應用了預分支模型的服務(wù)器。父進(jìn)程的責任僅在于繁衍子進(jìn)程,它從不響應來(lái)自socket的任何請求。真正處理連接的是子進(jìn)程,每個(gè)子進(jìn)程在終止之前會(huì )(逐一地)為多個(gè)連接服務(wù)。父進(jìn)程根據服務(wù)器負載的變化(通過(guò)監視記分板,記分板由子進(jìn)程負責保持同步)生成新的或者殺掉舊的子進(jìn)程。

  這種模型為服務(wù)器提供了其他模型所不具備的健壯。父進(jìn)程的代碼非常簡(jiǎn)單,它有足夠的信心保證在不出現錯誤的情況下持續運行。子進(jìn)程就很復雜了,而且當您加入了第三方提供的模塊后,將冒segmentation fault和其他崩潰的危險。即便這樣的事情發(fā)生了,也只會(huì )影響到一個(gè)連接。父進(jìn)程將繼續為請求服務(wù),并迅速替換掉已經(jīng)死亡的子進(jìn)程。

  預分支在不同的Unix之間有良好的可移植性。Apache向來(lái)將它作為重要的目標之一,并且將保持下去。

  但預分支模型由于各種各樣的性能問(wèn)題而飽受批判。主要的因素是分支進(jìn)程帶來(lái)的負擔、上下文切換帶來(lái)的負擔和多個(gè)進(jìn)程為內存帶來(lái)的負擔。另外它不能為請求提供有效的緩存機制(比如mmap文件池)。另有一些模型。JAWS project的論文對它們進(jìn)行了詳細的分析。實(shí)際上,所有這些模型帶來(lái)的性能損失在不同操作系統上的差別迥異。

  Apache的內核代碼已經(jīng)支持多線(xiàn)程。NT上的Apache 1.3就是多線(xiàn)程的。至少有另外兩種實(shí)驗性的多線(xiàn)程Apache:一個(gè)基于1.3內核并運行在DCE上;另一個(gè)基于1.0內核,它使用了一套自定義的用戶(hù)級線(xiàn)程庫。它們都不是對公眾發(fā)行的。有一個(gè)已經(jīng)發(fā)行了的Apache實(shí)驗版本:運行于Netscape運行時(shí)可移植(Portable Run Time)平臺上的1.3版,可以在此下載(如果您準備使用它的話(huà),歡迎您加入new-httpd郵件列表)。被重新設計的Apache2.0將包含抽象化的服務(wù)器模型,它使我們可以既支持預分支模型,又支持多種線(xiàn)程模型。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
NGINX 1.9.1 支持socket分片提升性能
大廠(chǎng)面試中出現概率極高的Linux性能優(yōu)化題
PHP的CGI實(shí)現 | PHP源碼閱讀,PHP設計模式
PHP socket 服務(wù)器框架 workerman
這是一篇最通熟易懂的性能調優(yōu)總結!
epoll
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久