APACHE工做原理詳解 (三)

Apache HTTP服務器是一個模塊化的軟件,使管理者能夠選擇核心中包含的模塊以裁剪功能。能夠在編譯時選擇被靜態包含進httpd二進制映象的模塊,也能夠編譯 成獨立於主httpd二進制映象的動態共享對象DSO,DSO模塊能夠在編譯服務器以後編譯,也能夠用Apache擴展工具(apxs)編譯並增長。程序員

  本文闡述如何使用DSO模塊及其工做原理。正則表達式

  工做原理apache

  DSO是Dynamic Shared Objects(動態共享目標)的縮寫,它是現代Unix派生出來的操做系統都存在着的一種動態鏈接機制。它提供了一種在運行時將特殊格式的代碼,在程序 運行須要時,將須要的部分從外存調入內存執行的方法。Apache在1.3之後的版本後開始支持它。由於Apache早就使用一個模塊概念來擴展它的功能 而且在內部使用一個基於調度的列表來連接擴展模塊到Apache核心模塊.因此,Apache早就註定要使用DSO來在運行時加載它的模塊。服務器

  讓咱們先來看一下Apache自己的程序結構:這是一個很複雜的四層結構--每一層構建在下一層之上。模塊化

  第四層是用Apache模塊開發的第三方庫--好比open ssl通常來講在Apache的官方發行版中這層是空的,可是在實際的Apache結構中這些庫構成的層結構確定是存在的。函數

  第三層是一些可選的附加功能模塊--如mod_ssl,mod_perl。這一層的每一個模塊一般實現的是Apache的一個獨立的分離的功能而事實上這些模塊沒有一個是必須的,運行一個最小的Apache不須要任何一個此層的模塊。工具

  第二層是Apache的基本功能庫-這也是Apache的核心本質層--這層包括Apache內核,http_core(Apache的核心模 塊),它們實現了基本HTTP功能(好比資源處理(經過文件描述符和內存段等等),保持預生成(pre-forked)子進程模型,監聽已配置的虛擬服務 器的TCP/IP套接字,傳輸HTTP請求流處處理進程,處理HTTP協議狀態,讀寫緩衝,此外還有附加的許多功能好比URL和MIME頭的解析及DSO 的裝載等),也提供了Apache的應用程序接口(API)(其實Apache的真正功能仍是包含在內部模塊中的,爲了容許這些模塊徹底控制Apache 進程,內核必須提供API接口),這層也包括了通常性的可用代碼庫(libap)和實現正則表達式匹配的庫(libregex)還有就是一個小的操做系統 的抽象庫(libos)。編碼

  最低層是與OS相關的平臺性應用函數,這些OS能夠是不一樣現代UNIX的變種,win32,os/2,MacOS甚至只要是一個POSIX子系統。spa

