一、何謂ASP快取/為什麼要快取當你的web站點採用asp技術建立的初期,可能感覺到的是asp動態網頁技術帶來的便利性,以及隨意修改性、 自如的http控制。但是,隨著訪問量的增加,你一定會發現自己的網站訪問速度越來越慢,IIS重新啟動得越來越頻繁。接下來,你一定想優化asp,諸如更換效能更優異的資料庫、建立索引、編寫預存程序等等。這些措施有些不需要增加成本壓力,有些則成本壓力很大(譬如叢access到SQL),效果還不一定。
面對web存取壓力,我認為最經濟的辦法是利用快取優化技術來實現緩解web的服務壓力。
Web訪問量增加通常意味著以下資源需求的快速成長:
1. 網路卡流量增加,需要消耗更多的CPU處理網路流量和網路I/O執行緒。
2、需要更頻繁的開啟/關閉資料庫連結(如果使用資料庫技術—通常asp都會採用資料庫作為資料儲存),嚴重消耗資源的事物數量、以及事務相互競爭資源所造成的死鎖、會增加網路I/O或CPU消耗。
3. 如果採用session的話,IIS為了維持狀態,會消耗更多內存,而內存消耗可能會引發物理內存不夠,引起物理內存同輔存儲的頻繁交換,從而引起代碼執行的停頓,web響應阻滯。
4、 由於存取的不到及時回應,會造成網頁存取故障,導致使用者刷新,進而加劇CPU、記憶體等資源需求。
實際上,考慮通常的web應用程序,很多時候的動態程式碼執行是不必要的。
二、asp快取的分類擅自總結,asp的快取可以分為兩類:
1. 檔案快取所謂檔案緩存,就是根據邏輯判斷,一段時間內某個asp的特定執行將不會有很大的變動,因而將內容以靜態html的形式存放,然後以web的重定向技術讓客戶端存取靜態文件,以達到減少CPU、資料庫資源等的需求。這樣的應用程式很多,譬如很多論壇就是在回覆貼文的時候將整個貼文重新產生靜態文件,然後進行重定向的,例如donews.com的論壇。該成靜態還有一個副作用(好處)–可以很容易被google等搜尋引擎收錄。一些所謂新聞發布系統的都採用了此技術。
2. 文件片段緩存所謂文件緩存,也是基於邏輯判斷,某部分數據(通常是需要消耗資源的大容量數據庫查詢取得)在一定時間內不會改變,所以我們可以將這些數據利用文件的形式進行存儲,當需要時候,可以透過讀取文件來獲取數據,避免增加資料庫的負擔。例如,我們通常將一些資料以xml格式存儲,然後利用xslt技術實作顯示(xml處理通常需要大量CPU資源,所以通常是IE直接讀取xml到客戶端在客戶的CPU上處理)。 CSDN的論壇就是這樣處理的。
3、 主存緩存除此之外,還可以考慮在記憶體中處理緩存,將需要及時回應的內容儲存在記憶體中,一旦存取需求,立即從快速的儲存中輸送出去。如果極大量的存取需求集中在幾個少量的頁面或主存足夠多,我想採用主存快取一定可以大幅提高web存取效能。
三、如何實現/使用快取實現快取需要考慮以下問題:
1、 哪些頁面會在短時間內不會改變?
分析自己的站點,這樣的頁面很多。譬如一個站點通常都有新聞資訊類的欄目,這些欄位通常都是站點維護人員在一天的某個時間發布資料,之後很少改動頁面。那麼這些頁面就適合採用靜態檔案快取。實際上, 所謂新聞發布系統就是這麼做的,那麼那也可以參考這些系統的思想改造自己的原有動態asp頁面。
2、 那些頁面針對全部訪客都採用同一個邏輯生成(也就是不區分訪客)。
除了新聞資訊之類的欄位所有訪客都看一個介面外,論壇等消耗資源的應用程式一般也可以設計成統一邏輯生成(同一個貼子,張三李四看的都一樣),針對這類應用頁面我們也可以採用靜態快取來實現。也可以考慮將資料片斷化,利用腳本技術在伺服器處理能力之外也就是客戶端瀏覽器處理。
3、 採用緩存的代價和收穫。
主要就是「空間換(反應)時間」。利用快取技術將之後頻繁需要的內容進行預處理,使其提高web伺服器回應能力,更重要贏得訪客的歡心。
代價就是web空間需求增加,同時又可能影響到存取效果。
但我認為適當的緩存,是利大於弊的。
4. 那些地方不適宜採用緩存動態查詢頁面,每個人的查詢內容不一樣,所以顯示結果不大一樣,所以不大可能將查詢結果生成緩存,所以採用緩存較為複雜且緩存利用率底下,造成管理成本上什(假設你快取了1000個查詢關鍵字,那麼管理這些關鍵字同快取的對應也是麻煩事)。
四、實例分析假設一個建議論壇的原有佈局如下:
根目錄下:
default.asp 首頁,一般是精華、推薦之類
listBorad.asp 此文件列出全部分欄目的名稱和介紹,如果攜帶參數MainBID就表示要列出板塊下的欄目
listThread.asp 此檔案若不攜帶任何參數表示列出全部的貼子,攜帶MainBID表示列出某塊的全部貼子。如果攜帶subBID表示列出具體欄目的貼子。如果攜帶page參數表示分頁列出主題。
ViewThread.asp 列出某個貼文內容。我們假設貼文顯示為一個發言,任意跟貼全部列在後面。 ID參數為要顯示的貼子。
Reply.asp 回應某個貼子,攜帶參數Id回應某個貼子其它的暫不討論。
以上,我們可以看到,如果全部是採用原始的ASP/PHP來做,那幾乎每個asp檔的執行都需要資料庫操作,頻繁的查詢,多表查詢。要知道查詢資料庫最終會帶來效能的下降,回應速度下降,帶給訪客緩慢的瀏覽影響,不利於web的品質。更重要的是對於甲乙兩個人來將,他們訪問ViewThread.asp之類的如果ID一致,那麼很多時候他們會看到同樣的內容(他們的瀏覽器收到的HTML代碼幾乎一樣),但是為了這“同樣的內容”,伺服器需要打開資料庫連結、查詢,讀取紀錄,顯示,關閉紀錄、資料庫連結。 。 。 。以下列的消耗伺服器資源的操作,如果是更多的人來訪問,最終的結果是這些人加劇消耗伺服器資源。實際上,這些為了「同樣的內容」所做的重複勞動是可以利用快取技術進行最佳化避免的。譬如:
在reply.asp提交內容後,我們立即調用生成靜態的功能,將整個貼子內容存儲為viewThread_xxxx.htm之類的靜態html文件,再通常情況下訪問viewThread.asp?ID=xxxx的時候,系統自動redirect到對應的靜態檔案viewThreadxxxx.htm去。這樣,當一個貼子沒有最新發佈時候,他始終是靜態內容提供給瀏覽者;一旦有了新的提交,將會更新到靜態文件中去,這樣,將會節省很多次資料庫操作,大大提高回應速度。
listBorad.asp也可以實作靜態化。我們可以分析其可能攜帶的參數,將快取檔案名稱設定為listBoard_xx.htm,在增加新的欄位時候進行更新listBoard_xxx.htm。 listThread.asp也類似,只不過由於其參數更多,所以快取檔案也會很多。擊若要快取listThread.asp? subBID=xxx&page=2,那麼對應的靜態檔案就是listThread_xxx_p2.htm。 default.asp也一樣。
那麼如何判斷什麼時候更新呢?在什麼時機更新?
討論listThread.asp? subBID=xxx&page=2,我們在執行listThread.asp俄時候提取subID和page,然後探測listThread_xxx_p2.htm是否存在,如果不存在就調用靜態生成功能進行生成該文件,最終重定向到此靜態文件。注意,此處的不存在就表示出現了新的內容需要我們更新。
那如何造成文件不存在呢?刪除。我們在發表一個新的貼子、刪除貼子、移動貼子的時候我們可以將類似listThread_xxx_p2.htm之類的靜態檔案全部刪除。這樣就通知了何時要進行快取。
現在還剩下一個問題,如何產生靜態檔案?
我們注意到,之前我們提到的「同樣的內容」。我們可以將改造前的default.asp、listThread.asp等拷貝一個副本,取名為default_d.asp、listThread_2.asp,且在同一個目錄中(理論上listThtrad.asp?subID=123同LISTtHREAD_D.ASP? SUBID=123的存取結果會是同樣的內容),這樣我們在需要產生靜態檔案的邏輯中,透過WEB存取請求的方式呼叫改造前的副本,得到html程式碼,並儲存為靜態檔案。這個web請求其實相當於在任何真實瀏覽者存取靜態內容之前,由伺服器本身現察看將會輸出的html,然後傳回這些程式碼,利用檔案操作功能儲存為靜態檔案。這樣,快取檔案就在真正瀏覽者之前被創建。
這樣的方案幾乎不會觸動原來的佈局,幾乎不會造成因為改造出現404之類的錯誤。其次,靜態檔案也會幫助你的網站容易被google之類的搜尋引擎收錄。何樂而不為?
最後,提醒,透過web訪問,在asp程式設計環境下,很多人採用xmlHTTP元件訪問,這會造成很多問題。 xmlhttp本身會cache請求的資源,導致我們透過此元件請求得到的內容不是最新的,造成邏輯上的混亂。所以,應選擇xml Server http物件或winhttp元件來實作web請求資源。
使用ASP中的快取技術可以很大程度上提高你的網站效能,其實這些實作方法是非常的簡單,它將說明如何在伺服器上的快取是如何運作以及你如何使用一種稱為斷開連接的ADO連接技術。
在介紹這些技術之前先說明一下到底什麼是ASP的快取技術。
所謂快取其實就是在記憶體中開闢一個用來保存資料的空間,使用快取你就不用頻繁的存取你儲存在硬碟上的資料了,靈活的使用快取你就免去了心疼的看著可憐的硬碟飽受讀數據時的折磨了。當你一旦執行了一個查詢動作,並且將查詢結果放入快取中後,你就可以很迅速的重複存取這些資料了。而如果你不把資料放入快取的話,當你再次執行這個查詢時,伺服器會將進程耗費在從資料庫中取得併排序上了。
當資料保存在快取中時,再次查詢時耗費的時間主要是在顯示資料的時間上了。
也就是說,我們不應該把經常需要改變的資料放到服務端的快取中,我們應該把改變少,但是又需要經常存取的資料放到快取中。
現在我們先討論ASP 在服務端使用快取的技術,過會再討論ASP如何在客戶端使用快取的技術。
當你有大量的資料(靜態的,就是說變動比較少的)需要顯示給客戶端時,你就可以考慮使用服務端的快取技術了。這種技巧尤其適用於那些顯示風格一致性比較強的網站(呵呵,對於非主流的網站可不好用的說。)
其實實作方法特別的簡單,大家只要看看下面這個簡單的例子就懂了。
這是一個用來顯示書籍分類的例子程序
DisplayBooks.ASP 檔案:
< %@ LANGUAGE=JavaS
cript % >
< html >
< 身體 >
< form method=post >
書籍分類; < %= getBooksListBox() % >
< p>
< input type=submit >
< %
function getBooksListBox()
{
BooksListBox = Application(“BooksListBox”)
if (BooksListBox != null) return BooksListBox;
crlf = String.fromCharCode(13, 10)
BooksListBox = “< select name=Books>” + crlf;
SQL = “Select * FROM Books orDER BY Name”;
cnnBooks = Server.CreateObject(“ADODB.Connection”);
cnnBooks.Open(“Books”, “Admin”,”");
rstBooks = cnnBooks.Execute(SQL);
fldBookName = rstBooks(“BookName”);
while (!rstBooks.EOF){
BooksListBox = BooksListBox + ” < option>” +
fldBookName + “” + crlf;
rstBooks.MoveNext();
}
BooksListBox = BooksListBox + “”
Application(“BooksListBox”) = BooksListBox
return BooksListBox;
}
% >
很簡單把,其實就是用了很簡單的Application技術,而且就一句話的不同:
Application(“BooksListBox”) = BooksListBox
你可以驗證一下你就會發現伺服器上的請求數量會降低不少的。這種情況尤其適合與那些更新不是很頻繁的網站內容,例如你一天(或則很長時間)只更新一次。
下面再討論一種客戶端的快取技術這種技術也叫斷開連線的ADO連線技術(翻譯等級太次,聽起來怎麼這麼彆扭)。這種技術主要使用在用來保存使用者個人資訊,例如使用者的密碼,代號等等上面。它主要使用了ADO的一些屬性。同時也回答了一些網友曾經提到的能否在Applocation中使用ADO物件的問題。解釋不清楚,下面讓程式碼來發言:
文件GLOBAL.ASA:
< !–METADATA TYPE=”TypeLib” FILE=”C:Program FilesCommon
Filessystemadomsado15.dll”– >
< SCRIPT LANGUAGE=VBScript RUNAT=”Server” >
Sub Application_OnStart
SQL = “Select UserName, Password FROM UserInfo”
cnnUsers = “DSN=User”
Set rsUsers = Server.CreateObject(“ADODB.Recordset”)
'注意下面這兩句話,就是用來實現那個叫可用的斷開連接的ADO技術
rsCustomers.CursorLocation = adUseClient
rsCustomers.Open SQL, cnnAdvWorks, adOpenStatic, AdLockReadOnly
' 斷開RecordSet的和資料庫的連接
rsCustomers.ActiveConnection = Nothing
Set Application(“rsCustomers”) = rsCustomers
End Sub
檔案Users.ASP
< %
'Clone方法使得每個使用者擁有自己的一個RecordSet集合
Set yourUsers = Application(“rsUsers”).Clone
Set UserName = yourUsers(“UserName”)
Set Password = yourUsers(“Password”)
Do Until yourUsers.EOF
% >
使用者名稱:< %= UserName % > 使用者密碼:< %= Password % >
< %
yourUsers.MoveNext
Loop
% >