一 序言
-------
我想linux愛好者沒有不知道Apache的. 作為一個linux的管理員更應該精通Apache的配制. 在這裡我就我的理解描述一下Apache. 作為一個被廣泛使用的Web服務器, Apache將reliable擺在了第一位, performance只是第二位的東東. 這一理念我覺得很好. 當然, 它最好的地方是開放源碼, 這才使我們有機會深入了解世界上最流行的Web Server.
二 基本結構介紹
---------------
Apache是由模塊組成, 其中http_core.c是最根本的, 一個最小的Apache編譯只包含這一個模塊. 你可以用"httpd -l" 可以列出Apache被編譯進了哪些模塊. 動態模塊是需要在配制文件中定義的. 在Redhat中, 只有"http_core.c"被編譯進去了, 其余的都被編譯成了so. 可以被Apache動態加載. Redhat中的Apache是比較特殊的, 標准的Apache只有一個配制文件httpd.conf, 其他的文件都是空的.
下面是在配制文件中裝載模塊的命令:
LoadModule digest_module modules/mod_digest.so
LoadModule proxy_module modules/libproxy.so
LoadModule php3_module modules/libphp3.so
... ...
ClearModuleList
AddModule mod_actions.c
AddModule mod_userdir.c
AddModule mod_alias.c
... ...
LoadModule是用於動態加載模塊的. ClearModuleList是刪除Apache中的模塊列表. AddModule是將模塊加入到列表中去. 上面命令是用於重新構造模塊列表, 模塊在列表中的順序代表了其處理時的優先級, 後面的優先級高.
Apache將一個Cl.net的請求按以下步驟處理:
1. URL -> Filename translation
2. Auth ID checking
3. Auth access checking
4. Access checking other than auth
5. Determining MIME type of the object requested
6. Fixups
7. Actually sending a response back to the client
8. Logging the request
Apache本身只負責內存分配, IO, 進程管理和模塊管理等, 它通過調用模塊提供的接口函數完成配制命令的處理和用戶請求的實際處理. 其中的核心模塊http_core.c提供了最基本的命令, 每一個模塊通常都會有自己的配制命令. 模塊可以參與上述的八個步驟. 每一個模塊提供一個struct module, 其中定義了大量的函數指針和結構指針, 通過struct module告訴Apache該模塊所支持的命令和參與的步驟.
struct module中定義了改模塊的名字, 這是通過宏來完成的, 其名字就是__FILE__. 所以在文件mod_foo.c中定義的模塊名字就叫mod_foo.c.
Apache內部維護了一個鏈表(頭指針為top_module). 最初時只有一個
http_core.c. 每一條命令LoadModule, AddModule. 都會在表頭加一項. 而在每一步, Apache都會按照鏈表中的順序來依次調用每個模塊提供的函數. 而在許多步, Apache碰到第一個返回OK的即結束. 因此, 表中的順序( 這也就是所謂的優先級了 )可以對系統有很大影響.
下面看一下上面說過的八個步驟:
1. URL -> Filename translation
將URL轉換為本地的文件名, 例如: mod_alias.c會在這一步處理alais
2. Auth ID checking
3. Auth access checking
4. Access checking other than auth
進行認證處理
5. Determining MIME type of the object requested
決定被請求對象的MIME類型
6. Fixups
不知道(誰知道請告訴我)
7. Actually sending a response back to the client
將應答發送給客戶
8. Logging the request
寫log
認證的部分會在後面講. 我們看一看最後幾步. Apache繼承了通過擴展名來判斷MIME類型的方法. AddType用來加入新的一些擴展名:
AddType application/x-httpd-php3 .php3
AddType application/x-tar .tgz
這兩條指令定義了後綴為php3和tgz的文件的MIME類型. 這裡用的都是標准的MIME類型, 所謂的決定MIME類型其實還包括了另一種情況: 模塊會用一些字符串來描述一個請求, Apache根據這一字符串來選擇一個相應的模塊來處理該請求. 這些字符串都是內部自定義的. 細節會在下面描述.
AddHandler cgi-script .cgi
AddHandler server-parsed .shtml
Sethandler cgi-script
AddHandler定義了何種擴展名用那一個字符串進行描述.
SetHandler將一個目錄下的文件都指定用這一個字符串描述.
我在這裡提到的命令都是與其結構密切相關的. Handler和Type的關系在下面會描述的. 許多的東東從外面是看不清楚的, 下面, 我們從裡面看.
三 程序的基本結構
-----------------
Apache有非常好的跨平台性. 為了實現這一目標和簡化模塊編寫者的負擔,Apache完成了許多基本的功能如IO, 內存分配等, 這些接口都是與具體平台無關的. 還有一些很有用的例程如: hash table, array 等. 在整個體系中, Apache有一個基本點, 它盡可能的使用簡單的結構和算法, 這不僅易於理解和維護, 還提高了它的穩定性.
在UNIX系統上, Apache采用了多進程模型, 在Window上采用了多線程模型.多進程模型中, 其子進程處理客戶請求, 父進程用於管理子進程. 當系統過載時父進程會再啟動幾個子進程, 當系統空閒時, 父進程會殺掉幾個子進程. 子進程的數目在"MinSpareServers"和"MaxSpareServers"之間. 而且, 每個子進程處理的請求個數也是有限制的, 這可以解決諸如內存洩漏等問題. 所有的進程狀態都被記錄在share memory中. 由於每個進程的狀態記錄在其中的一小塊內存上, 它通常也只讀寫這一塊內存, 因此, Apache沒有使用什麼同步機制.
在Richard Steve的書上說到的幾種多進程服務器模型, Apache都使用了,在不同的系統上根據其特點選擇使用不同的方法:
1. accept :
在accept處阻塞, 只有在accept是在內核級實現的才行.
2. select :
在select處阻塞.
3. mutex/lock_file :
使用mutex或lock_file來進行對accpet進行互斥.
三種方法都要求進行阻塞, 區別在於阻塞與不同的地方. 前兩種方法都會由所謂的巨群問題: 多個阻塞在同一個資源上的進程被同時喚醒引發再次競爭. 不過, 按Richard Steve 的評測, 第一種方法最快, 第二種其次, 第三種最慢. 其實, 在linux上第三種方法也會有巨群問題.
Apache雖然並不強調性能, 這並不意味著他們不重視性能. 而是Apache認為在Server端realiable才是第一位的. 但Apache的性能還是不錯的.
來源:Bricks with GNU&LINU