Len Cardinal,高級顧問,Microsoft Consulting Services George V. Reilly
Microsoft IIS Performance Lead
改編自Nancy Cluts 的文章 開(kāi)發人員(yuán)技術工(gōng)程師
Microsoft Corporation
2000 年 4 月
摘要:本文介紹優化 ASP 應用程序和 VBScript 的技巧。
引言
性能是一(yī)個特征。您必須預先設計性能,否則您以後就得重寫應用程序。就是說,有哪些好的策略可使 Active Server Pages (ASP) 應用程序性能達到最佳?
本文介紹了優化 ASP 應用程序和 Visual Basic® Scripting Edition (VBScript) 的技巧。本文讨論了許多陷阱。本文列出的建議已經在 http://www.microsoft.com 和其它站點中(zhōng)進行了測試,效果十分(fēn)顯著。本文假定您已經對 ASP 開(kāi)發,包括 VBScript 和/或 JScript、ASP Application、ASP Session 和其它 ASP 固有對象(Request、Response 和 Server)有了基本了解。
通常,ASP 性能主要取決于 ASP 代碼本身以外(wài)的很多因素。我(wǒ)(wǒ)們不在一(yī)篇文章中(zhōng)羅列出所有的信息,在本文結尾處我(wǒ)(wǒ)們列出了與性能有關的資(zī)源。這些鏈接涵蓋了 ASP 和非 ASP 主題,包括 ActiveX® 數據對象 (ADO)、組件對象模型 (COM)、數據庫和 Internet Information Server (IIS) 配置。這些都是我(wǒ)(wǒ)們喜歡的一(yī)些鏈接 - 一(yī)定要去(qù)看看。
技巧 1:将經常使用的數據緩存在 Web 服務器上
典型的 ASP 頁從後端數據存儲中(zhōng)檢索數據,然後将結果轉換成超文本标記語言 (HTML)。無論數據庫的速度如何,從内存中(zhōng)檢索數據總要比從後端數據存儲中(zhōng)檢索數據快得多。從本地硬盤讀取數據通常也比從數據庫中(zhōng)檢索數據更快。因此,通常可以将數據緩存在 Web 服務器上(存儲在内存或磁盤中(zhōng)),來提高性能。
緩存是傳統的以空間換取時間的做法。如果您緩存的内容正确,那麽您可以看到性能會有顯著的提高。爲使緩存有效,必須保存那些經常重複使用的數據,且要重新計算這些數據需要(适度)大(dà)的開(kāi)銷。如果緩存的都是些陳舊(jiù)的數據,就會造成内存浪費(fèi)。
不經常發生(shēng)改變的數據是很好的緩存候選數據,因爲您不必擔心随着時間的遷移該數據與數據庫同步的問題。組合框列表、引用表、DHTML 碎片、擴展标記語言 (XML) 字符串、菜單項和站點配置變量(包括數據源名稱 (DSN)、Internet 協議 (IP) 地址和 Web 路徑)都是很好的緩存候選内容。注意您可以緩存數據的“表示”,而不緩存數據本身。如果 ASP 頁很少更改,且緩存的開(kāi)銷也很大(dà)(例如,整個産品目錄),則應考慮事先産生(shēng) HTML,而不是在響應每個請求時重新顯示。
應将數據緩存在哪裏,有哪些緩存策略?通常,數據緩存在 Web 服務器的内存或磁盤中(zhōng)。下(xià)兩個技巧講述了這兩個方法。
技巧 2: 将經常使用的數據緩存在 Application 或 Session 對象中(zhōng)
ASP Application 和 Session 對象爲将數據緩存在内存中(zhōng)提供了方便的容器。您可以将數據指派到 Application 和 Session 對象中(zhōng),這些數據在 HTTP 調用之間保留在内存中(zhōng)。Session 數據是按每個用戶分(fēn)别存儲的,而 Application 數據則在所有用戶之間共享。
什麽時候将數據裝載到 Application 或 Session 中(zhōng)呢?通常,數據是在啓動 Application 或 Session 時裝載。要在 Application 或 Session 啓動過程中(zhōng)裝載數據,應将适當的代碼分(fēn)别添加到 Application_OnStart() 或 Session_OnStart() 中(zhōng)。這些函數應在 Global.asa 中(zhōng),如果沒有,則可以添加這些函數。還可以在第一(yī)次需要時裝載該數據。爲此,在 ASP 頁中(zhōng)添加一(yī)些代碼(或編寫一(yī)個可重複使用的腳本函數),以檢查數據是否存在,如果不存在,就裝載數據。這是一(yī)個傳統的性能技術,稱爲“惰性計算” - 在您知(zhī)道需要某一(yī)個值以前不計算該值。例如:
<%
Function GetEmploymentStatusList
Dim d
d = Application(?EmploymentStatusList?)
If d = ?? Then
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
Application(?EmploymentStatusList?) = d
End If
GetEmploymentStatusList = d
End Function
%>
可以爲所需要的每個數據塊編寫類似的函數。
應以什麽格式存儲數據?可以存儲任何變體(tǐ)類型,因爲所有腳本變量都是變體(tǐ)型。例如,您可以存儲字符串、整數或數組。通常,您将以這些變量類型之一(yī)存儲 ADO 記錄集的内容。要從 ADO 記錄集獲取數據,您可以手工(gōng)将數據複制到 VBScript 變量,一(yī)次一(yī)個字段。使用一(yī)個 ADO 記錄集持久函數 GetRows()、GetString() 或 Save()(ADO 2.5),可加快速度且更容易一(yī)些。其詳細情況已超出本文所讨論的範圍,但下(xià)面給出了一(yī)個函數舉例,說明使用 GetRows() 返回記錄集數據的一(yī)個數組:
' Get Recordset, return as an Array
Function FetchEmploymentStatusList
Dim rs
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
FetchEmploymentStatusList = rs.GetRows() ? Return data as an Array
rs.Close
Set rs = Nothing
End Function
對上面舉例做更進一(yī)步改進,可以将 HTML 緩存爲列表,而不是數組。下(xià)面是簡單的示例:
' Get Recordset, return as HTML Option list
Function FetchEmploymentStatusList
Dim rs, fldName, s
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
s = ?<select name=??EmploymentStatus??>? & vbCrLf
Set fldName = rs.Fields(?StatusName?) ' ADO Field Binding
Do Until rs.EOF
' Next line violates Don't Do String Concats,
' but it's OK because we are building a cache
s = s & ? <option>? & fldName & ?</option>? & vbCrLf
rs.MoveNext
Loop
s = s & ?</select>? & vbCrLf
rs.Close
Set rs = Nothing ' See Release Early
FetchEmploymentStatusList = s ' Return data as a String
End Function
在适當的條件下(xià),可以将 ADO 記錄集本身緩存在 Application 或 Session 作用域中(zhōng)。有兩個警告:
必須将 ADO 标記爲自由線程
必須使用斷開(kāi)連接的記錄集。
如果不能保證滿足這兩個要求,則不要緩存 ADO 記錄集。在下(xià)面的“非敏捷組件”和“不要緩存連接”技巧中(zhōng),我(wǒ)(wǒ)們将讨論将 COM 對象存儲在 Application 或 Session 作用域中(zhōng)的危險性。
當您将數據存儲在 Application 或 Session 作用域時,數據将保留在那裏,直到您以編程方式改變它、Session 過期或 Web 應用程序重新啓動爲止。如果數據需要更新怎麽辦?要手工(gōng)強制對 Application 數據進行更新,您可以訪問隻有管理員(yuán)才可訪問的 ASP 頁來更新數據。或者,您可以通過函數定期自動刷新數據。下(xià)面例子存儲帶有緩存數據的時間戳,并隔一(yī)段時間後刷新數據。
<%
' error handing not shown...
Const UPDATE_INTERVAL = 300 ' Refresh interval, in seconds
' Function to return the employment status list
Function GetEmploymentStatusList
UpdateEmploymentStatus
GetEmploymentStatusList = Application(?EmploymentStatusList?)
End Function
' Periodically update the cached data
Sub UpdateEmploymentStatusList
Dim d, strLastUpdate
strLastUpdate = Application(?LastUpdate?)
If (strLastUpdate = ??) Or _
(UPDATE_INTERVAL < DateDiff(?s?, strLastUpdate, Now)) Then
' Note: two or more calls might get in here. This is okay and will simply
' result in a few unnecessary fetches (there is a workaround for this)
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
' Update the Application object. Use Application.Lock()
' to ensure consistent data
Application.Lock
Application(?EmploymentStatusList?) = Events
Application(?LastUpdate?) = CStr(Now)
Application.Unlock
End If
End Sub
請參見 World's Fastest ListBox with Application Data,上面還有一(yī)個例子。
要知(zhī)道在 Session 或 Application 對象中(zhōng)緩存大(dà)的數組不是一(yī)個好的做法。在訪問數組的任何元素之前,腳本語言的語法要求必須臨時複制整個數組。例如,如果将由字符串組成的有 100,000 個元素的數組(該數組将美國郵政編碼映射到當地的氣象站)緩存在 Application 對象中(zhōng),ASP 必須先将所有的 100,000 個氣象站複制到臨時數組中(zhōng),然後才能提取一(yī)個字符串。在這種情況下(xià),用自定義方法建立一(yī)個自定義組件來存儲氣象站 - 或使用一(yī)個詞典組件會更好。
再警告大(dà)家一(yī)下(xià),不要将嬰兒與洗澡水一(yī)起倒掉:數組能快速查尋和存儲在内存中(zhōng)是鄰近的關鍵數據對。索引一(yī)個詞典比索引一(yī)個數組要慢(màn)得多。應針對您的實際情況,選擇提供最佳性能的數據結構。
技巧 3:将數據和 HTML 緩存在 Web 服務器的磁盤上
有時,數據可能太多,無法都緩存在内存中(zhōng)。“太多”隻是一(yī)個說法,這要看您想消耗多少内存,以及需緩存的項目數和檢索這些項目的頻(pín)率。在任何情況下(xià),如果數據太多而無法都緩存在内存中(zhōng),則考慮将數據以文本或 XML 文件緩存在 Web 服務器的硬盤上。可以同時将數據緩存在磁盤和内存中(zhōng),爲您的站點建立最适宜的緩存策略。
注意當測量單個 ASP 頁的性能時,檢索磁盤上的數據可能不一(yī)定要比從數據庫檢索數據更快。但緩存會降低數據庫和網絡上的負載。在高負載的情況下(xià),這樣做可大(dà)大(dà)改善總體(tǐ)吞吐量。當緩存開(kāi)銷很大(dà)的查詢結果(如多表聯接或複合存儲過程)或大(dà)的結果集時,這是非常有效的。與往常一(yī)樣,要測試一(yī)下(xià)幾種方案的優劣。
ASP 和 COM 提供一(yī)些建立基于磁盤的緩存方案的工(gōng)具。ADO 記錄集 Save() 和 Open() 函數保存和裝載磁盤中(zhōng)的記錄集。可以使用這些方法重新編寫上面 Application 數據緩存技巧中(zhōng)的代碼示例,用文件的 Save() 代替寫到 Application 對象中(zhōng)的代碼。
有一(yī)些其它組件可以用于文件:
Scripting.FileSystemObject 可使您創建、讀和寫文件。
與 Internet Explorer 一(yī)起提供的 Microsoft® XML 解析器 (MSXML) 支持保存和裝載 XML 文檔。
LookupTable 對象(例如,用在 MSN 上)是從磁盤裝載簡單列表的最好選擇。
最後,應考慮将數據的表示緩存在磁盤上,而不是數據本身。預先轉換的 HTML 可以用 .htm 或 .asp 文件存儲在磁盤上,超級鏈接可以直接指向這些文件。可以使用商(shāng)用工(gōng)具,如 XBuilder,或 Microsoft® SQL Server™ Internet 發布功能将産生(shēng) HTML 的過程自動化。或者,您可以将 HTML 代碼片斷放(fàng)在 .asp 文件中(zhōng)。還可以使用 FileSystemObject 從磁盤讀取 HTML 文件,或使用 XML 盡早轉換。
技巧 4:避免将非敏捷的組件緩存在 Application 或 Session 對象中(zhōng)
盡管将數據緩存在 Application 或 Session 對象中(zhōng)是一(yī)個好的做法,但緩存 COM 對象卻有嚴重的陷阱。通常,人們傾向于将經常使用的 COM 對象緩存到 Application 或 Session 對象中(zhōng)。很遺憾,許多 COM 對象(包括所有以 Visual Basic 6.0 或更低版本編寫的對象)當存儲在 Application 或 Session 對象時,會引起嚴重的瓶頸。
具體(tǐ)來講,當任何不敏捷的組件緩存在 Session 或 Application 對象時,将引起性能瓶頸。敏捷的組件是被标記爲 ThreadingModel=Both 的組件,它聚集 Free-threaded marshaler (FTM);或被标記爲 ThreadingModel=Neutral 的組件。(Neutral 模型是 Windows® 2000 和 COM+ 的新增模型。) 下(xià)列組件不是敏捷的:
自由線程的組件(除非它們聚集 FTM)。
單元線程組件。
單線程組件。
配置的組件(Microsoft Transaction Server (MTS)/COM+ 庫和服務器程序包/應用程序)不是敏捷的,除非它們是 Neutral 線程。單元線程組件和其它非敏捷的組件在頁作用域内是最适合的(即,它們在單個 ASP 頁上創建和銷毀)。
在 IIS 4.0 中(zhōng),被标記爲 ThreadingModel=Both 的組件被認爲是敏捷的。在 IIS 5.0 中(zhōng),隻有這一(yī)點還不夠。組件必須不僅被标記 Both,還必須聚集 FTM。有關敏捷性的文章講述了如何使以 Active Template Library 編寫的 C++ 組件聚集 FTM。要注意如果組件緩存界面指針,那麽那些指針本身必須是敏捷的,或必須存儲在 COM 共用界面表 (GIT) 中(zhōng)。如果您不能重新編譯 Both 線程組件以聚集 FTM,那麽您可以将組件标記爲 ThreadingModel=Neutral。或者,如果您不想讓 IIS 執行敏捷性檢查(因此,您可以允許非敏捷的組件存儲在 Application 或 Session 作用域中(zhōng)),您可以在配置數據庫中(zhōng)将 AspTrackThreadingModel 設置爲 True。不建議更改 AspTrackThreadingModel。
如果您想将以 Server.CreateObject 創建的非敏捷的組件存儲在 Application 對象中(zhōng),IIS 5.0 将出現一(yī)個錯誤。您可以在 Global.asa 中(zhōng)使用 <object runat=server scope=application ...> 避免這一(yī)錯誤,但不建議這樣做,因爲這會導緻彙集和串行化,關于這一(yī)點将在下(xià)面講述。
如果您緩存非敏捷的組件會出現什麽毛病?緩存在 Session 對象中(zhōng)的非敏捷的組件将 Session 鎖定于 ASP 工(gōng)作者線程。ASP 維護一(yī)個工(gōng)作者線程池來處理請求。通常情況下(xià),一(yī)個新請求總是由第一(yī)個可用的工(gōng)作者線程來處理。如果 Session 被鎖定于一(yī)個線程,那麽請求必須等到其相關的線程可用爲止。這裏有一(yī)個類比,也許會有所幫助:您去(qù)一(yī)家超級市場,挑選了一(yī)些商(shāng)品,并在 #_3 收款台付款。其後,每當您在那家超級市場爲商(shāng)品付款時,您總是必須在 #_3 收款台付款,即使其它收款台前排隊的人較少或者沒有人排隊,也是如此。
将非敏捷的組件存儲在 Application 作用域對性能的影響甚至更壞。ASP 必須創建一(yī)個特殊的線程運行存儲在 Application 作用域中(zhōng)的非敏捷組件。這會有兩個結果:所有調用都必須彙集到此線程,且所有調用都排成長隊。“彙集”的意思是參數必須存儲在内存的共享區域;執行一(yī)個開(kāi)銷很大(dà)的到特殊線程的上下(xià)文切換;執行組件的方法;将結果彙集到共享區域;執行另一(yī)個開(kāi)銷很大(dà)的上下(xià)文切換,将控制返回到原始的線程。“串行化”意思是指每次隻運行一(yī)個方法。兩個不同的 ASP 工(gōng)作者線程不能同時在共享組件上執行多個方法。這樣就杜絕了并發性,特别是在多處理器計算機上。更糟的是,所有非敏捷的 Application 作用域的組件共享一(yī)個線程(主機 STA),因此串行化的影響甚至更顯著。
如之奈何?下(xià)面是一(yī)些一(yī)般的規則。如果您使用 Visual Basic (6.0) 或更早版本編寫對象,那麽不要将它們緩存在 Application 或 Session 對象中(zhōng)。如果您不知(zhī)道對象的線程模型,不要緩存它。不要緩存非敏捷的對象,而應在每個頁面創建和釋放(fàng)它們。對象直接在 ASP 工(gōng)作者線程上運行,因此沒有彙集或串行化。如果 COM 對象在 IIS 服務器上運行,且如果它們不花長時間初始化和删除,性能尚可。注意單線程對象不應該這樣使用。小(xiǎo)心 - VB 可創建單線程對象!如果您必須這樣使用單線程對象(如 Microsoft Excel 電子表格),别指望會有很高的吞吐量。
當 ADO 被标記爲自由線程,ADO 記錄集可以安全地緩存。要将 ADO 标記爲自由線程,使用 Makfre15.bat 文件,該文件通常位于目錄 \\Program Files\Common\System\ADO 中(zhōng)。
警告 如果您使用 Microsoft Access 作爲數據庫,不應将 ADO 标記爲自由線程的。ADO 記錄集也必須切斷連接。一(yī)般來說,如果您不能控制站點中(zhōng)的 ADO 配置(例如,您是一(yī)個獨立的軟件廠商(shāng) [ISV],向管理他們自己的配置客戶銷售 Web 應用程序),最好不要緩存記錄集。
詞典組件也是敏捷的對象。LookupTable 從數據文件中(zhōng)裝載其數據,可用于組合框數據和配置信息。Duwamish Books 中(zhōng)的 PageCache 對象可提供詞典語法,Caprock Dictionary 也可提供。這些對象或其派生(shēng)對象可以構成有效緩存策略的基礎。注意 Scripting.Dictionary 對象不是敏捷的,不應該存儲在 Application 或 Session 作用域中(zhōng)。
技巧 5:不要将數據庫連接緩存在 Application 或 Session 對象中(zhōng)
緩存 ADO 連接通常是很糟糕的策略。如果一(yī)個 Connection 對象存儲在 Application 對象中(zhōng),并在所有的頁面中(zhōng)使用,那麽所有頁面将争搶這一(yī)連接。如果 Connection 對象存儲在 ASP Session 對象中(zhōng),那麽将爲每個用戶創建數據庫連接。這就會使連接池的優勢蕩然無存,并給 Web 服務器和數據庫帶來不必要的壓力。
可以不緩存數據庫連接,而是在使用 ADO 的每個 ASP 頁面中(zhōng)創建和删除 ADO 對象。這是很有效的,因爲 IIS 内嵌了數據庫連接池。更準确地說,IIS 自動啓用 OLEDB 和 ODBC 連接池。這就能确保在每個頁面上創建和删除連接将是有效的。
因爲連接的記錄集存儲一(yī)個到數據庫連接的引用,所以您不應将連接的記錄集緩存在 Application 或 Session 對象中(zhōng)。但是,您可以安全地緩存斷開(kāi)連接的記錄集,它們不保存到其數據連接的引用。要斷開(kāi)記錄集連接,執行下(xià)面的兩個步驟:
Set rs = Server.CreateObject(?ADODB.RecordSet?)
rs.CursorLocation = adUseClient ' step 1
' Populate the recordset with data
rs.Open strQuery, strProv
' Now disconnect the recordset from the data provider and data source
rs.ActiveConnection = Nothing ' step 2
有關連接池的更詳細信息,可以在 ADO 和 SQL Server 參考資(zī)料中(zhōng)找到。
技巧 6:合理地使用 Session 對象
既然我(wǒ)(wǒ)們已經讨論了緩存在 Application 和 Session 中(zhōng)的優點,現在開(kāi)始讨論避免使用 Session 對象的問題。正如下(xià)面所讨論的,當與忙的站點一(yī)起使用時,Session 有幾個缺點。“忙”的意思一(yī)般是指一(yī)秒鍾要求幾百頁面或成千上萬同時用戶的站點。這個技巧對于必須水平擴展的站點 - 即,那些利用多台服務器以處理負載或實現容錯的站點 - 甚至更重要。對于較小(xiǎo)的站點,諸如 Intranet 站點,要想實現 Session 帶來的方,必然增大(dà)系統開(kāi)銷。
簡言之,ASP 自動爲每個訪問 Web 服務器的用戶創建一(yī)個 Session。每個 Session 大(dà)約需要 10 KB 的内存開(kāi)銷(最主要的是數據存儲在 Session 中(zhōng)),這就使所有的請求都減慢(màn)。在配置的超時時段(通常是 20 分(fēn)鍾)結束以前,Session 一(yī)直保留有效。
Session 的最大(dà)的問題不是性能,而是可擴展性。Session 不能跨越幾台 Web 服務器,一(yī)旦在一(yī)台服務器上創建 Session,其數據就留在那兒。這就意味着如果您在一(yī)個 Web 服務器群使用 Session,您必須設計一(yī)個策略,将每個用戶請求始終發到用戶 Session 所在的那台服務器上。這被稱爲将用戶“粘”在 Web 服務器上。術語“粘性會話(huà)”就是從這裏派生(shēng)而來的。如果 Web 服務器崩潰,被“粘住的”用戶将丢失他們的會話(huà)狀态,因爲會話(huà)不是粘到磁盤上。
實現粘性會話(huà)的策略包括硬件和軟件解決方案。諸如 Windows 2000 Advanced Server 中(zhōng)的網絡負載平衡和 Cisco 的 Local Director 之類的解決方案都可以實現粘性會話(huà),代價是要損失一(yī)定程度的可擴展性。這些解決方案是不完善的。不建議此時部署您自己的軟件解決方案(我(wǒ)(wǒ)們過去(qù)常常使用 ISAPI 篩選器和 URL 轉換等等)。
Application 對象也不跨越多台服務器,如果您必須跨越 Web 服務器群共享和更新 Application 數據,您必須使用後端數據庫。但是,隻讀 Application 數據在 Web 服務器群中(zhōng)仍是有用的。
如果隻是因爲要增加運行時間(處理故障轉移和服務器維護),大(dà)多數關鍵任務站點至少需部署兩台 Web 服務器。因此,在設計關鍵任務應用程序時,必須實現“粘性會話(huà)”,或幹脆避免使用 Session,以及任何其它将用戶狀态存儲在單個 Web 服務器上的狀态管理技術。
如果您不使用 Session,一(yī)定要将它們關閉。您可以通過 Internet Services Manager,爲應用程序執行此操作(參見 ISM 文檔)。如果您決定使用 Session,您可以采用一(yī)些方法減輕它們對性能的影響。
您可以将不需要 Session 的内容(如幫助屏幕,訪問者區域等等)移到另一(yī)個關閉了 Session 的 ASP 應用程序中(zhōng)。您可以逐頁提示 ASP,您不再需要該頁面上的 Session 對象,使用以下(xià)放(fàng)在 ASP 頁面最上面的指令:
<% @EnableSessionState=False %>
使用這一(yī)指令有一(yī)個很好的理由是,這些 Session 在框架集方面存在一(yī)個有意思的問題。ASP 保證任何時候 Session 隻有一(yī)個請求執行。這樣就确保如果浏覽器爲一(yī)個用戶請求多個頁面,一(yī)次隻有一(yī)個 ASP 請求接觸 Session,這樣就避免了當訪問 Session 對象時發生(shēng)的多線程問題。很遺憾,一(yī)個框架集中(zhōng)的所有頁面将以串行方式顯示,一(yī)個接一(yī)個,而不是同時顯示。用戶可能必須等候很長時間,才能看到所有的框架。該故事的寓意:如果某些框架集頁面不依靠 Session,一(yī)定要使用 @EnableSessionState=False 指令告訴 ASP。
有許多管理 Session 狀态的方法,可替代 Session 對象的使用。對于少量的狀态(少于 4 KB),我(wǒ)(wǒ)們通常建議使用 Cookies、QueryString 變量和隐式變量。對于更大(dà)數據量,如購物(wù)小(xiǎo)車(chē),後端數據庫是最适合的選擇。有關 Web 服務器群中(zhōng)狀态管理技術的文章很多。有關詳細信息,請參見 Session 狀态參考資(zī)料。
技巧 7: 将代碼封裝在 COM 對象中(zhōng)
如果您有許多 VBScript 或 JScript,您可以經常将代碼移到編譯的 COM 對象中(zhōng),從而可改善性能。編譯的代碼通常比解釋的代碼運行得更快。編譯的 COM 對象可以通過“早綁定”訪問其它 COM 對象,與腳本使用的“晚綁定”相比,“早綁定”是調用 COM 對象的更有效方法。
将代碼封裝在 COM 對象中(zhōng)還有一(yī)些優點(除性能之外(wài)):
COM 對象有利于将表示邏輯與業務邏輯分(fēn)開(kāi)。
COM 對象可以保證代碼重複使用。
許多開(kāi)發人員(yuán)發現以 VB、C++ 或 Visual J++ 編寫的代碼比 ASP 更容易調試。
COM 對象也有缺點,包括初始開(kāi)發時間和需要不同的程序設計技巧。注意封裝少量的 ASP 可能引起性能下(xià)降,而不會得到性能改進。這種情況通常在少量的 ASP 代碼被封裝進 COM 對象時發生(shēng)。在這種情況下(xià),創建和調用 COM 對象的系統開(kāi)銷超過了編譯的代碼的優點。應反複地試驗,以确定什麽樣的 ASP 腳本和 COM 對象代碼的組合産生(shēng)最好的性能。注意,與 Microsoft Windows NT® 4.0/IIS 4.0 相比,Windows 2000/IIS 5.0 中(zhōng)在腳本和 ADO 性能方面有了很大(dà)的改進。因此,随着 IIS 5.0 的推出,編譯代碼比 ASP 代碼的性能優勢有所降低。
有關在 ASP 中(zhōng)使用 COM 的優點和缺點的詳細讨論,參見 ASP Component Guidelines and Programming Distributed Applications with and Microsoft Visual Basic 6.0。如果您部署 COM 組件,以負荷對它們進行測試特别重要。事實上,理所當然應對所有的 ASP 應用程序進行負荷測試。
技巧 8:遲一(yī)點獲得資(zī)源,早一(yī)點釋放(fàng)資(zī)源
這裏是一(yī)個小(xiǎo)技巧供您參考。一(yī)般來說,最好遲一(yī)點獲得資(zī)源,早一(yī)點釋放(fàng)資(zī)源。這适用于 COM 對象以及文件句柄和其它資(zī)源。
這種優化方法主要用于 ADO 連接和記錄集。當您使用完記錄集,比方說在顯示一(yī)個表及其數據之後,應立即釋放(fàng)它,而不是等到頁面結束時再釋放(fàng)。将 VBScript 變量設置爲 Nothing 是最好的做法。不要讓記錄集超出作用域之外(wài)。而且,要釋放(fàng)任何相關的 Command 或 Connection 對象(在将記錄集或連接設置爲 = Nothing 之前,不要忘記調用 Close())。這會縮短數據庫必須爲您準備資(zī)源的時間,并盡快釋放(fàng)數據庫到連接池的連接。
技巧 9:進程外(wài)執行過程以性能換取可靠性
ASP 和 MTS/COM+ 兩者都有配置選項,可使您兼顧可靠性和性能。當建立和部署應用程序時,應知(zhī)道如何兼顧兩者的性能。
ASP 選項
可以配置 ASP 應用程序,以便以三種方法之一(yī)運行。在 IIS 5.0 中(zhōng),引入了“隔離(lí)級”這一(yī)術語以說明這些選項。這三個隔離(lí)級分(fēn)别是低級、中(zhōng)級和高級:
低級隔離(lí)。這在 IIS 的所有版本中(zhōng)都得到支持,且是最快的。它在 Inetinfo.exe 中(zhōng)運行 ASP,Inetinfo.exe 是主要 IIS 進程。如果 ASP 應用程序崩潰,IIS 也會崩潰。(要在 IIS 4.0 下(xià)重新啓動 IIS,Web 站點管理員(yuán)應使用諸如 InetMon 之類的工(gōng)具監視站點,如果服務器發生(shēng)故障,應啓用批處理文件以重新啓動服務器。IIS 5.0 引入了可靠的重新啓動,該方法可使發生(shēng)故障的服務器自動重新啓動。)
中(zhōng)級隔離(lí)。IIS 5.0 引入了這個新的級别,它被稱爲進程外(wài)級别,因爲 ASP 在 IIS 進程之外(wài)運行。在中(zhōng)級隔離(lí)中(zhōng),被配置作爲中(zhōng)級隔離(lí)運行的所有 ASP 應用程序都共享一(yī)個進程空間。這就減少了在一(yī)台服務器運行多個進程外(wài) ASP 應用程序所需要的進程數量。中(zhōng)級隔離(lí)是 IIS 5.0 中(zhōng)的默認隔離(lí)級别。
高級隔離(lí)。在 IIS 4.0 和 IIS 5.0 中(zhōng)支持這一(yī)級别,高級隔離(lí)也是進程外(wài)的。如果 ASP 崩潰,Web 服務器并不會崩潰。下(xià)次 ASP 請求時,ASP 應用程序就會自動重新啓動。在高級隔離(lí)中(zhōng),配置作爲高級隔離(lí)運行的每個 ASP 應用程序都在其自有進程空間中(zhōng)運行。這樣做可保護 ASP 應用程序彼此之間不相互幹擾。其缺點是它要求每個 ASP 應用程序都要有一(yī)個單獨的進程。當在一(yī)台服務器上必須運行許多應用程序時,系統開(kāi)銷就會大(dà)大(dà)增加。
哪個選項最好的呢?在 IIS 4.0 中(zhōng),進程外(wài)運行将顯著降低性能。在 IIS 5.0 中(zhōng),做了許多改進,将進程外(wài)運行 ASP 應用程序所産生(shēng)的開(kāi)銷降到最低限度。事實上,在絕大(dà)多數測試中(zhōng),IIS 5.0 中(zhōng)的 ASP 進程外(wài)應用程序比 IIS 4.0 中(zhōng)的進程内應用程序運行得更快。不管怎樣,在兩個平台上,進程内(低隔離(lí)級)性能最佳。但是,如果訪問率相對較低或最大(dà)吞吐量較低,低隔離(lí)級的優勢不太明顯。因此,在您每一(yī) Web 服務器每秒鍾需要數百或成千上萬頁面時,才會覺得有必要設置低隔離(lí)級。與往常一(yī)樣,應對多種配置進行測試,确定您要采取哪一(yī)種折衷方案。
注意 當您運行 ASP 進程外(wài)應用程序時(中(zhōng)級或高級隔離(lí)),它們在 NT4 中(zhōng)的 MTS 和在 Windows 2000 中(zhōng)的 COM+ 中(zhōng)運行。即,在 NT4 中(zhōng)它們在 Mtx.exe 中(zhōng)運行;而在 Windows 2000 中(zhōng),它們在 DllHost.exe 中(zhōng)運行。您可以在任務管理器中(zhōng)看到這些進程在運行。您還可以看到 IIS 如何爲進程外(wài) ASP 應用程序配置 MTS 程序包或 COM+ 應用程序。
COM 選項
COM 組件也有三種配置選項,雖然與 ASP 選項不完全類似。COM 組件可以是“未配置的”、配置爲庫應用程序或配置爲服務器應用程序。“未配置的”意思是指組件沒有注冊 COM+。組件将在調用程序的進程空間運行,那就是說,它們是“進程内的”。庫應用程序也是進程内的,但使用 COM+ 的服務,包括安全、事務和上下(xià)文支持。服務器應用程序被配置爲在它們自有的進程空間内運行。
您可以看到未配置的組件比庫應用程序略有一(yī)些優勢。庫應用程序比服務器應用程序的性能優點更大(dà)。這是因爲庫應用程序與 ASP 在同一(yī)進程内運行,而服務器應用程序在它們的自有進程内運行。進程間的調用比進程内調用開(kāi)銷更大(dà)。而且,當在進程之間傳遞諸如記錄集之類的數據時,必須在兩個進程之間複制所有的數據。
陷阱!當使用 COM 服務器應用程序時,如果您在 ASP 和 COM 之間傳遞對象,要确保對象執行“按值彙集”或 MBV。執行 MBV 的對象将它們自己從一(yī)個進程複制到另一(yī)個進程。這比下(xià)面一(yī)種方法好,采用這種方法時,對象仍在創建者的進程中(zhōng),另外(wài)一(yī)個進程反複地調用創建進程以使用該對象。切斷連接的 ADO 記錄集将“按值彙集”,連接的記錄集則不然。Scripting.Dictionary 不執行 MBV,且不在進程之間傳遞。最後,VB 程序員(yuán)請注意:MBV 不通過傳遞參數 ByVal 獲得。MBV 由原始的組件作者執行。
怎麽辦?
如果讓我(wǒ)(wǒ)們建議一(yī)個兼顧性能與可靠性的合理配置,它們應是如下(xià)的配置:
在 IIS 4.0 中(zhōng),使用 ASP 低隔離(lí)級别,使用 MTS 服務器程序包。
在 IIS 5.0 上,使用 ASP 的中(zhōng)隔離(lí)級,并使用 COM+ 庫應用程序。
這些是非常一(yī)般的原則,主機服務公司一(yī)般情況下(xià)以中(zhōng)或高隔離(lí)級運行 ASP,而單用途的 Web 服務器可以以低隔離(lí)級運行。衡量各種利弊,并自己決定哪個配置更能符合您的需要。
技巧 10:使用顯式選項
在 .asp 文件中(zhōng)應使用 Option Explicit。此指令放(fàng)在 .asp 文件的最上面,它強制開(kāi)發人員(yuán)聲明要使用到的所有變量。許多程序員(yuán)認爲這種方法對于調試應用程序很有幫助,因爲這種方法避免了鍵錯變量名和誤建新變量的可能性(例如,将 MyXMLString=) 錯寫成 MyXLMString=...。
更重要的一(yī)點也許是,聲明的變量比未聲明的變量速度更快。由此,腳本在運行時每次用到未聲明的變量時,按名稱引用它。另一(yī)方面,聲明的變量是有順序的,要麽以編譯時間,要麽以運行時間。以後,聲明的變量都按此順序引用。因爲 Option Explicit 強制變量聲明,它能确保聲明所有變量,因此訪問的速度也很快。
技巧 11:在子例程和函數中(zhōng)使用局部變量
局部變量是那些在子例程和函數内聲明的變量。在函數或子例程内,局部變量訪問比全局變量訪問更快。局部變量的使用也會使代碼更清晰,因此應盡量使用局部變量。
技巧 12:将經常使用的數據複制到腳本變量中(zhōng)
當訪問 ASP 中(zhōng)的 COM 對象時,應将經常使用的對象數據複制到腳本變量中(zhōng)。這樣做可減少 COM 方法調用,因爲 COM 方法調用與訪問腳本變量相比,開(kāi)銷相對較大(dà)。當訪問 Collection 和 Dictionary 對象時,這種技術也會減少開(kāi)銷很大(dà)的查找。
一(yī)般來說,如果您打算不止一(yī)次訪問對象數據,那麽就應将數據放(fàng)到腳本變量中(zhōng)。這種優化的主要目标是 Request 變量(Form 和 QueryString 變量)。例如,您的站點可傳遞一(yī)個名爲 UserID 的 QueryString 變量。假設此 UserID 在特定頁面上被引用 12 次。可以無須調用 Request(?UserID?) 12 次,而是在 ASP 頁面最上面将 UserID 指派到一(yī)個變量。然後在該頁面自始至終使用該變量。這樣就省去(qù)了 11 次 COM 方法調用。
實際上,訪問 COM 屬性或方法的開(kāi)銷并沒有那麽大(dà)。下(xià)面舉一(yī)個例子,說明某相當常見的代碼(從語法上講):
Foo.bar.blah.baz = Foo.bar.blah.qaz(1)
If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...
當此代碼運行時,下(xià)面是發生(shēng)的情況:
變量 Foo 被解析爲全局對象。
變量 bar 被解析爲 Foo 的成員(yuán)。這實際就是一(yī)次 COM 方法調用。
變量 blah 被解析爲 Foo.bar 的成員(yuán)。這又(yòu)是一(yī)次 COM 方法調用。
變量 qaz 被解析爲 foo.bar.blah 的成員(yuán)。沒有錯,這還是一(yī)次 COM 方法調用。
調用 Foo.bar.blah.quaz(1)。再一(yī)次 COM 方法調用。懂了嗎(ma)?
再次執行步驟 1 至步驟 3 以解析 baz。系統并不知(zhī)道調用 qaz 是否改變對象模型,因此必須再次執行步驟 1 至 3 以解析 baz。
将 baz 解析爲 Foo.bar.blah 的成員(yuán)。賦予屬性。
再次執行步驟 1 至步驟 3 以解析 zaq。
再次執行步驟 1 至步驟 3 以解析 abc。
正如您可看到的,效率相當差(且慢(màn))。以 VBScript 寫此代碼的快速方法是:
Set myobj = Foo.bar.blah ' do the resolution of blah ONCE
Myobj.baz = myobj.qaz(1)
If Myobj.zaq = Myobj.abc Then '...
如果您使用 VBScript 5.0 或更高版本,您可以使用 With 語句寫此代碼:
With Foo.bar.blah
.baz = .qaz(1)
If .zaq = .abc Then '...
...
End With
注意此技巧也适用于 VB 程序設計。
技巧 13:避免重新确定數組的維數
應盡量避免 Redim 數組。就性能而言,如果計算機的物(wù)理内存大(dà)小(xiǎo)有限,最好将數組的初始維數設置爲其最不利的情況 - 或将維數設置爲其最佳的情況,然後再按需要重新确定維數。這并非意味着,如果知(zhī)道您不需要内存時,就随便分(fēn)配幾兆字節的内存。
下(xià)面的代碼給您顯示使用 Dim 和 Redim 不當的情形。
<%
Dim MyArray()
Redim MyArray(2)
MyArray(0) = ?hello?
MyArray(1) = ?good-bye?
MyArray(2) = ?farewell?
...
' some other code where you end up needing more space happens, then ...
Redim Preserve MyArray(5)
MyArray(3) = ?more stuff?
MyArray(4) = ?even more stuff?
MyArray(5) = ?yet more stuff?
%>
最好一(yī)開(kāi)始就将數組的初始大(dà)小(xiǎo) Dim 正确(在本例中(zhōng),是 5)比 Redim 數組使其更大(dà)好得多。您可能浪費(fèi)一(yī)些内存(如果您沒有使用所有的元素),但獲得的好處是速度變得更快。
技巧 14:使用響應緩沖
您可以通過啓用“響應緩沖”,将要輸出的一(yī)整頁緩沖起來。這樣就将寫到浏覽器的量減到最少,從而改善總體(tǐ)性能。每個寫操作都會産生(shēng)很大(dà)的系統開(kāi)銷(在 IIS 中(zhōng)以及在通過網絡發送的數據量方面),因此寫操作越少越好。由于其啓動慢(màn)且使用 Nagling 算法(用來減輕網絡塞車(chē)情況),TCP/IP 在發送一(yī)些大(dà)的數據塊時比必須發送許多小(xiǎo)的數據塊時的效率高得多。
有兩個方法啓用響應緩沖。第一(yī)種,您可以使用 Internet Services Manager 爲整個應用程序啓用響應緩沖。我(wǒ)(wǒ)們建議采用這種方法,在 IIS 4.0 和 IIS 5.0 中(zhōng)默認爲新的 ASP 應用程序啓用響應緩沖。第二種,可以在每個 ASP 頁面的接近頂端的地方加入下(xià)面的代碼行,從而啓用響應緩沖:
<% Response.Buffer = True %>
此代碼行必須在任何響應數據被寫到浏覽器之前執行(即,在任何 HTML 出現在 ASP 腳本之前以及在使用 Response.Cookies 集合設置任何 Cookies 之前)。一(yī)般來說,最好爲整個應用程序啓用響應緩沖。這樣,您就不必在每個頁面最上面寫入上述的代碼行。
Response.Flush
關于響應緩沖有一(yī)個常見的抱怨,就是用戶感覺到 ASP 頁面的響應速度很慢(màn)(即使整個響應時間得到改進),因爲他們必須等到整個頁面生(shēng)成,然後他們才能看到東西。對于運行時間長的頁面,您可以設置 Response.Buffer = False,禁用響應緩沖。但是,一(yī)個更好的策略是利用 Response.Flush 方法。這種方法将 ASP 轉換的所有 HTML 送到浏覽器。例如,在轉換 1,000 行的表的前 100 行之後,ASP 可以調用 Response.Flush,強制将轉換的結果送到浏覽器,這樣可使用戶在其餘的行準備好之前看到頭 100 行。這種技術可以将響應緩沖與浏覽器逐漸顯示數據完美地結合在一(yī)起。
(注意在上面的 1,000 行表的舉例中(zhōng),許多浏覽器在它們看到關閉 </table> 标記之前不會開(kāi)始顯示表。檢查您的目标浏覽器是否支持。爲避免這種情況,将表分(fēn)成多個具有較少行的表,并在每個表之後調用 Response.Flush。較新版本的 Internet Explorer 在表完全下(xià)載之前就開(kāi)始顯示表,如果您指定表列寬,顯示速度就會特别快,這樣做可避免強制 Internet Explorer 通過測量每個單元格的内容寬度來計算列寬。)
另一(yī)個關于響應緩沖的常見的抱怨是,當産生(shēng)非常大(dà)的頁面時,将占用許多服務器内存。撇開(kāi)産生(shēng)大(dà)頁面的方法不談,這種問題也可通過巧妙使用 Response.Flush 來加以解決。
技巧 15:批處理内嵌腳本和 Response.Write 語句
VBScript 語法 <% = expression %> 将“expression”的值寫到 ASP 輸出流中(zhōng)。如果響應緩沖未啓用,那麽執行其中(zhōng)的每一(yī)條語句,都會以許多小(xiǎo)的數據包通過網絡将數據寫到浏覽器中(zhōng)。這樣速度很慢(màn)。而且穿插執行少量的腳本和 HTML,将引起腳本引擎和 HTML 之間的切換,從而降低性能。因此,使用下(xià)面的技巧:使用 Response.Write 調用代替捆綁緊密的内嵌表達式。例如,在下(xià)面的示例中(zhōng),在每一(yī)行的每一(yī)字段對響應流有一(yī)次寫操作,每一(yī)行在 VBScript 和 HTML 之間有許多切換:
<table>
<% For Each fld in rs.Fields %>
<th><% = fld.Name %></th>
<%
Next
While Not rs.EOF
%>
<tr>
<% For Each fld in rs.Fields %>
<td><% = fld.value %></td>
<% Next
</tr>
<% rs.MoveNext
Wend %>
</table>
下(xià)面的代碼更有效,每一(yī)行對響應流有一(yī)次寫操作。所有的代碼都包含在一(yī)個 VBScript 塊内:
<table>
<%
For each fld in rs.Fields
Response.Write (?<th>? & fld.Name & ?</th>? & vbCrLf)
Next
While Not rs.EOF
Response.Write (?<tr>?)
For Each fld in rs.Fields %>
Response.Write(?<td>? & fld.value & ?</td>? & vbCrLf)
Next
Response.Write ?</tr>?
Wend
%>
</table>
當禁用響應緩沖時,這一(yī)技巧的效果特别大(dà)。最好啓用響應緩沖,然後看批處理 Response.Write 是否有助于提高性能。
(在這一(yī)特定舉例中(zhōng),建立表主體(tǐ)的嵌套循環 (While Not rs.EOF...) 可以用仔細構建的 GetString 調用來替代。)
技巧 16:如果頁面需要很長時間才能完成,那麽執行前使用 Response.IsClientConnected
如果用戶性急,他們可能會在您開(kāi)始執行他們的請求之前,就會放(fàng)棄 ASP 頁面。如果他們單擊刷新或移到服務器上的另一(yī)個頁面,在 ASP 請求隊列的末尾就有一(yī)個新的請求等候,在隊列的中(zhōng)間有一(yī)個斷開(kāi)連接的請求。當服務器的負載很高時(因此請求隊列就會很長,響應時間也會相應地變長),就會經常發生(shēng)這種情況,這樣隻能使情況變得更糟。如果用戶不再連接,執行 ASP 頁面(特别是慢(màn)的、大(dà)的 ASP 頁面)已沒有任何意義。您可以使用 Response.IsClientConnected 屬性檢查這一(yī)情況。如果它返回 False,則應調用 Response.End 并放(fàng)棄頁的其餘部分(fēn)。事實上,IIS 5.0 已将這一(yī)做法編爲程序 - 每當 ASP 即将執行新請求時,它就會檢查請求在隊列中(zhōng)已等候了多長時間。如果已經在那裏等候了多于 3 秒鍾,ASP 将檢查客戶機是否仍處于連接狀态,如果沒有連接,就立即終止請求。您可以在配置數據庫中(zhōng)使用 AspQueueConnectionTestTime 設置将超時時間由 3 秒調整爲其它值。
如果頁面要花很長時間才能執行完,也可以不時地檢查 Response.IsClientConnected。當啓用了響應緩沖時,最好不時地執行 Response.Flush,以用戶知(zhī)道,正在發生(shēng)什麽事。
注意 在 IIS 4.0 上,除非先執行了 Response.Write,否則 Response.IsClientConnected 就不能正常工(gōng)作。如果啓用了緩沖,您也必須執行 Response.Flush。在 IIS 5.0 上,卻沒有必要這樣做,- Response.IsClientConnected 工(gōng)作正常。在任何情況下(xià),Response.IsClientConnected 都會有一(yī)些開(kāi)銷,因此隻有在一(yī)個操作至少要花(比方說) 500 毫秒(如果您想維持每秒鍾數十頁的吞吐量,這是一(yī)個很長的時間)才使用它。經驗表明,不要每次重複執行緊密循環時都調用它,如顯示表的許多行時 - 每隔二十或五十行調用一(yī)次可能比較合适。
技巧 17:使用 <OBJECT> 标記例示對象
如果要引用不在所有代碼路徑(特别是服務器或應用程序作用域的對象)中(zhōng)使用的對象,使用 Global.asa 中(zhōng) <object runat=server id=objname> 标記聲明它們,而不使用 Server.CreateObject 方法。Server.CreateObject 能立即創建對象。如果以後不再使用該對象,您就浪費(fèi)了資(zī)源。<object id=objname> 标記聲明 objname,但在其方法或屬性第一(yī)次使用以前,不會創建 objname。
這又(yòu)是一(yī)個惰性計算的例子。
技巧 18:對于 ADO 和其它組件使用 TypeLib 聲明
當使用 ADO 時,開(kāi)發人員(yuán)經常加入 adovbs.txt,以訪問 ADO 的各種常量。在要使用常量的每個頁面中(zhōng)必須包含此文件。此常量文件相當大(dà),給每個 ASP 頁面的編譯時間和腳本大(dà)小(xiǎo)增加了許多系統開(kāi)銷。
IIS 5.0 引入了綁定到組件類型庫的功能。這可使您引用類型庫一(yī)次,并将其用在每個 ASP 頁面上。每個頁面不會産生(shēng)編譯常量文件的開(kāi)銷,且組件開(kāi)發人員(yuán)不必建立 VBScript#_include 文件以在 ASP 上使用。
要訪問 ADO TypeLib,将下(xià)面一(yī)條語句放(fàng)在 Global.asa 中(zhōng)。
<!-- METADATA NAME=?Microsoft ActiveX Data Objects 2.5 Library?
TYPE=?TypeLib? UUID=?{00000205-0000-0010-8000-00AA006D2EA4}? -->
或
<!-- METADATA TYPE=?TypeLib?
FILE=?C:\Program Files\Common Files\system\ado\msado15.dll? -->
技巧 19: 利用浏覽器的驗證功能
現今的浏覽器對一(yī)些高級功能如 XML、DHTML、Java 小(xiǎo)程序和遠程數據服務提供支持。盡可能使用這些功能。所有這些技術都可以執行客戶機端驗證和數據緩存,免去(qù)了到 Web 服務器的往返。如果您在運行一(yī)個智能浏覽器,那麽浏覽器就能爲您進行一(yī)些驗證(例如,在執行 POST 之前,檢查信用卡校驗和是否有效)。盡可能使用這一(yī)功能。通過減少客戶-服務器之間的往返,可降低 Web 服務器上的負載,并能減少網絡通信量(雖然發送到浏覽器的第一(yī)個頁面可能比較大(dà))以及服務器訪問的任何後端資(zī)源。此外(wài),用戶不必像住常一(yī)樣讀取新頁,從而用戶的感覺會好一(yī)些。這樣做并不意味着您可以不進行服務器端驗證 - 您還應始終進行服務器端驗證。這可以防止由于某種原因(如黑客,或浏覽器不運行客戶機端驗證例程)客戶機産生(shēng)錯誤的數據。
人們已經進行了大(dà)量的工(gōng)作,開(kāi)發“獨立于浏覽器”的 HTML。正是由于這種憂慮,開(kāi)發人員(yuán)不願再使用流行的浏覽器功能,但這些功能本可以改善性能。對于一(yī)些真正的高性能站點,必須關心浏覽器“訪問”問題,一(yī)個好的策略是優化頁面,使其适應流行的浏覽器。使用浏覽器功能組件,可以在 ASP 中(zhōng)方便地檢測到浏覽器功能。Microsoft FrontPage 等工(gōng)具有助于設計适合于浏覽器和指定 HTML 版本的代碼。參見 When is Better Worse?Weighing the Technology Trade-Offs,以了解更進一(yī)步的讨論。
技巧 20:避免在循環語句中(zhōng)使用字符串串聯
許多人在循環語句中(zhōng)建立一(yī)個字符串,如下(xià)所示:
s = ?<table>? & vbCrLf
For Each fld in rs.Fields
s = s & ? <th>? & fld.Name & ?</th> ?
Next
While Not rs.EOF
s = s & vbCrLf & ? <tr>?
For Each fld in rs.Fields
s = s & ? <td>? & fld.value & ?</td> ?
Next
s = s & ? </tr>?
rs.MoveNext
Wend
s = s & vbCrLf & ?</table>? & vbCrLf
Response.Write s
采用這種方法會出現一(yī)些問題。第一(yī)個問題是反複串聯字符串需要花兩次方的時間,更通俗地說,運行這種循環語句所花的時間與記錄數乘以字段數所得值的平方成正比。舉一(yī)個更簡單的例子,就可以更清楚地說明這一(yī)問題。
s = ??
For i = Asc(?A?) to Asc(?Z?)
s = s & Chr(i)
Next
在第一(yī)次叠代中(zhōng),您獲得了一(yī)個字符的字符串 ?A?。在第二次叠代中(zhōng),VBScript 必須重新分(fēn)配字符串并将兩個字符 (?AB?) 複制到 s 中(zhōng)。在第三次叠代中(zhōng),它還必須再次重新分(fēn)配 s 并将三個字符複制到 s 中(zhōng)。在 N 次(第 26 次)叠代中(zhōng),它必須重新分(fēn)配并将 N 個字符複制到 s 中(zhōng)。總共就是 1+2+3+...+N,即 N*(N+1)/2 次複制。
在上面的記錄集舉例中(zhōng),如果有 100 個記錄和 5 個字段,内循環将執行 100*5 = 500 次,所有的複制和重新分(fēn)配所花的時間與 500*500 = 250,000 成正比。這對于中(zhōng)等大(dà)小(xiǎo)的記錄集來說複制操作太多了。
在本例中(zhōng),代碼可以用 Response.Write() 或内嵌腳本 (<% = fld.value %>) 替代字符串串聯來改進。如果啓用了響應緩沖的話(huà)(應該的),這樣做就會更快,因爲 Response.Write 隻将數據附加到響應緩沖的末尾。并不涉及重新分(fēn)配,因此效率很高。
在将 ADO 記錄集轉換爲 HTML 表的特定情況下(xià),應考慮使用 GetRows 或 GetString。
如果在 JScript 中(zhōng)串聯字符串,特别建議使用 += 運算符,即,使用 s += ?某字符串?,而不使用 s = s + ?某字符串?。
技巧 21:啓用浏覽器和代理緩存
在默認情況下(xià),ASP 禁止在浏覽器和代理中(zhōng)進行緩存。這是有意義的,因爲就實質而言 ASP 頁面是動态的,上面有随時間不斷變化的潛在信息。如果頁面不要求在每個視圖上進行刷新,您應啓用浏覽器和代理緩存。這可使浏覽器和代理在一(yī)定的時間内使用頁面的“緩存”副本,您可以控制時間的長短。緩存可以大(dà)大(dà)減輕服務器上的負載,縮短用戶的等待時間。
哪一(yī)種動态頁面可作爲要緩存的頁面呢?下(xià)面舉一(yī)些例子:
天氣預報頁面,在此頁面上,每隔 5 分(fēn)鍾更新一(yī)次天氣預報。
列出新聞條目或新聞稿的主頁,它一(yī)天更新兩次。
共同基金業績列表,在此列表中(zhōng),基本統計信息每隔幾小(xiǎo)時更新一(yī)次。
注意,在使用浏覽器或代理緩存的情況下(xià),Web 服務器上記錄的訪問次數減少了。如果您想準确地測量所有頁面視圖或張帖公布,您就不希望使用浏覽器和代理緩存。
浏覽器緩存由 HTTP“過期”報頭控制,該報頭由 Web 服務器發送給浏覽器。ASP 提供兩個簡單的機制發送此報頭。要設置頁面使其過多少分(fēn)鍾後到期,則應設置 Response.Expires 屬性。下(xià)面的例子告訴浏覽器内容在 10 分(fēn)鍾内過期:
<% Response.Expires = 10 %>
若将 Response.Expires 設置爲負數或 0,則禁用緩存。一(yī)定要使用大(dà)的負數,如 -1000(略多于一(yī)天),以避免服務器和浏覽器時鍾之間的不匹配。第二個屬性 Response.ExpiresAbsolute 将使您設置内容過期的具體(tǐ)時間:
<% Response.ExpiresAbsolute = #May 31,2001 13:30:15# %>
您可以不使用 Response 對象設置過期時間,而将 <META> 标記寫進 HTML,通常寫在 HTML 文件的 <HEAD> 部分(fēn)。一(yī)些浏覽器将遵照此指令,而代理則不然。
<META HTTP-EQUIV=?Expires? value=?May 31,2001 13:30:15?>
最後,您可以使用 Response.CacheControl 屬性,指示其内容是否可以讓 HTTP 代理緩存。若将此屬性設置爲“Public”,代理就可以緩存此内容。
<% Response.CacheControl = ?Public? %>
在默認情況下(xià),此屬性被設置爲“Private”。注意,對于顯示某用戶特定數據的頁面,不應啓用代理緩存,因爲代理可能給用戶提供屬于其他用戶的頁面。
技巧 22:盡可能使用 Server.Transfer 代替 Response.Redirect
Response.Redirect 讓浏覽器請求另一(yī)個頁面。此函數常用來将用戶重定向到一(yī)個登錄或錯誤頁面。因爲重定向強制請求新頁面,結果是浏覽器必須到 Web 服務器往返兩次,且 Web 服務器必須多處理一(yī)個請求。IIS 5.0 引入了一(yī)個新的函數 Server.Transfer,它将執行轉移到同一(yī)台服務器上的另一(yī)個 ASP 頁。這樣就避免多餘的浏覽器-Web-服務器的往返,從而改善了總體(tǐ)系統性能以及縮短了用戶的響應時間。檢查“重定向”中(zhōng)的“新的方向”,上面應該是 Server.Transfer 和 Server.Execute。
另請參見 Leveraging ASP in IIS 5.0,了解 IIS 5.0 和 ASP 3.0 新功能的完整列表。
技巧 23:在目錄 URL 中(zhōng)使用後斜杠
一(yī)個相關的技巧是确保在指向目錄的 URL 中(zhōng)使用後斜杠 (/)。如果您省略了後斜杠,浏覽器就會向服務器發出請求,隻是爲了告訴服務器,它在請求目錄。浏覽器就會發出第二個請求,将斜杠附加到 URL 後面,隻有此後,服務器才能以該目錄的默認文檔或目錄列表(如果沒有默認文檔且啓用了目錄浏覽的話(huà))響應。附加斜杠可省去(qù)第一(yī)個、無用的住返。爲便于用戶閱讀,可以省略顯示名稱中(zhōng)的後斜杠。
例如,寫:
<a href=?http://msdn.microsoft.com/workshop/? title=?MSDN Web
Workshop?>http://msdn.microsoft.com/workshop</a>
這也适用于指向 Web 站點上主頁的 URL:使用下(xià)面的:<a href=?http://msdn.microsoft.com/?>,而不使用 <a href=?http://msdn.microsoft.com?>。
技巧 24:避免使用服務器變量
訪問服務器變量會使 Web 站點向服務器發出一(yī)個特殊請求,并收集所有服務器變量,而不隻是您請求的那個變量。這種情況類似于,在發黴的閣樓上,在一(yī)個文件夾中(zhōng)查找某個文件。當您想要找那個文件時,您必須去(qù)閣樓上,先找到文件夾,然後才能找到這份文件。當您請求服務器變量時,發生(shēng)的情況是一(yī)樣的 - 您第一(yī)次請求服務器變量時,就會使性能受到影響。後面的對其它服務器變量的請求,則不會對性能産生(shēng)影響。
決不要訪問非限定的 Request 對象(例如,Request("Data"))。對于不在 Request.Cookies、Request.Form、Request.QueryString 或 Request.ClientCertificate 中(zhōng)的項目,則隐式調用 Request.ServerVariables。Request.ServerVariables 集合比其它集合慢(màn)得多。
技巧 25:升級到最新和最出色的
系統組件是恒定的,我(wǒ)(wǒ)們建議您将它們升級到最新和最好的配置。最好升級到 Windows 2000(因此,也應升級到 IIS 5.0、ADO 2.5、MSXML 2.5、Internet Explorer 5.0、VBScript 5.1 和 JScript 5.1)。在多處理器計算機上,實施 IIS 5.0 和 ADO 2.5 可顯著改善性能。在 Windows 2000 下(xià),ASP 可以很好地擴展到四個處理器或更多,而在 IIS 4.0 下(xià),ASP 的擴展性不能超出兩個處理器。在應用程序中(zhōng)使用的腳本代碼和 ADO 越多,升級到 Windows 2000 之後,性能的改善就會越多。
如果目前還不能升級到 Windows 2000,您可以升級到 SQL Server、ADO、VBScript 和 JScript、MSXML、Internet Explorer 和 NT 4 Service Packs 的最新版本。它們均可提高性能和可靠性。
技巧 26:優化 Web 服務器
有多種 IIS 優化參數可以改善站點性能。例如,對于 IIS 4.0,我(wǒ)(wǒ)們常常發現,增加 ASP ProcessorThreadMax 參數(參見 IIS 文檔)可以顯著改善性能,特别是在傾向于等待後端資(zī)源(如數據庫)或其它中(zhōng)間産品(如屏幕刷)的站點上。在 IIS 5.0 中(zhōng),您可能發現啓用 ASP Thread Gating 比查找一(yī)個 AspProcessorThreadMax 最佳設置效率更高,這一(yī)點現在已爲大(dà)家所熟知(zhī)。
有關較好的參考資(zī)料,參見下(xià)面的優化 IIS。
最佳的配置設置取決于(其中(zhōng)一(yī)些因素)應用程序代碼、運行所在的系統硬件和客戶機工(gōng)作負荷。找到最佳設置的唯一(yī)方法是進行性能測試,這是我(wǒ)(wǒ)們在下(xià)一(yī)個技巧中(zhōng)所要讨論的。
技巧 27:進行性能測試
正如我(wǒ)(wǒ)們在前面已經講過,性能是一(yī)個特征。如果您想要改善站點的性能,那麽就制定一(yī)個性能目标,然後逐步改進,直到達到目标爲止。不要,就不進行任何性能測試。通常,在項目結束時,再作必需的結構調整已經爲時太晚,您的客戶将爲此感到失望。将性能測試作爲您日常測試的一(yī)部分(fēn)來進行。可以對單個組件分(fēn)别進行性能測試,如針對 ASP 頁或 COM 對象,或将站點作爲一(yī)個整體(tǐ)來測試。
許多人使用單個浏覽器請求頁面,來測試 Web 站點的性能。這樣做就會給您一(yī)個感覺,即站點的響應能力很好,但這樣做實際上并不能告訴您在負載條件下(xià)站點的性能如何。
一(yī)般情況下(xià),要想準确地測試性能,您需要一(yī)個專門的測試環境。此環境應包括硬件,其處理器速度、處理器數量、内存、磁盤、網絡配置等方面與生(shēng)産環境的硬件相似。其次,您必須指定客戶機的工(gōng)作負荷:有多少同時的用戶,他們發出請求的頻(pín)率,他們點擊頁面的類型等等。如果您沒有站點實際使用情況的數據,您必須估計一(yī)下(xià)使用的情況。最後,您需要一(yī)個可以模拟預期客戶機工(gōng)作負荷的工(gōng)具。有了這些工(gōng)具,您就可以開(kāi)始回答諸如“如果我(wǒ)(wǒ)有 N 個同時的用戶,那麽需要多少服務器?”之類的問題。您還可以找出出現瓶頸的原因,并以此爲目标進行優化。
下(xià)面列出了一(yī)些好的 Web 負載測試工(gōng)具。我(wǒ)(wǒ)們特别推薦 Microsoft Web Application Stress (WAS) 工(gōng)具包。WAS 可使您記錄測試腳本,然後模拟數百或成千上萬個用戶訪問 Web 服務器。WAS 報告很多統計信息,包括每秒鍾的請求數,響應時間分(fēn)布情況和錯誤計數。WAS 有豐富的客戶機界面和基于 Web 的界面兩種,Web 界面可使您進行遠程測試。
一(yī)定要閱讀 IIS 5.0 Tuning Guide。
技巧 28:閱讀資(zī)源鏈接
下(xià)面是一(yī)些與性能有關的出色的資(zī)源鏈接。如果您想了解有關信息,請閱讀 Developing Scalable Web Applications。
資(zī)源
優化 ASP 腳本
優化 IIS
ADO 和 SQL Server
ASP 組件和線程模型
詞典組件
會話(huà)狀态
性能和可擴展性
工(gōng)具
書(shū)目
ASP Web 站點
ASP 樣式
XML
優化 ASP 腳本
Developing Scalable Web Applications
Got Any Cache? Nancy Winnick Cluts 著
Maximizing the Performance of Your Active Server Pages,Nancy Winnick Cluts 著
15 Seconds: Performance Section
Enhancing Performance in ASP - Part I,Wayne Plourde 著
When is Better Worse? Weighing the Technology Trade-Offs,Nancy Winnick Cluts 著
Speed and Optimization Resources,Charles Carroll 著
優化 IIS
The Art and Science of Web Server Tuning with Internet Information Services 5.0
Leveraging ASP in IIS 5.0,J.D. Meier 著
Tuning IIS 4.0 for High Volume Sites,Michael Stephenson 著
Tuning Internet Information Server Performance,Mike Moore 著
Navigating the Maze of Settings for Web Server Performance Optimization,Todd Wanke 著
Managing Internet Information Server 4.0 for Performance,Hans Hugli 著
ADO 和 SQL Server
Top Ten Tips: Accessing SQL Through ADO and ASP,J.D. Meier 著
Improve the Performance of your MDAC Application,Suresh Kannan 著
Pooling in the Microsoft Data Access Components,Leland Ahlbeck 和 Don Willits 合著
SQL Server: Performance Benchmarks and Guides
Improving the Performance of Data Access Components with IIS 4.0,Leland Ahlbeck 著
Microsoft Data Access Components (MDAC) and ActiveX Data Objects (ADO) Performance Tips,Leland Ahlbeck 著
Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Server Perspective,Damien Lindauer 著
Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Application Perspective,Damien Lindauer 著
Accessing Recordsets over the Internet,Dino Esposito 著
ASP 組件和線程模型
ASP Component Guidelines,J.D. Meier 著
Q243548: INFO: Design Guidelines for VB Components under ASP
Threading Models Explained,Nancy Winnick Cluts 著
So Happy Together? Using ActiveX components with Active Server Pages,Nancy Winnick Cluts 著
Developing Active Server Components with ATL,George Reilly 著
Agility in Server Components,Neil Allain 著
Building High-Performance Middle-Tier Components with C++,Jon Flanders 著
Active Server Pages and COM Apartments,Don Box 著
House of COM: Active Server Pages,Don Box 著
House of COM: Contexts,Don Box 著
House of COM: Performance Trade-offs of the Windows 2000 Component Execution Environment,Don Box 著
Building COM Components That Take Full Advantage of Visual Basic and Scripting,Ivo Salmre 著
Component Design Principles for MTS
詞典組件
Creating a Page Cache Object,Robert Coleridge 著
Abridging the Dictionary Object: The ASP Team Creates a Lookup-Table Object,Robert Carter 著
Caprock Dictionary
Site Server Commerce Edition includes a dictionary component
會話(huà)狀态
Q175167: HOWTO: Persisting values Without Sessions
Q157906: HOWTO: How To Maintain State Across Pages with VBScript
XML-based Persistence Behaviors Fix Web Farm Headaches,Aaron Skonnard 著
House of COM: Stateless Programming,Don Box 著
性能和擴展性
Blueprint for Building Web Sites Using the Microsoft Windows DNA Platform
Server Performance and Scalability Killers,George Reilly 著
Microsoft Visual Studio Scalability Center
Fitch & Mather Stocks 2000
Tuning the FMStocks Application
High-Performance Visual Basic Apps,Ken Spencer 著
Duwamish Books,Phase 4
Top Windows DNA Performance Mistakes and How to Prevent Them,Gary Geiger 和 Jon Pulsipher 合著
Building from Static HTML to High-Performance Web-Farms,Shawn Bice 著
工(gōng)具
Microsoft Web Application Stress Tool
I Can't Stress It Enough -- Load Test Your ASP Application,J.D. Meier 著
Windows DNA Performance Kit
Monitoring Events in Distributed Applications Using Visual Studio Analyzer,Mai-lan Tomsen 著
書(shū)目
Professional Active Server Pages 3.0,Wrox Press(特别是第 26 章:Optimizing ASP Performance,George Reilly 和 Matthew Gibbs 合著)。
Microsoft Internet Information Services 5.0 Resource Guide(與 Windows 2000 Server Resource Kit 在一(yī)起),Microsoft Press。
Microsoft Internet Information Server Resource Kit(用于 IIS 4.0),Microsoft Press。
Programming Distributed Applications with COM and Microsoft Visual Basic 6.0,Ted Pattison 著,Microsoft Press。
Effective COM,Don Box、Keith Brown、Tim Ewald 和 Chris Sells 合著;Addison-Wesley。
Developing Web Usability: The Practice of Simplicity,Jakob Nielsen 著,New Riders。
ASP Web 站點
Microsoft TechNet for IIS
LearnASP.com
4GuysFromRolla.com
15Seconds.com
AspToday.com
Asp101.com
AspLists.com。許多專業的郵件列表包括:
Fast Code!
ASP Advanced
Not NewbieState Management
Scalability
Visual Basic Components
XML
C++/ATL Component Building
UseIt.com: Web 可用性
ASP 樣式
ASP Best Practices,George Reilly 著
ASP Quick Lessons,Charles Carroll 著
Planning for ASP,John Meade 著
ASP Guidelines,J.D. Meier 著
XML
Inside XML Performance,Chris Lovett 著
Inside MSXML3 Performance,Chris Lovett 著
Microsoft IIS Performance Lead
改編自Nancy Cluts 的文章 開(kāi)發人員(yuán)技術工(gōng)程師
Microsoft Corporation
2000 年 4 月
摘要:本文介紹優化 ASP 應用程序和 VBScript 的技巧。
引言
性能是一(yī)個特征。您必須預先設計性能,否則您以後就得重寫應用程序。就是說,有哪些好的策略可使 Active Server Pages (ASP) 應用程序性能達到最佳?
本文介紹了優化 ASP 應用程序和 Visual Basic® Scripting Edition (VBScript) 的技巧。本文讨論了許多陷阱。本文列出的建議已經在 http://www.microsoft.com 和其它站點中(zhōng)進行了測試,效果十分(fēn)顯著。本文假定您已經對 ASP 開(kāi)發,包括 VBScript 和/或 JScript、ASP Application、ASP Session 和其它 ASP 固有對象(Request、Response 和 Server)有了基本了解。
通常,ASP 性能主要取決于 ASP 代碼本身以外(wài)的很多因素。我(wǒ)(wǒ)們不在一(yī)篇文章中(zhōng)羅列出所有的信息,在本文結尾處我(wǒ)(wǒ)們列出了與性能有關的資(zī)源。這些鏈接涵蓋了 ASP 和非 ASP 主題,包括 ActiveX® 數據對象 (ADO)、組件對象模型 (COM)、數據庫和 Internet Information Server (IIS) 配置。這些都是我(wǒ)(wǒ)們喜歡的一(yī)些鏈接 - 一(yī)定要去(qù)看看。
技巧 1:将經常使用的數據緩存在 Web 服務器上
典型的 ASP 頁從後端數據存儲中(zhōng)檢索數據,然後将結果轉換成超文本标記語言 (HTML)。無論數據庫的速度如何,從内存中(zhōng)檢索數據總要比從後端數據存儲中(zhōng)檢索數據快得多。從本地硬盤讀取數據通常也比從數據庫中(zhōng)檢索數據更快。因此,通常可以将數據緩存在 Web 服務器上(存儲在内存或磁盤中(zhōng)),來提高性能。
緩存是傳統的以空間換取時間的做法。如果您緩存的内容正确,那麽您可以看到性能會有顯著的提高。爲使緩存有效,必須保存那些經常重複使用的數據,且要重新計算這些數據需要(适度)大(dà)的開(kāi)銷。如果緩存的都是些陳舊(jiù)的數據,就會造成内存浪費(fèi)。
不經常發生(shēng)改變的數據是很好的緩存候選數據,因爲您不必擔心随着時間的遷移該數據與數據庫同步的問題。組合框列表、引用表、DHTML 碎片、擴展标記語言 (XML) 字符串、菜單項和站點配置變量(包括數據源名稱 (DSN)、Internet 協議 (IP) 地址和 Web 路徑)都是很好的緩存候選内容。注意您可以緩存數據的“表示”,而不緩存數據本身。如果 ASP 頁很少更改,且緩存的開(kāi)銷也很大(dà)(例如,整個産品目錄),則應考慮事先産生(shēng) HTML,而不是在響應每個請求時重新顯示。
應将數據緩存在哪裏,有哪些緩存策略?通常,數據緩存在 Web 服務器的内存或磁盤中(zhōng)。下(xià)兩個技巧講述了這兩個方法。
技巧 2: 将經常使用的數據緩存在 Application 或 Session 對象中(zhōng)
ASP Application 和 Session 對象爲将數據緩存在内存中(zhōng)提供了方便的容器。您可以将數據指派到 Application 和 Session 對象中(zhōng),這些數據在 HTTP 調用之間保留在内存中(zhōng)。Session 數據是按每個用戶分(fēn)别存儲的,而 Application 數據則在所有用戶之間共享。
什麽時候将數據裝載到 Application 或 Session 中(zhōng)呢?通常,數據是在啓動 Application 或 Session 時裝載。要在 Application 或 Session 啓動過程中(zhōng)裝載數據,應将适當的代碼分(fēn)别添加到 Application_OnStart() 或 Session_OnStart() 中(zhōng)。這些函數應在 Global.asa 中(zhōng),如果沒有,則可以添加這些函數。還可以在第一(yī)次需要時裝載該數據。爲此,在 ASP 頁中(zhōng)添加一(yī)些代碼(或編寫一(yī)個可重複使用的腳本函數),以檢查數據是否存在,如果不存在,就裝載數據。這是一(yī)個傳統的性能技術,稱爲“惰性計算” - 在您知(zhī)道需要某一(yī)個值以前不計算該值。例如:
<%
Function GetEmploymentStatusList
Dim d
d = Application(?EmploymentStatusList?)
If d = ?? Then
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
Application(?EmploymentStatusList?) = d
End If
GetEmploymentStatusList = d
End Function
%>
可以爲所需要的每個數據塊編寫類似的函數。
應以什麽格式存儲數據?可以存儲任何變體(tǐ)類型,因爲所有腳本變量都是變體(tǐ)型。例如,您可以存儲字符串、整數或數組。通常,您将以這些變量類型之一(yī)存儲 ADO 記錄集的内容。要從 ADO 記錄集獲取數據,您可以手工(gōng)将數據複制到 VBScript 變量,一(yī)次一(yī)個字段。使用一(yī)個 ADO 記錄集持久函數 GetRows()、GetString() 或 Save()(ADO 2.5),可加快速度且更容易一(yī)些。其詳細情況已超出本文所讨論的範圍,但下(xià)面給出了一(yī)個函數舉例,說明使用 GetRows() 返回記錄集數據的一(yī)個數組:
' Get Recordset, return as an Array
Function FetchEmploymentStatusList
Dim rs
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
FetchEmploymentStatusList = rs.GetRows() ? Return data as an Array
rs.Close
Set rs = Nothing
End Function
對上面舉例做更進一(yī)步改進,可以将 HTML 緩存爲列表,而不是數組。下(xià)面是簡單的示例:
' Get Recordset, return as HTML Option list
Function FetchEmploymentStatusList
Dim rs, fldName, s
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
s = ?<select name=??EmploymentStatus??>? & vbCrLf
Set fldName = rs.Fields(?StatusName?) ' ADO Field Binding
Do Until rs.EOF
' Next line violates Don't Do String Concats,
' but it's OK because we are building a cache
s = s & ? <option>? & fldName & ?</option>? & vbCrLf
rs.MoveNext
Loop
s = s & ?</select>? & vbCrLf
rs.Close
Set rs = Nothing ' See Release Early
FetchEmploymentStatusList = s ' Return data as a String
End Function
在适當的條件下(xià),可以将 ADO 記錄集本身緩存在 Application 或 Session 作用域中(zhōng)。有兩個警告:
必須将 ADO 标記爲自由線程
必須使用斷開(kāi)連接的記錄集。
如果不能保證滿足這兩個要求,則不要緩存 ADO 記錄集。在下(xià)面的“非敏捷組件”和“不要緩存連接”技巧中(zhōng),我(wǒ)(wǒ)們将讨論将 COM 對象存儲在 Application 或 Session 作用域中(zhōng)的危險性。
當您将數據存儲在 Application 或 Session 作用域時,數據将保留在那裏,直到您以編程方式改變它、Session 過期或 Web 應用程序重新啓動爲止。如果數據需要更新怎麽辦?要手工(gōng)強制對 Application 數據進行更新,您可以訪問隻有管理員(yuán)才可訪問的 ASP 頁來更新數據。或者,您可以通過函數定期自動刷新數據。下(xià)面例子存儲帶有緩存數據的時間戳,并隔一(yī)段時間後刷新數據。
<%
' error handing not shown...
Const UPDATE_INTERVAL = 300 ' Refresh interval, in seconds
' Function to return the employment status list
Function GetEmploymentStatusList
UpdateEmploymentStatus
GetEmploymentStatusList = Application(?EmploymentStatusList?)
End Function
' Periodically update the cached data
Sub UpdateEmploymentStatusList
Dim d, strLastUpdate
strLastUpdate = Application(?LastUpdate?)
If (strLastUpdate = ??) Or _
(UPDATE_INTERVAL < DateDiff(?s?, strLastUpdate, Now)) Then
' Note: two or more calls might get in here. This is okay and will simply
' result in a few unnecessary fetches (there is a workaround for this)
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
' Update the Application object. Use Application.Lock()
' to ensure consistent data
Application.Lock
Application(?EmploymentStatusList?) = Events
Application(?LastUpdate?) = CStr(Now)
Application.Unlock
End If
End Sub
請參見 World's Fastest ListBox with Application Data,上面還有一(yī)個例子。
要知(zhī)道在 Session 或 Application 對象中(zhōng)緩存大(dà)的數組不是一(yī)個好的做法。在訪問數組的任何元素之前,腳本語言的語法要求必須臨時複制整個數組。例如,如果将由字符串組成的有 100,000 個元素的數組(該數組将美國郵政編碼映射到當地的氣象站)緩存在 Application 對象中(zhōng),ASP 必須先将所有的 100,000 個氣象站複制到臨時數組中(zhōng),然後才能提取一(yī)個字符串。在這種情況下(xià),用自定義方法建立一(yī)個自定義組件來存儲氣象站 - 或使用一(yī)個詞典組件會更好。
再警告大(dà)家一(yī)下(xià),不要将嬰兒與洗澡水一(yī)起倒掉:數組能快速查尋和存儲在内存中(zhōng)是鄰近的關鍵數據對。索引一(yī)個詞典比索引一(yī)個數組要慢(màn)得多。應針對您的實際情況,選擇提供最佳性能的數據結構。
技巧 3:将數據和 HTML 緩存在 Web 服務器的磁盤上
有時,數據可能太多,無法都緩存在内存中(zhōng)。“太多”隻是一(yī)個說法,這要看您想消耗多少内存,以及需緩存的項目數和檢索這些項目的頻(pín)率。在任何情況下(xià),如果數據太多而無法都緩存在内存中(zhōng),則考慮将數據以文本或 XML 文件緩存在 Web 服務器的硬盤上。可以同時将數據緩存在磁盤和内存中(zhōng),爲您的站點建立最适宜的緩存策略。
注意當測量單個 ASP 頁的性能時,檢索磁盤上的數據可能不一(yī)定要比從數據庫檢索數據更快。但緩存會降低數據庫和網絡上的負載。在高負載的情況下(xià),這樣做可大(dà)大(dà)改善總體(tǐ)吞吐量。當緩存開(kāi)銷很大(dà)的查詢結果(如多表聯接或複合存儲過程)或大(dà)的結果集時,這是非常有效的。與往常一(yī)樣,要測試一(yī)下(xià)幾種方案的優劣。
ASP 和 COM 提供一(yī)些建立基于磁盤的緩存方案的工(gōng)具。ADO 記錄集 Save() 和 Open() 函數保存和裝載磁盤中(zhōng)的記錄集。可以使用這些方法重新編寫上面 Application 數據緩存技巧中(zhōng)的代碼示例,用文件的 Save() 代替寫到 Application 對象中(zhōng)的代碼。
有一(yī)些其它組件可以用于文件:
Scripting.FileSystemObject 可使您創建、讀和寫文件。
與 Internet Explorer 一(yī)起提供的 Microsoft® XML 解析器 (MSXML) 支持保存和裝載 XML 文檔。
LookupTable 對象(例如,用在 MSN 上)是從磁盤裝載簡單列表的最好選擇。
最後,應考慮将數據的表示緩存在磁盤上,而不是數據本身。預先轉換的 HTML 可以用 .htm 或 .asp 文件存儲在磁盤上,超級鏈接可以直接指向這些文件。可以使用商(shāng)用工(gōng)具,如 XBuilder,或 Microsoft® SQL Server™ Internet 發布功能将産生(shēng) HTML 的過程自動化。或者,您可以将 HTML 代碼片斷放(fàng)在 .asp 文件中(zhōng)。還可以使用 FileSystemObject 從磁盤讀取 HTML 文件,或使用 XML 盡早轉換。
技巧 4:避免将非敏捷的組件緩存在 Application 或 Session 對象中(zhōng)
盡管将數據緩存在 Application 或 Session 對象中(zhōng)是一(yī)個好的做法,但緩存 COM 對象卻有嚴重的陷阱。通常,人們傾向于将經常使用的 COM 對象緩存到 Application 或 Session 對象中(zhōng)。很遺憾,許多 COM 對象(包括所有以 Visual Basic 6.0 或更低版本編寫的對象)當存儲在 Application 或 Session 對象時,會引起嚴重的瓶頸。
具體(tǐ)來講,當任何不敏捷的組件緩存在 Session 或 Application 對象時,将引起性能瓶頸。敏捷的組件是被标記爲 ThreadingModel=Both 的組件,它聚集 Free-threaded marshaler (FTM);或被标記爲 ThreadingModel=Neutral 的組件。(Neutral 模型是 Windows® 2000 和 COM+ 的新增模型。) 下(xià)列組件不是敏捷的:
自由線程的組件(除非它們聚集 FTM)。
單元線程組件。
單線程組件。
配置的組件(Microsoft Transaction Server (MTS)/COM+ 庫和服務器程序包/應用程序)不是敏捷的,除非它們是 Neutral 線程。單元線程組件和其它非敏捷的組件在頁作用域内是最适合的(即,它們在單個 ASP 頁上創建和銷毀)。
在 IIS 4.0 中(zhōng),被标記爲 ThreadingModel=Both 的組件被認爲是敏捷的。在 IIS 5.0 中(zhōng),隻有這一(yī)點還不夠。組件必須不僅被标記 Both,還必須聚集 FTM。有關敏捷性的文章講述了如何使以 Active Template Library 編寫的 C++ 組件聚集 FTM。要注意如果組件緩存界面指針,那麽那些指針本身必須是敏捷的,或必須存儲在 COM 共用界面表 (GIT) 中(zhōng)。如果您不能重新編譯 Both 線程組件以聚集 FTM,那麽您可以将組件标記爲 ThreadingModel=Neutral。或者,如果您不想讓 IIS 執行敏捷性檢查(因此,您可以允許非敏捷的組件存儲在 Application 或 Session 作用域中(zhōng)),您可以在配置數據庫中(zhōng)将 AspTrackThreadingModel 設置爲 True。不建議更改 AspTrackThreadingModel。
如果您想将以 Server.CreateObject 創建的非敏捷的組件存儲在 Application 對象中(zhōng),IIS 5.0 将出現一(yī)個錯誤。您可以在 Global.asa 中(zhōng)使用 <object runat=server scope=application ...> 避免這一(yī)錯誤,但不建議這樣做,因爲這會導緻彙集和串行化,關于這一(yī)點将在下(xià)面講述。
如果您緩存非敏捷的組件會出現什麽毛病?緩存在 Session 對象中(zhōng)的非敏捷的組件将 Session 鎖定于 ASP 工(gōng)作者線程。ASP 維護一(yī)個工(gōng)作者線程池來處理請求。通常情況下(xià),一(yī)個新請求總是由第一(yī)個可用的工(gōng)作者線程來處理。如果 Session 被鎖定于一(yī)個線程,那麽請求必須等到其相關的線程可用爲止。這裏有一(yī)個類比,也許會有所幫助:您去(qù)一(yī)家超級市場,挑選了一(yī)些商(shāng)品,并在 #_3 收款台付款。其後,每當您在那家超級市場爲商(shāng)品付款時,您總是必須在 #_3 收款台付款,即使其它收款台前排隊的人較少或者沒有人排隊,也是如此。
将非敏捷的組件存儲在 Application 作用域對性能的影響甚至更壞。ASP 必須創建一(yī)個特殊的線程運行存儲在 Application 作用域中(zhōng)的非敏捷組件。這會有兩個結果:所有調用都必須彙集到此線程,且所有調用都排成長隊。“彙集”的意思是參數必須存儲在内存的共享區域;執行一(yī)個開(kāi)銷很大(dà)的到特殊線程的上下(xià)文切換;執行組件的方法;将結果彙集到共享區域;執行另一(yī)個開(kāi)銷很大(dà)的上下(xià)文切換,将控制返回到原始的線程。“串行化”意思是指每次隻運行一(yī)個方法。兩個不同的 ASP 工(gōng)作者線程不能同時在共享組件上執行多個方法。這樣就杜絕了并發性,特别是在多處理器計算機上。更糟的是,所有非敏捷的 Application 作用域的組件共享一(yī)個線程(主機 STA),因此串行化的影響甚至更顯著。
如之奈何?下(xià)面是一(yī)些一(yī)般的規則。如果您使用 Visual Basic (6.0) 或更早版本編寫對象,那麽不要将它們緩存在 Application 或 Session 對象中(zhōng)。如果您不知(zhī)道對象的線程模型,不要緩存它。不要緩存非敏捷的對象,而應在每個頁面創建和釋放(fàng)它們。對象直接在 ASP 工(gōng)作者線程上運行,因此沒有彙集或串行化。如果 COM 對象在 IIS 服務器上運行,且如果它們不花長時間初始化和删除,性能尚可。注意單線程對象不應該這樣使用。小(xiǎo)心 - VB 可創建單線程對象!如果您必須這樣使用單線程對象(如 Microsoft Excel 電子表格),别指望會有很高的吞吐量。
當 ADO 被标記爲自由線程,ADO 記錄集可以安全地緩存。要将 ADO 标記爲自由線程,使用 Makfre15.bat 文件,該文件通常位于目錄 \\Program Files\Common\System\ADO 中(zhōng)。
警告 如果您使用 Microsoft Access 作爲數據庫,不應将 ADO 标記爲自由線程的。ADO 記錄集也必須切斷連接。一(yī)般來說,如果您不能控制站點中(zhōng)的 ADO 配置(例如,您是一(yī)個獨立的軟件廠商(shāng) [ISV],向管理他們自己的配置客戶銷售 Web 應用程序),最好不要緩存記錄集。
詞典組件也是敏捷的對象。LookupTable 從數據文件中(zhōng)裝載其數據,可用于組合框數據和配置信息。Duwamish Books 中(zhōng)的 PageCache 對象可提供詞典語法,Caprock Dictionary 也可提供。這些對象或其派生(shēng)對象可以構成有效緩存策略的基礎。注意 Scripting.Dictionary 對象不是敏捷的,不應該存儲在 Application 或 Session 作用域中(zhōng)。
技巧 5:不要将數據庫連接緩存在 Application 或 Session 對象中(zhōng)
緩存 ADO 連接通常是很糟糕的策略。如果一(yī)個 Connection 對象存儲在 Application 對象中(zhōng),并在所有的頁面中(zhōng)使用,那麽所有頁面将争搶這一(yī)連接。如果 Connection 對象存儲在 ASP Session 對象中(zhōng),那麽将爲每個用戶創建數據庫連接。這就會使連接池的優勢蕩然無存,并給 Web 服務器和數據庫帶來不必要的壓力。
可以不緩存數據庫連接,而是在使用 ADO 的每個 ASP 頁面中(zhōng)創建和删除 ADO 對象。這是很有效的,因爲 IIS 内嵌了數據庫連接池。更準确地說,IIS 自動啓用 OLEDB 和 ODBC 連接池。這就能确保在每個頁面上創建和删除連接将是有效的。
因爲連接的記錄集存儲一(yī)個到數據庫連接的引用,所以您不應将連接的記錄集緩存在 Application 或 Session 對象中(zhōng)。但是,您可以安全地緩存斷開(kāi)連接的記錄集,它們不保存到其數據連接的引用。要斷開(kāi)記錄集連接,執行下(xià)面的兩個步驟:
Set rs = Server.CreateObject(?ADODB.RecordSet?)
rs.CursorLocation = adUseClient ' step 1
' Populate the recordset with data
rs.Open strQuery, strProv
' Now disconnect the recordset from the data provider and data source
rs.ActiveConnection = Nothing ' step 2
有關連接池的更詳細信息,可以在 ADO 和 SQL Server 參考資(zī)料中(zhōng)找到。
技巧 6:合理地使用 Session 對象
既然我(wǒ)(wǒ)們已經讨論了緩存在 Application 和 Session 中(zhōng)的優點,現在開(kāi)始讨論避免使用 Session 對象的問題。正如下(xià)面所讨論的,當與忙的站點一(yī)起使用時,Session 有幾個缺點。“忙”的意思一(yī)般是指一(yī)秒鍾要求幾百頁面或成千上萬同時用戶的站點。這個技巧對于必須水平擴展的站點 - 即,那些利用多台服務器以處理負載或實現容錯的站點 - 甚至更重要。對于較小(xiǎo)的站點,諸如 Intranet 站點,要想實現 Session 帶來的方,必然增大(dà)系統開(kāi)銷。
簡言之,ASP 自動爲每個訪問 Web 服務器的用戶創建一(yī)個 Session。每個 Session 大(dà)約需要 10 KB 的内存開(kāi)銷(最主要的是數據存儲在 Session 中(zhōng)),這就使所有的請求都減慢(màn)。在配置的超時時段(通常是 20 分(fēn)鍾)結束以前,Session 一(yī)直保留有效。
Session 的最大(dà)的問題不是性能,而是可擴展性。Session 不能跨越幾台 Web 服務器,一(yī)旦在一(yī)台服務器上創建 Session,其數據就留在那兒。這就意味着如果您在一(yī)個 Web 服務器群使用 Session,您必須設計一(yī)個策略,将每個用戶請求始終發到用戶 Session 所在的那台服務器上。這被稱爲将用戶“粘”在 Web 服務器上。術語“粘性會話(huà)”就是從這裏派生(shēng)而來的。如果 Web 服務器崩潰,被“粘住的”用戶将丢失他們的會話(huà)狀态,因爲會話(huà)不是粘到磁盤上。
實現粘性會話(huà)的策略包括硬件和軟件解決方案。諸如 Windows 2000 Advanced Server 中(zhōng)的網絡負載平衡和 Cisco 的 Local Director 之類的解決方案都可以實現粘性會話(huà),代價是要損失一(yī)定程度的可擴展性。這些解決方案是不完善的。不建議此時部署您自己的軟件解決方案(我(wǒ)(wǒ)們過去(qù)常常使用 ISAPI 篩選器和 URL 轉換等等)。
Application 對象也不跨越多台服務器,如果您必須跨越 Web 服務器群共享和更新 Application 數據,您必須使用後端數據庫。但是,隻讀 Application 數據在 Web 服務器群中(zhōng)仍是有用的。
如果隻是因爲要增加運行時間(處理故障轉移和服務器維護),大(dà)多數關鍵任務站點至少需部署兩台 Web 服務器。因此,在設計關鍵任務應用程序時,必須實現“粘性會話(huà)”,或幹脆避免使用 Session,以及任何其它将用戶狀态存儲在單個 Web 服務器上的狀态管理技術。
如果您不使用 Session,一(yī)定要将它們關閉。您可以通過 Internet Services Manager,爲應用程序執行此操作(參見 ISM 文檔)。如果您決定使用 Session,您可以采用一(yī)些方法減輕它們對性能的影響。
您可以将不需要 Session 的内容(如幫助屏幕,訪問者區域等等)移到另一(yī)個關閉了 Session 的 ASP 應用程序中(zhōng)。您可以逐頁提示 ASP,您不再需要該頁面上的 Session 對象,使用以下(xià)放(fàng)在 ASP 頁面最上面的指令:
<% @EnableSessionState=False %>
使用這一(yī)指令有一(yī)個很好的理由是,這些 Session 在框架集方面存在一(yī)個有意思的問題。ASP 保證任何時候 Session 隻有一(yī)個請求執行。這樣就确保如果浏覽器爲一(yī)個用戶請求多個頁面,一(yī)次隻有一(yī)個 ASP 請求接觸 Session,這樣就避免了當訪問 Session 對象時發生(shēng)的多線程問題。很遺憾,一(yī)個框架集中(zhōng)的所有頁面将以串行方式顯示,一(yī)個接一(yī)個,而不是同時顯示。用戶可能必須等候很長時間,才能看到所有的框架。該故事的寓意:如果某些框架集頁面不依靠 Session,一(yī)定要使用 @EnableSessionState=False 指令告訴 ASP。
有許多管理 Session 狀态的方法,可替代 Session 對象的使用。對于少量的狀态(少于 4 KB),我(wǒ)(wǒ)們通常建議使用 Cookies、QueryString 變量和隐式變量。對于更大(dà)數據量,如購物(wù)小(xiǎo)車(chē),後端數據庫是最适合的選擇。有關 Web 服務器群中(zhōng)狀态管理技術的文章很多。有關詳細信息,請參見 Session 狀态參考資(zī)料。
技巧 7: 将代碼封裝在 COM 對象中(zhōng)
如果您有許多 VBScript 或 JScript,您可以經常将代碼移到編譯的 COM 對象中(zhōng),從而可改善性能。編譯的代碼通常比解釋的代碼運行得更快。編譯的 COM 對象可以通過“早綁定”訪問其它 COM 對象,與腳本使用的“晚綁定”相比,“早綁定”是調用 COM 對象的更有效方法。
将代碼封裝在 COM 對象中(zhōng)還有一(yī)些優點(除性能之外(wài)):
COM 對象有利于将表示邏輯與業務邏輯分(fēn)開(kāi)。
COM 對象可以保證代碼重複使用。
許多開(kāi)發人員(yuán)發現以 VB、C++ 或 Visual J++ 編寫的代碼比 ASP 更容易調試。
COM 對象也有缺點,包括初始開(kāi)發時間和需要不同的程序設計技巧。注意封裝少量的 ASP 可能引起性能下(xià)降,而不會得到性能改進。這種情況通常在少量的 ASP 代碼被封裝進 COM 對象時發生(shēng)。在這種情況下(xià),創建和調用 COM 對象的系統開(kāi)銷超過了編譯的代碼的優點。應反複地試驗,以确定什麽樣的 ASP 腳本和 COM 對象代碼的組合産生(shēng)最好的性能。注意,與 Microsoft Windows NT® 4.0/IIS 4.0 相比,Windows 2000/IIS 5.0 中(zhōng)在腳本和 ADO 性能方面有了很大(dà)的改進。因此,随着 IIS 5.0 的推出,編譯代碼比 ASP 代碼的性能優勢有所降低。
有關在 ASP 中(zhōng)使用 COM 的優點和缺點的詳細讨論,參見 ASP Component Guidelines and Programming Distributed Applications with and Microsoft Visual Basic 6.0。如果您部署 COM 組件,以負荷對它們進行測試特别重要。事實上,理所當然應對所有的 ASP 應用程序進行負荷測試。
技巧 8:遲一(yī)點獲得資(zī)源,早一(yī)點釋放(fàng)資(zī)源
這裏是一(yī)個小(xiǎo)技巧供您參考。一(yī)般來說,最好遲一(yī)點獲得資(zī)源,早一(yī)點釋放(fàng)資(zī)源。這适用于 COM 對象以及文件句柄和其它資(zī)源。
這種優化方法主要用于 ADO 連接和記錄集。當您使用完記錄集,比方說在顯示一(yī)個表及其數據之後,應立即釋放(fàng)它,而不是等到頁面結束時再釋放(fàng)。将 VBScript 變量設置爲 Nothing 是最好的做法。不要讓記錄集超出作用域之外(wài)。而且,要釋放(fàng)任何相關的 Command 或 Connection 對象(在将記錄集或連接設置爲 = Nothing 之前,不要忘記調用 Close())。這會縮短數據庫必須爲您準備資(zī)源的時間,并盡快釋放(fàng)數據庫到連接池的連接。
技巧 9:進程外(wài)執行過程以性能換取可靠性
ASP 和 MTS/COM+ 兩者都有配置選項,可使您兼顧可靠性和性能。當建立和部署應用程序時,應知(zhī)道如何兼顧兩者的性能。
ASP 選項
可以配置 ASP 應用程序,以便以三種方法之一(yī)運行。在 IIS 5.0 中(zhōng),引入了“隔離(lí)級”這一(yī)術語以說明這些選項。這三個隔離(lí)級分(fēn)别是低級、中(zhōng)級和高級:
低級隔離(lí)。這在 IIS 的所有版本中(zhōng)都得到支持,且是最快的。它在 Inetinfo.exe 中(zhōng)運行 ASP,Inetinfo.exe 是主要 IIS 進程。如果 ASP 應用程序崩潰,IIS 也會崩潰。(要在 IIS 4.0 下(xià)重新啓動 IIS,Web 站點管理員(yuán)應使用諸如 InetMon 之類的工(gōng)具監視站點,如果服務器發生(shēng)故障,應啓用批處理文件以重新啓動服務器。IIS 5.0 引入了可靠的重新啓動,該方法可使發生(shēng)故障的服務器自動重新啓動。)
中(zhōng)級隔離(lí)。IIS 5.0 引入了這個新的級别,它被稱爲進程外(wài)級别,因爲 ASP 在 IIS 進程之外(wài)運行。在中(zhōng)級隔離(lí)中(zhōng),被配置作爲中(zhōng)級隔離(lí)運行的所有 ASP 應用程序都共享一(yī)個進程空間。這就減少了在一(yī)台服務器運行多個進程外(wài) ASP 應用程序所需要的進程數量。中(zhōng)級隔離(lí)是 IIS 5.0 中(zhōng)的默認隔離(lí)級别。
高級隔離(lí)。在 IIS 4.0 和 IIS 5.0 中(zhōng)支持這一(yī)級别,高級隔離(lí)也是進程外(wài)的。如果 ASP 崩潰,Web 服務器并不會崩潰。下(xià)次 ASP 請求時,ASP 應用程序就會自動重新啓動。在高級隔離(lí)中(zhōng),配置作爲高級隔離(lí)運行的每個 ASP 應用程序都在其自有進程空間中(zhōng)運行。這樣做可保護 ASP 應用程序彼此之間不相互幹擾。其缺點是它要求每個 ASP 應用程序都要有一(yī)個單獨的進程。當在一(yī)台服務器上必須運行許多應用程序時,系統開(kāi)銷就會大(dà)大(dà)增加。
哪個選項最好的呢?在 IIS 4.0 中(zhōng),進程外(wài)運行将顯著降低性能。在 IIS 5.0 中(zhōng),做了許多改進,将進程外(wài)運行 ASP 應用程序所産生(shēng)的開(kāi)銷降到最低限度。事實上,在絕大(dà)多數測試中(zhōng),IIS 5.0 中(zhōng)的 ASP 進程外(wài)應用程序比 IIS 4.0 中(zhōng)的進程内應用程序運行得更快。不管怎樣,在兩個平台上,進程内(低隔離(lí)級)性能最佳。但是,如果訪問率相對較低或最大(dà)吞吐量較低,低隔離(lí)級的優勢不太明顯。因此,在您每一(yī) Web 服務器每秒鍾需要數百或成千上萬頁面時,才會覺得有必要設置低隔離(lí)級。與往常一(yī)樣,應對多種配置進行測試,确定您要采取哪一(yī)種折衷方案。
注意 當您運行 ASP 進程外(wài)應用程序時(中(zhōng)級或高級隔離(lí)),它們在 NT4 中(zhōng)的 MTS 和在 Windows 2000 中(zhōng)的 COM+ 中(zhōng)運行。即,在 NT4 中(zhōng)它們在 Mtx.exe 中(zhōng)運行;而在 Windows 2000 中(zhōng),它們在 DllHost.exe 中(zhōng)運行。您可以在任務管理器中(zhōng)看到這些進程在運行。您還可以看到 IIS 如何爲進程外(wài) ASP 應用程序配置 MTS 程序包或 COM+ 應用程序。
COM 選項
COM 組件也有三種配置選項,雖然與 ASP 選項不完全類似。COM 組件可以是“未配置的”、配置爲庫應用程序或配置爲服務器應用程序。“未配置的”意思是指組件沒有注冊 COM+。組件将在調用程序的進程空間運行,那就是說,它們是“進程内的”。庫應用程序也是進程内的,但使用 COM+ 的服務,包括安全、事務和上下(xià)文支持。服務器應用程序被配置爲在它們自有的進程空間内運行。
您可以看到未配置的組件比庫應用程序略有一(yī)些優勢。庫應用程序比服務器應用程序的性能優點更大(dà)。這是因爲庫應用程序與 ASP 在同一(yī)進程内運行,而服務器應用程序在它們的自有進程内運行。進程間的調用比進程内調用開(kāi)銷更大(dà)。而且,當在進程之間傳遞諸如記錄集之類的數據時,必須在兩個進程之間複制所有的數據。
陷阱!當使用 COM 服務器應用程序時,如果您在 ASP 和 COM 之間傳遞對象,要确保對象執行“按值彙集”或 MBV。執行 MBV 的對象将它們自己從一(yī)個進程複制到另一(yī)個進程。這比下(xià)面一(yī)種方法好,采用這種方法時,對象仍在創建者的進程中(zhōng),另外(wài)一(yī)個進程反複地調用創建進程以使用該對象。切斷連接的 ADO 記錄集将“按值彙集”,連接的記錄集則不然。Scripting.Dictionary 不執行 MBV,且不在進程之間傳遞。最後,VB 程序員(yuán)請注意:MBV 不通過傳遞參數 ByVal 獲得。MBV 由原始的組件作者執行。
怎麽辦?
如果讓我(wǒ)(wǒ)們建議一(yī)個兼顧性能與可靠性的合理配置,它們應是如下(xià)的配置:
在 IIS 4.0 中(zhōng),使用 ASP 低隔離(lí)級别,使用 MTS 服務器程序包。
在 IIS 5.0 上,使用 ASP 的中(zhōng)隔離(lí)級,并使用 COM+ 庫應用程序。
這些是非常一(yī)般的原則,主機服務公司一(yī)般情況下(xià)以中(zhōng)或高隔離(lí)級運行 ASP,而單用途的 Web 服務器可以以低隔離(lí)級運行。衡量各種利弊,并自己決定哪個配置更能符合您的需要。
技巧 10:使用顯式選項
在 .asp 文件中(zhōng)應使用 Option Explicit。此指令放(fàng)在 .asp 文件的最上面,它強制開(kāi)發人員(yuán)聲明要使用到的所有變量。許多程序員(yuán)認爲這種方法對于調試應用程序很有幫助,因爲這種方法避免了鍵錯變量名和誤建新變量的可能性(例如,将 MyXMLString=) 錯寫成 MyXLMString=...。
更重要的一(yī)點也許是,聲明的變量比未聲明的變量速度更快。由此,腳本在運行時每次用到未聲明的變量時,按名稱引用它。另一(yī)方面,聲明的變量是有順序的,要麽以編譯時間,要麽以運行時間。以後,聲明的變量都按此順序引用。因爲 Option Explicit 強制變量聲明,它能确保聲明所有變量,因此訪問的速度也很快。
技巧 11:在子例程和函數中(zhōng)使用局部變量
局部變量是那些在子例程和函數内聲明的變量。在函數或子例程内,局部變量訪問比全局變量訪問更快。局部變量的使用也會使代碼更清晰,因此應盡量使用局部變量。
技巧 12:将經常使用的數據複制到腳本變量中(zhōng)
當訪問 ASP 中(zhōng)的 COM 對象時,應将經常使用的對象數據複制到腳本變量中(zhōng)。這樣做可減少 COM 方法調用,因爲 COM 方法調用與訪問腳本變量相比,開(kāi)銷相對較大(dà)。當訪問 Collection 和 Dictionary 對象時,這種技術也會減少開(kāi)銷很大(dà)的查找。
一(yī)般來說,如果您打算不止一(yī)次訪問對象數據,那麽就應将數據放(fàng)到腳本變量中(zhōng)。這種優化的主要目标是 Request 變量(Form 和 QueryString 變量)。例如,您的站點可傳遞一(yī)個名爲 UserID 的 QueryString 變量。假設此 UserID 在特定頁面上被引用 12 次。可以無須調用 Request(?UserID?) 12 次,而是在 ASP 頁面最上面将 UserID 指派到一(yī)個變量。然後在該頁面自始至終使用該變量。這樣就省去(qù)了 11 次 COM 方法調用。
實際上,訪問 COM 屬性或方法的開(kāi)銷并沒有那麽大(dà)。下(xià)面舉一(yī)個例子,說明某相當常見的代碼(從語法上講):
Foo.bar.blah.baz = Foo.bar.blah.qaz(1)
If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...
當此代碼運行時,下(xià)面是發生(shēng)的情況:
變量 Foo 被解析爲全局對象。
變量 bar 被解析爲 Foo 的成員(yuán)。這實際就是一(yī)次 COM 方法調用。
變量 blah 被解析爲 Foo.bar 的成員(yuán)。這又(yòu)是一(yī)次 COM 方法調用。
變量 qaz 被解析爲 foo.bar.blah 的成員(yuán)。沒有錯,這還是一(yī)次 COM 方法調用。
調用 Foo.bar.blah.quaz(1)。再一(yī)次 COM 方法調用。懂了嗎(ma)?
再次執行步驟 1 至步驟 3 以解析 baz。系統并不知(zhī)道調用 qaz 是否改變對象模型,因此必須再次執行步驟 1 至 3 以解析 baz。
将 baz 解析爲 Foo.bar.blah 的成員(yuán)。賦予屬性。
再次執行步驟 1 至步驟 3 以解析 zaq。
再次執行步驟 1 至步驟 3 以解析 abc。
正如您可看到的,效率相當差(且慢(màn))。以 VBScript 寫此代碼的快速方法是:
Set myobj = Foo.bar.blah ' do the resolution of blah ONCE
Myobj.baz = myobj.qaz(1)
If Myobj.zaq = Myobj.abc Then '...
如果您使用 VBScript 5.0 或更高版本,您可以使用 With 語句寫此代碼:
With Foo.bar.blah
.baz = .qaz(1)
If .zaq = .abc Then '...
...
End With
注意此技巧也适用于 VB 程序設計。
技巧 13:避免重新确定數組的維數
應盡量避免 Redim 數組。就性能而言,如果計算機的物(wù)理内存大(dà)小(xiǎo)有限,最好将數組的初始維數設置爲其最不利的情況 - 或将維數設置爲其最佳的情況,然後再按需要重新确定維數。這并非意味着,如果知(zhī)道您不需要内存時,就随便分(fēn)配幾兆字節的内存。
下(xià)面的代碼給您顯示使用 Dim 和 Redim 不當的情形。
<%
Dim MyArray()
Redim MyArray(2)
MyArray(0) = ?hello?
MyArray(1) = ?good-bye?
MyArray(2) = ?farewell?
...
' some other code where you end up needing more space happens, then ...
Redim Preserve MyArray(5)
MyArray(3) = ?more stuff?
MyArray(4) = ?even more stuff?
MyArray(5) = ?yet more stuff?
%>
最好一(yī)開(kāi)始就将數組的初始大(dà)小(xiǎo) Dim 正确(在本例中(zhōng),是 5)比 Redim 數組使其更大(dà)好得多。您可能浪費(fèi)一(yī)些内存(如果您沒有使用所有的元素),但獲得的好處是速度變得更快。
技巧 14:使用響應緩沖
您可以通過啓用“響應緩沖”,将要輸出的一(yī)整頁緩沖起來。這樣就将寫到浏覽器的量減到最少,從而改善總體(tǐ)性能。每個寫操作都會産生(shēng)很大(dà)的系統開(kāi)銷(在 IIS 中(zhōng)以及在通過網絡發送的數據量方面),因此寫操作越少越好。由于其啓動慢(màn)且使用 Nagling 算法(用來減輕網絡塞車(chē)情況),TCP/IP 在發送一(yī)些大(dà)的數據塊時比必須發送許多小(xiǎo)的數據塊時的效率高得多。
有兩個方法啓用響應緩沖。第一(yī)種,您可以使用 Internet Services Manager 爲整個應用程序啓用響應緩沖。我(wǒ)(wǒ)們建議采用這種方法,在 IIS 4.0 和 IIS 5.0 中(zhōng)默認爲新的 ASP 應用程序啓用響應緩沖。第二種,可以在每個 ASP 頁面的接近頂端的地方加入下(xià)面的代碼行,從而啓用響應緩沖:
<% Response.Buffer = True %>
此代碼行必須在任何響應數據被寫到浏覽器之前執行(即,在任何 HTML 出現在 ASP 腳本之前以及在使用 Response.Cookies 集合設置任何 Cookies 之前)。一(yī)般來說,最好爲整個應用程序啓用響應緩沖。這樣,您就不必在每個頁面最上面寫入上述的代碼行。
Response.Flush
關于響應緩沖有一(yī)個常見的抱怨,就是用戶感覺到 ASP 頁面的響應速度很慢(màn)(即使整個響應時間得到改進),因爲他們必須等到整個頁面生(shēng)成,然後他們才能看到東西。對于運行時間長的頁面,您可以設置 Response.Buffer = False,禁用響應緩沖。但是,一(yī)個更好的策略是利用 Response.Flush 方法。這種方法将 ASP 轉換的所有 HTML 送到浏覽器。例如,在轉換 1,000 行的表的前 100 行之後,ASP 可以調用 Response.Flush,強制将轉換的結果送到浏覽器,這樣可使用戶在其餘的行準備好之前看到頭 100 行。這種技術可以将響應緩沖與浏覽器逐漸顯示數據完美地結合在一(yī)起。
(注意在上面的 1,000 行表的舉例中(zhōng),許多浏覽器在它們看到關閉 </table> 标記之前不會開(kāi)始顯示表。檢查您的目标浏覽器是否支持。爲避免這種情況,将表分(fēn)成多個具有較少行的表,并在每個表之後調用 Response.Flush。較新版本的 Internet Explorer 在表完全下(xià)載之前就開(kāi)始顯示表,如果您指定表列寬,顯示速度就會特别快,這樣做可避免強制 Internet Explorer 通過測量每個單元格的内容寬度來計算列寬。)
另一(yī)個關于響應緩沖的常見的抱怨是,當産生(shēng)非常大(dà)的頁面時,将占用許多服務器内存。撇開(kāi)産生(shēng)大(dà)頁面的方法不談,這種問題也可通過巧妙使用 Response.Flush 來加以解決。
技巧 15:批處理内嵌腳本和 Response.Write 語句
VBScript 語法 <% = expression %> 将“expression”的值寫到 ASP 輸出流中(zhōng)。如果響應緩沖未啓用,那麽執行其中(zhōng)的每一(yī)條語句,都會以許多小(xiǎo)的數據包通過網絡将數據寫到浏覽器中(zhōng)。這樣速度很慢(màn)。而且穿插執行少量的腳本和 HTML,将引起腳本引擎和 HTML 之間的切換,從而降低性能。因此,使用下(xià)面的技巧:使用 Response.Write 調用代替捆綁緊密的内嵌表達式。例如,在下(xià)面的示例中(zhōng),在每一(yī)行的每一(yī)字段對響應流有一(yī)次寫操作,每一(yī)行在 VBScript 和 HTML 之間有許多切換:
<table>
<% For Each fld in rs.Fields %>
<th><% = fld.Name %></th>
<%
Next
While Not rs.EOF
%>
<tr>
<% For Each fld in rs.Fields %>
<td><% = fld.value %></td>
<% Next
</tr>
<% rs.MoveNext
Wend %>
</table>
下(xià)面的代碼更有效,每一(yī)行對響應流有一(yī)次寫操作。所有的代碼都包含在一(yī)個 VBScript 塊内:
<table>
<%
For each fld in rs.Fields
Response.Write (?<th>? & fld.Name & ?</th>? & vbCrLf)
Next
While Not rs.EOF
Response.Write (?<tr>?)
For Each fld in rs.Fields %>
Response.Write(?<td>? & fld.value & ?</td>? & vbCrLf)
Next
Response.Write ?</tr>?
Wend
%>
</table>
當禁用響應緩沖時,這一(yī)技巧的效果特别大(dà)。最好啓用響應緩沖,然後看批處理 Response.Write 是否有助于提高性能。
(在這一(yī)特定舉例中(zhōng),建立表主體(tǐ)的嵌套循環 (While Not rs.EOF...) 可以用仔細構建的 GetString 調用來替代。)
技巧 16:如果頁面需要很長時間才能完成,那麽執行前使用 Response.IsClientConnected
如果用戶性急,他們可能會在您開(kāi)始執行他們的請求之前,就會放(fàng)棄 ASP 頁面。如果他們單擊刷新或移到服務器上的另一(yī)個頁面,在 ASP 請求隊列的末尾就有一(yī)個新的請求等候,在隊列的中(zhōng)間有一(yī)個斷開(kāi)連接的請求。當服務器的負載很高時(因此請求隊列就會很長,響應時間也會相應地變長),就會經常發生(shēng)這種情況,這樣隻能使情況變得更糟。如果用戶不再連接,執行 ASP 頁面(特别是慢(màn)的、大(dà)的 ASP 頁面)已沒有任何意義。您可以使用 Response.IsClientConnected 屬性檢查這一(yī)情況。如果它返回 False,則應調用 Response.End 并放(fàng)棄頁的其餘部分(fēn)。事實上,IIS 5.0 已将這一(yī)做法編爲程序 - 每當 ASP 即将執行新請求時,它就會檢查請求在隊列中(zhōng)已等候了多長時間。如果已經在那裏等候了多于 3 秒鍾,ASP 将檢查客戶機是否仍處于連接狀态,如果沒有連接,就立即終止請求。您可以在配置數據庫中(zhōng)使用 AspQueueConnectionTestTime 設置将超時時間由 3 秒調整爲其它值。
如果頁面要花很長時間才能執行完,也可以不時地檢查 Response.IsClientConnected。當啓用了響應緩沖時,最好不時地執行 Response.Flush,以用戶知(zhī)道,正在發生(shēng)什麽事。
注意 在 IIS 4.0 上,除非先執行了 Response.Write,否則 Response.IsClientConnected 就不能正常工(gōng)作。如果啓用了緩沖,您也必須執行 Response.Flush。在 IIS 5.0 上,卻沒有必要這樣做,- Response.IsClientConnected 工(gōng)作正常。在任何情況下(xià),Response.IsClientConnected 都會有一(yī)些開(kāi)銷,因此隻有在一(yī)個操作至少要花(比方說) 500 毫秒(如果您想維持每秒鍾數十頁的吞吐量,這是一(yī)個很長的時間)才使用它。經驗表明,不要每次重複執行緊密循環時都調用它,如顯示表的許多行時 - 每隔二十或五十行調用一(yī)次可能比較合适。
技巧 17:使用 <OBJECT> 标記例示對象
如果要引用不在所有代碼路徑(特别是服務器或應用程序作用域的對象)中(zhōng)使用的對象,使用 Global.asa 中(zhōng) <object runat=server id=objname> 标記聲明它們,而不使用 Server.CreateObject 方法。Server.CreateObject 能立即創建對象。如果以後不再使用該對象,您就浪費(fèi)了資(zī)源。<object id=objname> 标記聲明 objname,但在其方法或屬性第一(yī)次使用以前,不會創建 objname。
這又(yòu)是一(yī)個惰性計算的例子。
技巧 18:對于 ADO 和其它組件使用 TypeLib 聲明
當使用 ADO 時,開(kāi)發人員(yuán)經常加入 adovbs.txt,以訪問 ADO 的各種常量。在要使用常量的每個頁面中(zhōng)必須包含此文件。此常量文件相當大(dà),給每個 ASP 頁面的編譯時間和腳本大(dà)小(xiǎo)增加了許多系統開(kāi)銷。
IIS 5.0 引入了綁定到組件類型庫的功能。這可使您引用類型庫一(yī)次,并将其用在每個 ASP 頁面上。每個頁面不會産生(shēng)編譯常量文件的開(kāi)銷,且組件開(kāi)發人員(yuán)不必建立 VBScript#_include 文件以在 ASP 上使用。
要訪問 ADO TypeLib,将下(xià)面一(yī)條語句放(fàng)在 Global.asa 中(zhōng)。
<!-- METADATA NAME=?Microsoft ActiveX Data Objects 2.5 Library?
TYPE=?TypeLib? UUID=?{00000205-0000-0010-8000-00AA006D2EA4}? -->
或
<!-- METADATA TYPE=?TypeLib?
FILE=?C:\Program Files\Common Files\system\ado\msado15.dll? -->
技巧 19: 利用浏覽器的驗證功能
現今的浏覽器對一(yī)些高級功能如 XML、DHTML、Java 小(xiǎo)程序和遠程數據服務提供支持。盡可能使用這些功能。所有這些技術都可以執行客戶機端驗證和數據緩存,免去(qù)了到 Web 服務器的往返。如果您在運行一(yī)個智能浏覽器,那麽浏覽器就能爲您進行一(yī)些驗證(例如,在執行 POST 之前,檢查信用卡校驗和是否有效)。盡可能使用這一(yī)功能。通過減少客戶-服務器之間的往返,可降低 Web 服務器上的負載,并能減少網絡通信量(雖然發送到浏覽器的第一(yī)個頁面可能比較大(dà))以及服務器訪問的任何後端資(zī)源。此外(wài),用戶不必像住常一(yī)樣讀取新頁,從而用戶的感覺會好一(yī)些。這樣做并不意味着您可以不進行服務器端驗證 - 您還應始終進行服務器端驗證。這可以防止由于某種原因(如黑客,或浏覽器不運行客戶機端驗證例程)客戶機産生(shēng)錯誤的數據。
人們已經進行了大(dà)量的工(gōng)作,開(kāi)發“獨立于浏覽器”的 HTML。正是由于這種憂慮,開(kāi)發人員(yuán)不願再使用流行的浏覽器功能,但這些功能本可以改善性能。對于一(yī)些真正的高性能站點,必須關心浏覽器“訪問”問題,一(yī)個好的策略是優化頁面,使其适應流行的浏覽器。使用浏覽器功能組件,可以在 ASP 中(zhōng)方便地檢測到浏覽器功能。Microsoft FrontPage 等工(gōng)具有助于設計适合于浏覽器和指定 HTML 版本的代碼。參見 When is Better Worse?Weighing the Technology Trade-Offs,以了解更進一(yī)步的讨論。
技巧 20:避免在循環語句中(zhōng)使用字符串串聯
許多人在循環語句中(zhōng)建立一(yī)個字符串,如下(xià)所示:
s = ?<table>? & vbCrLf
For Each fld in rs.Fields
s = s & ? <th>? & fld.Name & ?</th> ?
Next
While Not rs.EOF
s = s & vbCrLf & ? <tr>?
For Each fld in rs.Fields
s = s & ? <td>? & fld.value & ?</td> ?
Next
s = s & ? </tr>?
rs.MoveNext
Wend
s = s & vbCrLf & ?</table>? & vbCrLf
Response.Write s
采用這種方法會出現一(yī)些問題。第一(yī)個問題是反複串聯字符串需要花兩次方的時間,更通俗地說,運行這種循環語句所花的時間與記錄數乘以字段數所得值的平方成正比。舉一(yī)個更簡單的例子,就可以更清楚地說明這一(yī)問題。
s = ??
For i = Asc(?A?) to Asc(?Z?)
s = s & Chr(i)
Next
在第一(yī)次叠代中(zhōng),您獲得了一(yī)個字符的字符串 ?A?。在第二次叠代中(zhōng),VBScript 必須重新分(fēn)配字符串并将兩個字符 (?AB?) 複制到 s 中(zhōng)。在第三次叠代中(zhōng),它還必須再次重新分(fēn)配 s 并将三個字符複制到 s 中(zhōng)。在 N 次(第 26 次)叠代中(zhōng),它必須重新分(fēn)配并将 N 個字符複制到 s 中(zhōng)。總共就是 1+2+3+...+N,即 N*(N+1)/2 次複制。
在上面的記錄集舉例中(zhōng),如果有 100 個記錄和 5 個字段,内循環将執行 100*5 = 500 次,所有的複制和重新分(fēn)配所花的時間與 500*500 = 250,000 成正比。這對于中(zhōng)等大(dà)小(xiǎo)的記錄集來說複制操作太多了。
在本例中(zhōng),代碼可以用 Response.Write() 或内嵌腳本 (<% = fld.value %>) 替代字符串串聯來改進。如果啓用了響應緩沖的話(huà)(應該的),這樣做就會更快,因爲 Response.Write 隻将數據附加到響應緩沖的末尾。并不涉及重新分(fēn)配,因此效率很高。
在将 ADO 記錄集轉換爲 HTML 表的特定情況下(xià),應考慮使用 GetRows 或 GetString。
如果在 JScript 中(zhōng)串聯字符串,特别建議使用 += 運算符,即,使用 s += ?某字符串?,而不使用 s = s + ?某字符串?。
技巧 21:啓用浏覽器和代理緩存
在默認情況下(xià),ASP 禁止在浏覽器和代理中(zhōng)進行緩存。這是有意義的,因爲就實質而言 ASP 頁面是動态的,上面有随時間不斷變化的潛在信息。如果頁面不要求在每個視圖上進行刷新,您應啓用浏覽器和代理緩存。這可使浏覽器和代理在一(yī)定的時間内使用頁面的“緩存”副本,您可以控制時間的長短。緩存可以大(dà)大(dà)減輕服務器上的負載,縮短用戶的等待時間。
哪一(yī)種動态頁面可作爲要緩存的頁面呢?下(xià)面舉一(yī)些例子:
天氣預報頁面,在此頁面上,每隔 5 分(fēn)鍾更新一(yī)次天氣預報。
列出新聞條目或新聞稿的主頁,它一(yī)天更新兩次。
共同基金業績列表,在此列表中(zhōng),基本統計信息每隔幾小(xiǎo)時更新一(yī)次。
注意,在使用浏覽器或代理緩存的情況下(xià),Web 服務器上記錄的訪問次數減少了。如果您想準确地測量所有頁面視圖或張帖公布,您就不希望使用浏覽器和代理緩存。
浏覽器緩存由 HTTP“過期”報頭控制,該報頭由 Web 服務器發送給浏覽器。ASP 提供兩個簡單的機制發送此報頭。要設置頁面使其過多少分(fēn)鍾後到期,則應設置 Response.Expires 屬性。下(xià)面的例子告訴浏覽器内容在 10 分(fēn)鍾内過期:
<% Response.Expires = 10 %>
若将 Response.Expires 設置爲負數或 0,則禁用緩存。一(yī)定要使用大(dà)的負數,如 -1000(略多于一(yī)天),以避免服務器和浏覽器時鍾之間的不匹配。第二個屬性 Response.ExpiresAbsolute 将使您設置内容過期的具體(tǐ)時間:
<% Response.ExpiresAbsolute = #May 31,2001 13:30:15# %>
您可以不使用 Response 對象設置過期時間,而将 <META> 标記寫進 HTML,通常寫在 HTML 文件的 <HEAD> 部分(fēn)。一(yī)些浏覽器将遵照此指令,而代理則不然。
<META HTTP-EQUIV=?Expires? value=?May 31,2001 13:30:15?>
最後,您可以使用 Response.CacheControl 屬性,指示其内容是否可以讓 HTTP 代理緩存。若将此屬性設置爲“Public”,代理就可以緩存此内容。
<% Response.CacheControl = ?Public? %>
在默認情況下(xià),此屬性被設置爲“Private”。注意,對于顯示某用戶特定數據的頁面,不應啓用代理緩存,因爲代理可能給用戶提供屬于其他用戶的頁面。
技巧 22:盡可能使用 Server.Transfer 代替 Response.Redirect
Response.Redirect 讓浏覽器請求另一(yī)個頁面。此函數常用來将用戶重定向到一(yī)個登錄或錯誤頁面。因爲重定向強制請求新頁面,結果是浏覽器必須到 Web 服務器往返兩次,且 Web 服務器必須多處理一(yī)個請求。IIS 5.0 引入了一(yī)個新的函數 Server.Transfer,它将執行轉移到同一(yī)台服務器上的另一(yī)個 ASP 頁。這樣就避免多餘的浏覽器-Web-服務器的往返,從而改善了總體(tǐ)系統性能以及縮短了用戶的響應時間。檢查“重定向”中(zhōng)的“新的方向”,上面應該是 Server.Transfer 和 Server.Execute。
另請參見 Leveraging ASP in IIS 5.0,了解 IIS 5.0 和 ASP 3.0 新功能的完整列表。
技巧 23:在目錄 URL 中(zhōng)使用後斜杠
一(yī)個相關的技巧是确保在指向目錄的 URL 中(zhōng)使用後斜杠 (/)。如果您省略了後斜杠,浏覽器就會向服務器發出請求,隻是爲了告訴服務器,它在請求目錄。浏覽器就會發出第二個請求,将斜杠附加到 URL 後面,隻有此後,服務器才能以該目錄的默認文檔或目錄列表(如果沒有默認文檔且啓用了目錄浏覽的話(huà))響應。附加斜杠可省去(qù)第一(yī)個、無用的住返。爲便于用戶閱讀,可以省略顯示名稱中(zhōng)的後斜杠。
例如,寫:
<a href=?http://msdn.microsoft.com/workshop/? title=?MSDN Web
Workshop?>http://msdn.microsoft.com/workshop</a>
這也适用于指向 Web 站點上主頁的 URL:使用下(xià)面的:<a href=?http://msdn.microsoft.com/?>,而不使用 <a href=?http://msdn.microsoft.com?>。
技巧 24:避免使用服務器變量
訪問服務器變量會使 Web 站點向服務器發出一(yī)個特殊請求,并收集所有服務器變量,而不隻是您請求的那個變量。這種情況類似于,在發黴的閣樓上,在一(yī)個文件夾中(zhōng)查找某個文件。當您想要找那個文件時,您必須去(qù)閣樓上,先找到文件夾,然後才能找到這份文件。當您請求服務器變量時,發生(shēng)的情況是一(yī)樣的 - 您第一(yī)次請求服務器變量時,就會使性能受到影響。後面的對其它服務器變量的請求,則不會對性能産生(shēng)影響。
決不要訪問非限定的 Request 對象(例如,Request("Data"))。對于不在 Request.Cookies、Request.Form、Request.QueryString 或 Request.ClientCertificate 中(zhōng)的項目,則隐式調用 Request.ServerVariables。Request.ServerVariables 集合比其它集合慢(màn)得多。
技巧 25:升級到最新和最出色的
系統組件是恒定的,我(wǒ)(wǒ)們建議您将它們升級到最新和最好的配置。最好升級到 Windows 2000(因此,也應升級到 IIS 5.0、ADO 2.5、MSXML 2.5、Internet Explorer 5.0、VBScript 5.1 和 JScript 5.1)。在多處理器計算機上,實施 IIS 5.0 和 ADO 2.5 可顯著改善性能。在 Windows 2000 下(xià),ASP 可以很好地擴展到四個處理器或更多,而在 IIS 4.0 下(xià),ASP 的擴展性不能超出兩個處理器。在應用程序中(zhōng)使用的腳本代碼和 ADO 越多,升級到 Windows 2000 之後,性能的改善就會越多。
如果目前還不能升級到 Windows 2000,您可以升級到 SQL Server、ADO、VBScript 和 JScript、MSXML、Internet Explorer 和 NT 4 Service Packs 的最新版本。它們均可提高性能和可靠性。
技巧 26:優化 Web 服務器
有多種 IIS 優化參數可以改善站點性能。例如,對于 IIS 4.0,我(wǒ)(wǒ)們常常發現,增加 ASP ProcessorThreadMax 參數(參見 IIS 文檔)可以顯著改善性能,特别是在傾向于等待後端資(zī)源(如數據庫)或其它中(zhōng)間産品(如屏幕刷)的站點上。在 IIS 5.0 中(zhōng),您可能發現啓用 ASP Thread Gating 比查找一(yī)個 AspProcessorThreadMax 最佳設置效率更高,這一(yī)點現在已爲大(dà)家所熟知(zhī)。
有關較好的參考資(zī)料,參見下(xià)面的優化 IIS。
最佳的配置設置取決于(其中(zhōng)一(yī)些因素)應用程序代碼、運行所在的系統硬件和客戶機工(gōng)作負荷。找到最佳設置的唯一(yī)方法是進行性能測試,這是我(wǒ)(wǒ)們在下(xià)一(yī)個技巧中(zhōng)所要讨論的。
技巧 27:進行性能測試
正如我(wǒ)(wǒ)們在前面已經講過,性能是一(yī)個特征。如果您想要改善站點的性能,那麽就制定一(yī)個性能目标,然後逐步改進,直到達到目标爲止。不要,就不進行任何性能測試。通常,在項目結束時,再作必需的結構調整已經爲時太晚,您的客戶将爲此感到失望。将性能測試作爲您日常測試的一(yī)部分(fēn)來進行。可以對單個組件分(fēn)别進行性能測試,如針對 ASP 頁或 COM 對象,或将站點作爲一(yī)個整體(tǐ)來測試。
許多人使用單個浏覽器請求頁面,來測試 Web 站點的性能。這樣做就會給您一(yī)個感覺,即站點的響應能力很好,但這樣做實際上并不能告訴您在負載條件下(xià)站點的性能如何。
一(yī)般情況下(xià),要想準确地測試性能,您需要一(yī)個專門的測試環境。此環境應包括硬件,其處理器速度、處理器數量、内存、磁盤、網絡配置等方面與生(shēng)産環境的硬件相似。其次,您必須指定客戶機的工(gōng)作負荷:有多少同時的用戶,他們發出請求的頻(pín)率,他們點擊頁面的類型等等。如果您沒有站點實際使用情況的數據,您必須估計一(yī)下(xià)使用的情況。最後,您需要一(yī)個可以模拟預期客戶機工(gōng)作負荷的工(gōng)具。有了這些工(gōng)具,您就可以開(kāi)始回答諸如“如果我(wǒ)(wǒ)有 N 個同時的用戶,那麽需要多少服務器?”之類的問題。您還可以找出出現瓶頸的原因,并以此爲目标進行優化。
下(xià)面列出了一(yī)些好的 Web 負載測試工(gōng)具。我(wǒ)(wǒ)們特别推薦 Microsoft Web Application Stress (WAS) 工(gōng)具包。WAS 可使您記錄測試腳本,然後模拟數百或成千上萬個用戶訪問 Web 服務器。WAS 報告很多統計信息,包括每秒鍾的請求數,響應時間分(fēn)布情況和錯誤計數。WAS 有豐富的客戶機界面和基于 Web 的界面兩種,Web 界面可使您進行遠程測試。
一(yī)定要閱讀 IIS 5.0 Tuning Guide。
技巧 28:閱讀資(zī)源鏈接
下(xià)面是一(yī)些與性能有關的出色的資(zī)源鏈接。如果您想了解有關信息,請閱讀 Developing Scalable Web Applications。
資(zī)源
優化 ASP 腳本
優化 IIS
ADO 和 SQL Server
ASP 組件和線程模型
詞典組件
會話(huà)狀态
性能和可擴展性
工(gōng)具
書(shū)目
ASP Web 站點
ASP 樣式
XML
優化 ASP 腳本
Developing Scalable Web Applications
Got Any Cache? Nancy Winnick Cluts 著
Maximizing the Performance of Your Active Server Pages,Nancy Winnick Cluts 著
15 Seconds: Performance Section
Enhancing Performance in ASP - Part I,Wayne Plourde 著
When is Better Worse? Weighing the Technology Trade-Offs,Nancy Winnick Cluts 著
Speed and Optimization Resources,Charles Carroll 著
優化 IIS
The Art and Science of Web Server Tuning with Internet Information Services 5.0
Leveraging ASP in IIS 5.0,J.D. Meier 著
Tuning IIS 4.0 for High Volume Sites,Michael Stephenson 著
Tuning Internet Information Server Performance,Mike Moore 著
Navigating the Maze of Settings for Web Server Performance Optimization,Todd Wanke 著
Managing Internet Information Server 4.0 for Performance,Hans Hugli 著
ADO 和 SQL Server
Top Ten Tips: Accessing SQL Through ADO and ASP,J.D. Meier 著
Improve the Performance of your MDAC Application,Suresh Kannan 著
Pooling in the Microsoft Data Access Components,Leland Ahlbeck 和 Don Willits 合著
SQL Server: Performance Benchmarks and Guides
Improving the Performance of Data Access Components with IIS 4.0,Leland Ahlbeck 著
Microsoft Data Access Components (MDAC) and ActiveX Data Objects (ADO) Performance Tips,Leland Ahlbeck 著
Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Server Perspective,Damien Lindauer 著
Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Application Perspective,Damien Lindauer 著
Accessing Recordsets over the Internet,Dino Esposito 著
ASP 組件和線程模型
ASP Component Guidelines,J.D. Meier 著
Q243548: INFO: Design Guidelines for VB Components under ASP
Threading Models Explained,Nancy Winnick Cluts 著
So Happy Together? Using ActiveX components with Active Server Pages,Nancy Winnick Cluts 著
Developing Active Server Components with ATL,George Reilly 著
Agility in Server Components,Neil Allain 著
Building High-Performance Middle-Tier Components with C++,Jon Flanders 著
Active Server Pages and COM Apartments,Don Box 著
House of COM: Active Server Pages,Don Box 著
House of COM: Contexts,Don Box 著
House of COM: Performance Trade-offs of the Windows 2000 Component Execution Environment,Don Box 著
Building COM Components That Take Full Advantage of Visual Basic and Scripting,Ivo Salmre 著
Component Design Principles for MTS
詞典組件
Creating a Page Cache Object,Robert Coleridge 著
Abridging the Dictionary Object: The ASP Team Creates a Lookup-Table Object,Robert Carter 著
Caprock Dictionary
Site Server Commerce Edition includes a dictionary component
會話(huà)狀态
Q175167: HOWTO: Persisting values Without Sessions
Q157906: HOWTO: How To Maintain State Across Pages with VBScript
XML-based Persistence Behaviors Fix Web Farm Headaches,Aaron Skonnard 著
House of COM: Stateless Programming,Don Box 著
性能和擴展性
Blueprint for Building Web Sites Using the Microsoft Windows DNA Platform
Server Performance and Scalability Killers,George Reilly 著
Microsoft Visual Studio Scalability Center
Fitch & Mather Stocks 2000
Tuning the FMStocks Application
High-Performance Visual Basic Apps,Ken Spencer 著
Duwamish Books,Phase 4
Top Windows DNA Performance Mistakes and How to Prevent Them,Gary Geiger 和 Jon Pulsipher 合著
Building from Static HTML to High-Performance Web-Farms,Shawn Bice 著
工(gōng)具
Microsoft Web Application Stress Tool
I Can't Stress It Enough -- Load Test Your ASP Application,J.D. Meier 著
Windows DNA Performance Kit
Monitoring Events in Distributed Applications Using Visual Studio Analyzer,Mai-lan Tomsen 著
書(shū)目
Professional Active Server Pages 3.0,Wrox Press(特别是第 26 章:Optimizing ASP Performance,George Reilly 和 Matthew Gibbs 合著)。
Microsoft Internet Information Services 5.0 Resource Guide(與 Windows 2000 Server Resource Kit 在一(yī)起),Microsoft Press。
Microsoft Internet Information Server Resource Kit(用于 IIS 4.0),Microsoft Press。
Programming Distributed Applications with COM and Microsoft Visual Basic 6.0,Ted Pattison 著,Microsoft Press。
Effective COM,Don Box、Keith Brown、Tim Ewald 和 Chris Sells 合著;Addison-Wesley。
Developing Web Usability: The Practice of Simplicity,Jakob Nielsen 著,New Riders。
ASP Web 站點
Microsoft TechNet for IIS
LearnASP.com
4GuysFromRolla.com
15Seconds.com
AspToday.com
Asp101.com
AspLists.com。許多專業的郵件列表包括:
Fast Code!
ASP Advanced
Not NewbieState Management
Scalability
Visual Basic Components
XML
C++/ATL Component Building
UseIt.com: Web 可用性
ASP 樣式
ASP Best Practices,George Reilly 著
ASP Quick Lessons,Charles Carroll 著
Planning for ASP,John Meade 著
ASP Guidelines,J.D. Meier 著
XML
Inside XML Performance,Chris Lovett 著
Inside MSXML3 Performance,Chris Lovett 著