APACHE工做原理詳解 - PHP程序員 - 李國華【PHP程序員C++】博客

  

  圖1 apache模塊功能分層操作系統

  在這個複雜的程序結構中有趣的部分是---事實上第三層和第四層與第二層之間是鬆散的鏈接,而另外一方面第三層的模塊間是互相依賴的--因這種結 構形成的顯著影響就是第三層和第四層的代碼不能靜態地鏈接到最低層平臺級的代碼上。所以DSO模式就成了解決它的一種手段。結合DSO功能,這個結構就變 得很靈活了,可讓Apache內核(從技術上說應該是mod_so模塊而不是內核)在啓動時(而不是安裝時)裝載必要的部分以實現第三層和第四層的功 能。

  現代類Unix的系統都有一種叫動態共享對象(DSO)的動態鏈接/加載的巧妙的機制,從而能夠在運行時刻,將編譯成特殊格式的代碼加載到一個可執行程序的地址空間。

  加載的方法一般有兩種:其一是,在可執行文件啓動時由系統程序ld.so自動加載;其二是,在執行程序中手工地經過Unix加載器的系統接口執行系統調用dlopen()/dlsym()以實現加載。

  按第一種方法,DSO一般被稱爲共享庫(shared libraries)或者DSO庫(DSO libraries),使用libfoo.so或者libfoo.so.1.2的文件名,被存儲在系統目錄中(一般是/usr/lib),並在編譯安裝 時,使用鏈接器參數-lfoo創建了指向可執行程序的鏈接。經過設置鏈接器參數-R或者環境變量LD_LIBRARY_PATH,庫中硬編碼了可執行文件 的路徑,使Unix加載器可以定位到位於/usr/lib的libfoo.so,以解析可執行文件中還沒有解析的位於DSO的符號。

  一般,DSO不會引用可執行文件中的符號(由於它是通用代碼的可重用庫),也不會有後繼的解析動做。可執行文件無須本身做任何動做以使用DSO 中的符號,而徹底由Unix加載器代辦(事實上,調用ld.so的代碼是被連入每一個可執行文件的非靜態運行時刻啓動代碼的一部分)。動態加載公共庫代碼的 優勢是明顯的:只須要在系統庫libc.so中存儲一個庫代碼,從而爲每一個程序節省了磁盤存儲空間。

  按第二種方法,DSO一般被稱爲共享對象(shared objects)或者DSO文件(DSO files),可使用任何文件名(可是規範的名稱是foo.so),被存儲在程序特定的目錄中,也不會自動創建指向其所用的可執行文件的鏈接,而由可執 行文件在運行時本身調用dlopen()來加載DSO到其地址空間,同時也不會進行爲可執行文件解析DSO中符號的操做。Unix加載器會根據可執行程序 的輸出符號表和已經加載的DSO庫自動解析DSO中還沒有解析的符號(尤爲是無所不在的libc.so中的符號),如此DSO就得到了可執行程序的符號信 息,就好象是被靜態鏈接的。

  最後,爲了利用DSO API的優勢,執行程序必須用dlsym()解析DSO中的符號,以備稍後在諸如指派表等中使用。也就是說,執行程序必須本身解析其所需的符號。這種機制 的優勢是容許不加載可選的程序部件,直到程序須要的時候才被動態地加載(也就不須要內存開銷),以擴展程序的功能。

  雖然這種DSO機制看似很直接,但至少有一個難點,就是在用DSO擴展程序功能(即第二種方法)時爲DSO對可執行程序中符號的解析,這是因 爲,「反向解析」可執行程序中的DSO符號在全部標準平臺上與庫的設計都是矛盾的(庫不會知道什麼程序會使用它)。實際應用中,可執行文件中的全局符號通 常不是重輸出的,所以不能爲DSO所用。因此在運行時刻用DSO來擴展程序功能,就必須找到強制鏈接器輸出全部全局符號的方法。

  共享庫是一種典型的解決方法,由於它符合DSO機制,並且爲操做系統所提供的幾乎全部類型的庫所使用。另外一方面,使用共享對象並非許多程序爲擴展其功能所採用的方法。

  截止到1998年,只有少數軟件包使用DSO機制在運行時刻實際地擴展其功能,諸如Perl 5(經過其XS機制和DynaLoader模塊), Netscape Server等。從1.3版本開始,Apache也加入此列,由於Apache已經用了基於指派表(dispatch-list-based)的方法來連 接外部模塊到Apache的核心。因此,Apache也就固然地在運行時刻用DSO來加載其模塊。

  優勢和缺點

  上述基於DSO的功能有以下優勢:

  因爲服務器包的裝配工做能夠在運行時刻使用httpd.conf的配置命令LoadModule來進行,而不是在編譯中使用configure 來進行,所以顯得更靈活。好比:只須要安裝一個Apache,就能夠運行多個不一樣的服務器實例(如標準&SSL版本,濃縮的&功能增強版 本[mod_perl, PHP3],等等)。

  服務器包能夠在安裝後使用第三方模塊被輕易地擴展。這至少對廠商發行包的維護者有巨大的好處,他能夠創建一個Apache核心包,而爲諸如PHP3, mod_perl, mod_fastcgi等擴展另建附加的包。

  更簡單的Apache模塊原型。使用DSO配合apxs,能夠脫離Apache源代碼樹,僅須要一個apxs -i和一個apachectl restart命令,把開發的模塊新版本歸入運行中的Apache服務器。

  DSO有以下缺點:

  因爲並非全部的操做系統都支持動態加載代碼到一個程序的地址空間,所以DSO機制並不能用於全部的平臺。

  因爲Unix加載器有必須進行的符號解析的開銷,服務器的啓動會慢20%左右。

  在某些平臺上,獨立位置代碼(positon independent code[PIC])有時須要複雜的彙編語言技巧來實現相對尋址,而絕對尋址則不須要,所以服務器在運行時會慢5%左右。

  因爲DSO模塊不能在全部平臺上爲其餘基於DSO的庫所鏈接(ld -lfoo),好比,基於a.out的平臺一般不提供此功能,而基於ELF的平臺則提供,所以DSO機制並不能被用於全部類型的模塊。或者能夠這樣說,編 譯爲DSO文件的模塊只能使用由Apache核心、C庫(libc)和Apache核心所用的全部其餘動態或靜態的庫、含有獨立位置代碼的靜態庫 (libfoo.a)所提供的符號。而要使用其餘代碼,就只能確保Apache核心自己包含對此代碼的引用,或者本身用dlopen()來加載此代碼。

  模塊實現

  相關模塊 相關指令

  mod_so <IfModule>

  LoadModule

  Apache對獨立模塊的DSO支持是創建在被靜態編譯進Apache核心的mod_so模塊基礎上的,這是core之外惟一不能做爲DSO存 在的模塊,而其餘全部已發佈的Apache模塊,均可以經過安裝文檔中闡述的配置選項--enable-module=shared,被獨立地編譯成 DSO並使之生效。一個被編譯爲mod_foo.so的DSO模塊,能夠在httpd.conf中使用mod_so的LoadModule指令,在服務器 啓動或從新啓動時被加載。

  用命令行參數-l能夠查看已經編譯到服務器中的模塊。

  新提供的支持程序apxs(APache eXtenSion)能夠在Apache源代碼樹之外編譯基於DSO的模塊,從而簡化Apache DSO模塊的創建過程。其原理很簡單:安裝Apache時,配置命令make install會安裝Apache C頭文件,並把依賴於平臺的編譯器和鏈接器參數傳給apxs程序,使用戶能夠脫離Apache的發佈源代碼樹編譯其模塊源代碼,而不改變支持DSO的編譯 器和鏈接器的參數。

  用法概要

  Apache 2.0的DSO功能簡要說明:

  編譯並安裝已發佈的Apache模塊,好比編譯mod_foo.c爲mod_foo.so的DSO模塊:

  $ ./configure --prefix=/path/to/install --enable-foo=shared

  $ make install

  編譯並安裝第三方Apache模塊, 好比編譯mod_foo.c爲mod_foo.so的DSO模塊:

  $ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared

  $ make install

  配置Apache以便共享後續安裝的模塊:

  $ ./configure --enable-so

  $ make install

  用apxs在Apache源代碼樹之外編譯並安裝第三方Apache模塊,好比編譯mod_foo.c爲mod_foo.so的DSO模塊:

  $ cd /path/to/3rdparty

  $ apxs -c mod_foo.c

  $ apxs -i -a -n foo mod_foo.la

  共享模塊編譯完畢之後,都必須在httpd.conf中用LoadModule指令使Apache激活該模塊。

  參考資料:

  Ralf S. Engelschall-- Apache 1.3 Dynamic Shared Object (DSO) Support

  Apache2.0 文檔-- 動態共享對象

相關文章
相關標籤/搜索