第三章 系統設計與實作
3.2 Application-Level 動態網頁快取系統之設計與實作
3.2.3 系統實作
本研究採用RedHat Linux 8.0 作業系統、Apache 2.0.45 網頁伺服器,以及 PHP 4.3.1 動態網頁語言之共同組合,作為 Application-Level 動態網頁快取系統之實作 主體環境,至於採用此種組合的原因,除了這樣的組合不僅常見於現今多數網 站,同時也因其擁有相當優異之服務效率表現,而更重要的原因,則在於其個別 軟體套件皆有提供完整的軟體開發介面,以及豐富的文件說明,可供本研究進行 深入的系統開發之用,而以下為本研究對Application-Level 動態網頁快取系統之 系統元件之實作。
Web Switch
由於先前已在3.2.2.2 章節中說明,網頁伺服器中之 Web Switch 已有動、
靜態網頁處理流程之判別機制,現僅須於此判別機制前,先行一步處理URL,
即為再加上一 URL Pre-Processing,便可隨意操控此判別機制之最終判別結 果,而能完成本研究對Web Switch 之系統元件設計。
而在Apache 網頁伺服器之眾多附加軟體模組中,mod_rewrite [15] 正好擁 有處理URL 之能力,其能在 Apache 開始正式處理客戶端請求之前,先取得請
求中之URL,並依據事先訂定之判別條件(Condition)與處理方式(Rule),
改寫URL(URL Rewrite),Apache 即會視此經 mod_rewrite 改寫後之 URL,
為客戶端請求中之 URL 而開始進行處理,因此,本研究即使用 mod_rewrite 來實作URL Pre-processing。
圖3.11、URL Rewrite Rule
圖3.12、urlparsr.pl 程式碼
圖3.11 即為本研究所撰寫之 URL Rewrite Rule,圖中之前三行用以啟動 mod_rewrite,後三行則正式開始處理 URL,一開始,先設定用來將 Type B URL 轉譯為Type A URL 之程式為 urlparse.pl,而 urlparse.pl 之程式碼為圖 3.12,其 中可見urlparse.pl 所需進行的工作,僅為替換 URL 中之” , ”成” / ”,以及替 換” ! ”成” ? ”,故其工作之內容相當輕鬆,並不會拖慢 Apache 處理之速度,而 接下來之URL Rewrite Rule 為判別客戶端所請求之網頁有無存在,若存在,則
RewriteEngine on
RewriteLog logs/rewrite.log RewriteLogLevel 9
RewriteMap urlparse prg:/usr/local/apache2/cgi-bin/urlparse.pl RewriteCond /usr/local/apache2/htdocs%{REQUEST_FILENAME} !-s RewriteRule ^/cache_dir(.*)\.html$ ${urlparse:$1} [L]
#!/usr/bin/perl -w
$|=1;
while(<STDIN>) {
chomp $_; s/,/\//g; s/!/?/g;
printf $_."\n"; }
交由Apache 自行處理,若不存在,則開始進行下一 URL Rewrite Rule,判別 URL 是否為 Type B,若是,則開始執行 urlparse.pl,將此 Type B URL 轉譯為 Type A URL,以使 Apache 的判別機制所見之 URL 為 Type A,而能開始進行 動態網頁之處理流程。
在檢視過圖3.13 之 Apache 存取紀錄(access.log),與圖3.14 之 mod_rewrite 紀錄(rewrite.log)後,證明本研究之 Web Switch 實作是相當成功的。
WADC
圖3.15 為一以 PHP 動態網頁語言所實作之標準 WADC 設計範本,其中含有多 個不同功用之程序區塊,現說明如下:
1. 一般而言,動態網頁程式在尚未完全執行完其所有程式碼之前,就會先行 陸陸續續地將已經產生之部分動態網頁,交由網頁伺服器傳回客戶端,此 時即已無法再傳送HTTP Header,因 HTTP Header 須於網頁傳送之前即先 傳送至客戶端,方能生效,但在動態網頁尚未完全產生之前,並未有足夠 之資訊可供產生相關之HTTP Cache-Control Header,因此,須將已產生之 動態網頁先暫時儲存在某處,直到全部動態網頁皆已產生後,再依動態網 頁之內容,產生適當之HTTP Header,並先行送出這些 HTTP Header,才 能隨後送出動態網頁,而由PHP 所提供之 ob_start()函式,即可提供一緩 衝儲存器(Buffer),供作在其後之程式碼所產生之資料暫存之用,這即代
表ob_start(),可讓 WADC 暫存、快取其所產生之動態網頁。
圖3.13、access.log
圖3.14、rewrite.log
2. 無論是對客戶端或是對 Cache Manager,WADC 皆須提供快取文件之逾期 時間,如此客戶端之網頁快取系統才能在快取文件之內容行將變動之際,
向伺服器端索取最新之內容,另外倘若此快取文件有著固定之變動週期,
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (2) init rewrite engine with requested uri /cache_dir/news,finance.php!id=0001.html
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (3) applying pattern '^/cache_dir(.*)\.html$' to uri '/cache_dir/news,finance.php!id=0001.html'
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (4) RewriteCond: input='/usr/local/apache2/htdocs/cache_dir/news,finance.php!id=0001.html' pattern='!-s' => matched
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (5) map lookup OK: map=urlparse key=/news,finance.php!id=0001 -> val=/news/finance.php?id=0001
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (2) rewrite /cache_dir/news,finance.php!id=0001.html -> /news/finance.php?id=0001
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (3) split uri=/news/finance.php?id=0001 -> uri=/news/finance.php, args=id=0001
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (2) local path result: /news/finance.php
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (2) prefixed with document_root to /usr/local/apache2/htdocs/news/finance.php
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] [localhost/sid#81200e0][rid#81f63a8/initial] (1) go-ahead with /usr/local/apache2/htdocs/news/finance.php [OK]
127.0.0.1 - - [03/Jul/2003:19:49:33 +0800] "GET /cache_dir/news,finance.php!id=0001.html HTTP/1.0" 200 1092
圖3.15、WADC 之設計範本
<?
ob_start();
$cache_age=600;
$cache_FILE_EXIST = FALSE;
$cache_STR = $_SERVER["REQUEST_URI"];
if(ereg("\?",$cache_STR)) {
ereg("^/(.*)",$cache_STR,$cache_REG);
$cache_STR = $cache_REG[1];
$cache_STR = ereg_replace("\/",",",$cache_STR);
$cache_STR = ereg_replace("\?","!",$cache_STR);
$cache_STR = $cache_STR.".html";
} else {
ereg("^/(.*)ache_dir/(.*)",$cache_STR,$cache_REG);
$cache_STR = $cache_REG[2];
}
$cache_file = "/tmp/cache_dir/".$cache_STR;
// Content Start include("finance.inc");
// Content End
$cache_contents=ob_get_contents();
if(file_exists($cache_file)) {
$cache_file = $cache_file.".cmr";
$cache_FILE_EXIST = TRUE;
}
$cache_fp=fopen($cache_file,"w");
fwrite($cache_fp,$cache_contents);
fclose($cache_fp);
$cache_fsize=filesize($cache_file);
$cache_filemodtime=date("D, d M Y H:i:s",(time() - 8*3600));
header("Cache-Control: max-age=".$cache_age.",must-revalidate");
header("Expires: ".gmdate("D, d M Y H:i:s", (time() - 8*3600) + $cache_age)." GMT");
header("Last-Modified: ".$cache_filemodtime." GMT");
header("Accept-Ranges: bytes");
header("Content-length: ". $cache_fsize);
header("Content-Type: text/html");
ob_end_flush();
if( $cache_FILE_EXIST == FALSE) {
$cache_STR = $cache_STR.":T".$cache_age;
$cache_STRC = escapeshellcmd($cache_STR);
system("./cmrc $cache_STRC");
}
?>
1. 開始快取
2. 設定快取逾期時間
3. 轉譯 Type A URL 成 Type B URL
4. 執行程式碼以產生動態內容
5. 儲存動態內容成快取文件
6. 產生 HTTP Cache-Control Header,並結束快取
7. 知會 Cache Manager
Cache Manager 也才能適時的進行維護快取文件內容一致行之工作,因 此,在此須設定快取文件之逾期時間。
3. 由於 WADC 將動態網頁存成快取文件時,須以 Type B URL 命名此快取文 件,但由於WADC 所收到之 URL 皆為 Type A URL,因此,在此須進行 轉譯Type A URL 成 Type B URL 之工作。
4. 若要程式設計師將所有的動態網頁程式皆改寫成 WADC,則可能需付出
不少時間與成本,而本研究即考量此點,設計出圖3.14 之 WADC 標準範 本,讓原先動態網頁程式”包含(include)”在此範本中執行,如此,程式
設計師即可輕鬆的將所有既有之動態網頁應用程式,皆改為WADC。
5. 待完整動態網頁已產生後,WADC 即需將動態網頁存成快取文件,但依 照曾在3.2.2.3 章節解釋過之因素,故須先判別在 Cache Directory 中有無 存在先前已產生之同名快取文件,已決定此次所產生的快取文件之Type B URL 檔名後是否須加上”.cmr”副檔名,而在此,即是進行上述之工作。
6. 一旦動態網頁已全部產生,WADC 即可由動態網頁取得足夠之資訊,產 生適當之HTTP Cache-Control Header,至於先前用以暫存所有此 WADC 所產生之 HTTP Header 與動態網頁的 Buffer,此時也可刪除不用,而當 Buffer 刪除之同時,其內之所有資料也會全部釋放,交由網頁伺服器傳送 至客戶端,供客戶端使用。
7. 在最後,若確定 WADC 所收到之 Type A URL 並非來自於 Cache Manager,
則WADC 須知會 Cache Manager 快取文件已產生,並告知 Cache Manager 該如何來維護此快取文件之內容一致性,而 WADC 知會 Cache Manager 之方法,為同時使用 UNIX 作業系統中的訊號(Signal)與訊息佇列
(Message Queue),至於使用之理由與實際做法,將於 Cache Manager 之 實作中說明解釋。
Cache Manager
Cache Manager 之主要工作,即在維護快取文件之內容一致性,而要能準 確、適時的完成此項工作,則須依賴WADC 能給予正確的快取文件維護訊息,
並須能向網頁伺服器提出Type A URL 之請求,不過,Cache Manager 卻不可 與其他系統元件有直接的交流、互動,以免影響整個快取系統之服務效率,因 此,本研究在實作Cache Manager 時,設計出如圖 3.16 之 Cache Manager 與其 它系統元件之關係,讓Cache Manager 在不能直接接觸其它系統元件之限制條 件下,能完成其本身之工作。
本研究使用 ANSI C 語言與 GCC 3.2 編譯器實作 Cache Manager,並為 Cache Manager 實作出如圖 3.16 之與其它元件之互動方式,圖 3.16 解說如下:
1. WADC 將其所產生之動態網頁,儲存成以 Type B URL 為檔名之快取文 件,放置在Cache Directory 之中。
圖3.16、Cache Manager 與其它系統元件之實作關係圖
2. WADC 將該快取文件的維護訊息,放入伺服器作業系統之訊息佇列
(Message Queue)當中,而 Message Queue 為 UNIX 作業系統中,程 式彼此可共同使用之獨特記憶體區塊,可作為程式間相互溝通之管道、
方式,且其可一直獨立存在於作業系統之上,而不似 UNIX 作業系統 上,另一也可用來讓程式相互溝通之方式 – 共享記憶體(Shared Memory),會隨其起始程式之結束而消失,或是殘留、迷失在記憶體中,
因此本研究選擇使用Message Queue 作為 WADC 與 Cache Manager 傳遞 訊息方式。
3. WADC 發出一訊息(Signal)至 Cache Manager,使 Cache Manager 能得
Web Server Link
-list
Message Queue Cache
Directory
Cache Manager
WADC
1. Save 2. Send
3. Signal
4. Get 5. Get
6. Save 7. Socket
知在Message Queue 中有快取文件之維護訊息待查看,而 Signal 為 UNIX 作業系統中,一種經常使用的程式中斷(Interrupt)機制,用來迫使程 式中斷執行,或是依序 Signal 種類之不同,而進行相對應於 Signal 種 類之不同反應動作,在此快取系統中,由於Cache Manager 不能與其它 系統元件直接互動,而在平常無工作須立即進行時,Cache Manager 皆 處於沉睡狀態(Sleep),本研究則使用Signal,以喚醒 Cache Manager,
使Cache Manager 得知有快取文件維護訊息之存在。
4. 在收到 WADC 所發出之 Signal 後,Cache Manager 即自 Message Queue 中取出訊息,並閱讀之。
5. Cache Manager 依訊息中所說明之快取文件名稱、維護一致性之方式,
至Cache Directory 取得該快取文件之屬性值。
6. Cache Manager 將所收集到的該快取文件之全部屬性值,儲存在 Cache Manager 本身的 Link-list 當中,此 Link-list 即為 Cache Manager 放置所
有快取文件之屬性值的地方,而Cache Manager 之日常作業皆須依賴此 Link-list,方能得知該在什麼時間,對什麼快取文件,進行何種之快取 文件一致性內容維護之作業。
7. 而在須進行維護快取文件之一致性作業時,Cache Manager 須對網頁伺 服器提出Type A URL 之請求,以迫使網頁伺服器進行動態網頁處理流 程,執行 WADC 以產生新一份的快取文件,本研究則使用通訊端連結
(Socket Connection)之方式,以讓 Cache Manager 能直接對網頁伺服 器之通訊埠(Port)提出請求。