不修改程式碼優化ASP.NET網站效能的一些方法
本文將介紹一些方法用於優化ASP.NET網站效能,這些方法都是不需要修改程式程式碼的。它們主要分為二個方面:1. 利用ASP.NET自身的擴充套件性進行優化。2. 優化IIS設定。
配置OutputCache
用快取來優化網站效能的方法,估計是無人不知的。 ASP.NET提供了HttpRuntime.Cache物件來快取資料,也提供了OutputCache指令來快取整個頁面輸出。雖然OutputCache指令使用起來更方便,也有非常好的效果,不過,它需要我們在那些頁面中新增這樣一個指令。
對於設定過OutputCache的頁面來說,瀏覽器在收到這類頁面的響應後,會將頁面響應內容快取起來。只要在指定的快取時間之內,且使用者沒有強制重新整理的操作,那麼就根本不會再次請求服務端,而對於來自其它的瀏覽器發起的請求,如果快取頁已生成,那麼就可以直接從快取中響應請求,加快響應速度。因此,OutputCache指令對於效能優化來說,是很有意義的(除非所有頁面頁面都在頻繁更新)。
在網站的優化階段,我們可以用Fiddler之類的工具找出一些內容幾乎不會改變的頁面,給它們設定OutputCache,但是,按照傳統的開發流程,我們需要針對每個頁面檔案執行以下操作:
1. 簽出頁面檔案。
2. 新增OutputCache指令。
3. 重新發布頁面。
4. 簽入檔案(如果遇到多分支並行,還可能需要合併操作)。
以上這些原始碼管理制度會讓一個簡單的事情複雜化,那麼,有沒一種更簡單的方法能解決這個問題呢?
接下來,本文將介紹一種方法,它利用ASP.NET自身的擴充套件性,以配置檔案的方式為頁面設定OutputCache引數。配置檔案其它就是一個XML檔案,內容如下:
<?xml version="1.0" encoding="utf-8"?> <OutputCache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Settings> <Setting Duration="3" FilePath="/Pages/a3.aspx" /> <Setting Duration="10" FilePath="/Pages/a5.aspx" /> </Settings> </OutputCache>
看了這段配置,我想您應該也能猜到它能有什麼作用。
每一行配置引數為一個頁面指定OutputCache所需要的引數,示例檔案為了簡單隻使用二個引數,其它可以支援的引數請參考OutputCache指令。
為了能讓這個配置檔案有效,需要在web.config中配置以下內容(適用於IIS7):
<system.webServer> <modules> <add name="SetOutputCacheModule" type="WebSiteOptimize.SetOutputCacheModule, WebSiteOptimize" /> </modules> </system.webServer>
在這裡,我註冊了一個HttpModule,它的全部程式碼如下:
public class SetOutputCacheModule : IHttpModule { static SetOutputCacheModule() { // 載入配置檔案 string xmlFilePath = Path.Combine(HttpRuntime.AppDomainAppPath, "OutputCache.config"); ConfigManager.LoadConfig(xmlFilePath); } public void Init(HttpApplication app) { app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute); } void app_PreRequestHandlerExecute(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; Dictionary<string, OutputCacheSetting> settings = ConfigManager.Settings; if( settings == null ) throw new ConfigurationErrorsException("SetOutputCacheModule載入配置檔案失敗。"); // 實現方法: // 查詢配置引數,如果找到匹配的請求,就設定OutputCache OutputCacheSetting setting = null; if( settings.TryGetValue(app.Request.FilePath, out setting) ) { setting.SetResponseCache(app.Context); } }
ConfigManager類用於讀取配置檔案,並啟用了檔案依賴技術,當配置檔案更新後,程式會自動重新載入:
internal static class ConfigManager { private static readonly string CacheKey = Guid.NewGuid().ToString(); private static Exception s_loadConfigException; private static Dictionary<string, OutputCacheSetting> s_settings; public static Dictionary<string, OutputCacheSetting> Settings { get{ Exception exceptin = s_loadConfigException; if( exceptin != null ) throw exceptin; return s_settings; } } public static void LoadConfig(string xmlFilePath) { Dictionary<string, OutputCacheSetting> dict = null; try { OutputCacheConfig config = XmlHelper.XmlDeserializeFromFile<OutputCacheConfig>(xmlFilePath, Encoding.UTF8); dict = config.Settings.ToDictionary(x => x.FilePath, StringComparer.OrdinalIgnoreCase); } catch( Exception ex ) { s_loadConfigException = new System.Configuration.ConfigurationException( "初始化SetOutputCacheModule時發生異常,請檢查" + xmlFilePath + "檔案是否配置正確。", ex); } if( dict != null ) { // 註冊快取移除通知,以便在使用者修改了配置檔案後自動重新載入。 // 參考:細說 ASP.NET Cache 及其高階用法 // http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html CacheDependency dep = new CacheDependency(xmlFilePath); HttpRuntime.Cache.Insert(CacheKey, xmlFilePath, dep, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, CacheRemovedCallback); } s_settings = dict; } private static void CacheRemovedCallback(string key, object value, CacheItemRemovedReason reason) { string xmlFilePath = (string)value; // 由於事件發生時,檔案可能還沒有完全關閉,所以只好讓程式稍等。 System.Threading.Thread.Sleep(3000); // 重新載入配置檔案 LoadConfig(xmlFilePath); } }
有了AutoSetOutputCacheModule,我們就可以直接使用配置檔案為頁面設定OutputCache引數,而不需要修改任何頁面,是不是很容易使用?
說明:MyMVC框架已支援這種功能,所有相關的可以從MyMVC框架的原始碼中獲取。
建議:對於一些很少改變的頁面,快取頁是一種很有效的優化方法。
啟用內容過期
每個網站都會有一些資原始檔(圖片,JS,CSS),這些檔案相對於ASPX頁面來說,它們的輸出內容極有可能在一段長時間之內不會有變化,而IIS在響應這類資原始檔時不會生成Cache-Control響應頭。在這種情況下,瀏覽器或許會快取它們,也許會再次發起請求(比如重啟後),總之就是快取行為不受控制且快取時間不夠長久。
有沒有想過可以把它們在瀏覽器中長久快取起來呢?
為了告訴瀏覽器將這些檔案長久快取起來,減少一些無意義的請求(提高頁面呈現速度),我們可以在IIS中啟用內容過期,這樣設定後,IIS就能生成Cache-Control響應頭,明確告訴瀏覽器將檔案快取多久。
在IIS6中,這個引數很好找到:
然而,在IIS7中,這個引數不容易被發現,需要以下操作才能找到:
選擇網站(或者網站子目錄)節點,雙擊【HTTP響應標頭】
再點選右邊的【設定常用標頭】連結,
此時將會顯示:
說明:【啟用內容過期】這個設定可以基於整個網站,也可以針對子目錄,或者一個具體的檔案。
注意:如果您在IIS7中針對某個子目錄或者檔案設定【啟用內容過期】,前面的對話方塊看起來是一模一樣的,
然而,在IIS6中,我們可以清楚地從對話方塊的標題欄中知道我們在做什麼:
有時真感覺IIS7的介面在退步!
最後我想說一句:可以直接為整個網站啟用內容過期,ASPX頁面是不會被快取的!
說到這裡可能有人會想:這個過期時間我該設定多久呢?
十分鐘,2個小時,一天,還是一個月?
在我看來,這個時間越久越好。
可能有人又會說了:萬一我要升級某個JS檔案怎麼辦,時間設定久了,使用者怎麼更新呢?
如果你問我這個問題,我也只能說是你的程式碼不合理(畢竟你解決不了升級問題),想知道原因的話,請繼續閱讀。
解決資原始檔升級問題
對於一些規模不大的網站來說,通常會將資原始檔與程式檔案一起部署到一個網站中。
這時可能會採用下面的方式來引用JS或者CSS檔案:
<link type="text/css" href="aaaa.css" rel="Stylesheet" /> <script type="text/javascript" src="bbb.js"></script>
在這種情況下,如果使用了前面所說的【啟用內容過期】方法,那麼當有JS,CSS檔案需要升級時,由於瀏覽器的快取還沒有過期,所以就不會請求伺服器,此時會使用已快取的版本,因此可能會出現各種奇怪的BUG
對於前面談到的BUG,我認為根源在於引用JS,CSS檔案的方式有缺陷,那種方法完全沒有考慮到版本升級問題,正確的方法有二種:
1. 給檔名新增版本號,像jquery那樣,每個版本一個檔案(jquery-1.4.4.min.js)。
2. 在URL後面新增一個版本號,讓原先的URL失效。
第一種方法由於每次升級都產生了一個新檔案,所以不存在快取問題,但是,維護一大堆檔案的成本可能會比較大,因此我建議採用第二種方法來解決。
在MyMVC的示例程式碼中,我使用了下面的方法來引用這些資原始檔:
<%= HtmlExtension.RefCssFileHtml("/css/StyleSheet.css")%> <%= HtmlExtension.RefJsFileHtml("/js/MyPage/fish.js")%>
在頁面執行時,會產生如下的輸出結果:
<link type="text/css" rel="Stylesheet" href="/css/StyleSheet.css?_t=634642185820000000" /> <script type="text/javascript" src="/js/MyPage/fish.js?_t=634642154020000000"></script>
這二個工具方法的實現程式碼如下(在MyMVC的示例程式碼中):
private static readonly string s_root = HttpRuntime.AppDomainAppPath.TrimEnd('\\'); public static string RefJsFileHtml(string path) { string filePath = s_root + path.Replace("/", "\\"); string version = File.GetLastWriteTimeUtc(filePath).Ticks.ToString(); return string.Format("<script type=\"text/javascript\" src=\"{0}?_t={1}\"></script>\r\n", path, version); } public static string RefCssFileHtml(string path) { string filePath = s_root + path.Replace("/", "\\"); string version = File.GetLastWriteTimeUtc(filePath).Ticks.ToString(); return string.Format("<link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}?_t={1}\" />\r\n", path, version); }
上面這種獲取檔案版本號的方法,是一種比較簡單的解決方案。每個引用的地方在生成HTML程式碼時,都會訪問檔案的最後修改時間,這會給磁碟帶來一點讀的開銷,如果您擔心這種實現方式可能會給效能帶來影響,那麼也可以增加一個配置檔案的方式來解決(請自行實現),例如以下結構:
<?xml version="1.0" encoding="utf-8"?> <ArrayOfFileVersion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <FileVersion FilePath="/js/JScript.js" Version="255324" /> <FileVersion FilePath="/css/StyleSheet.css" Version="2324235" /> </ArrayOfFileVersion>
如果您認為這種配置檔案需要手工維護,不夠自動化,還可以採用程式的方式自動在執行時維護一個列表,總之,直接引用資原始檔的方法是一種直接耦合,會給檔案升級帶來麻煩,我們可以通過一個外部方法來解開這個直接耦合(給FileVersion增加一個屬性還還可以將內部地址改成一個CDN地址)。
啟用壓縮
壓縮響應結果也是常用的網站優化方法,由於現在的瀏覽器都已支援壓縮功能,因此,如果在服務端能壓縮響應結果,對於網速較慢的使用者來說,會減少很多網路傳輸時間,最終的體驗就是網頁顯示速度變快了!
IIS6雖然提供壓縮的設定介面,然而配置是基於伺服器級別的:
注意:這裡的【應用程式檔案】不包括aspx,如果需要壓縮aspx的響應,需要手工修改x:\WINDOWS\system32\inetsrv\MetaBase.xml檔案(參考加大字號部分):
<IIsCompressionScheme Location ="/LM/W3SVC/Filters/Compression/gzip" HcCompressionDll="%windir%\system32\inetsrv\gzip.dll" HcCreateFlags="1" HcDoDynamicCompression="TRUE" HcDoOnDemandCompression="TRUE" HcDoStaticCompression="TRUE" HcDynamicCompressionLevel="9" HcFileExtensions="htm html txt js css htc" HcOnDemandCompLevel="10" HcPriority="1" HcScriptFileExtensions="asp exe aspx axd" >
說明:要修改MetaBase.xml,需要停止IIS Admin Service服務。
在IIS7中,我們可以在伺服器級別配置壓縮引數:
然後在每個網站中開啟或者關閉壓縮功能:
說明:IIS7中已經不再使用MetaBase.xml,所以我們找不到IIS6的那些設定了。 IIS7壓縮的過濾條件不再針對副檔名,而是採用了mimeType規則(儲存在applicationHost.config)。根據IIS7的壓縮規則,當我們啟用動態壓縮後,會壓縮aspx的響應結果。
二種壓縮方法的差別:
1. 靜態內容壓縮:當伺服器在第一次響應某個靜態檔案時,會生成一個壓縮後的結果,並儲存到磁碟中,以便重用。
2. 動態內容壓縮:【每次】在響應客戶端之前,壓縮響應結果,在記憶體中完成,因此會給CPU帶來一些負擔。
注意:要不要【啟用動態內容壓縮】這個引數,需要評估伺服器的CPU是否能以承受(觀察工作管理員或者檢視效能計數器)。
刪除無用的HttpModule
對一個網站來說,ASP.NET提供的有些HttpMoudle可能並不是需要的,然而,如果你不去手工禁用它們,它們其實會一直執行。
比如 我會禁用下面這些HttpMoudle:
<httpModules> <remove name="Session"/> <remove name="RoleManager"/> <remove name="PassportAuthentication"/> <remove name="Profile"/> <remove name="ServiceModel"/> </httpModules>
對於使用Forms身份認證的網站的來說,下面這些HttpModule也是可以禁用的:
<httpModules> <remove name="WindowsAuthentication"/> <remove name="FileAuthorization"/> </httpModules>
其它優化選項
優化ASP.NET網站是一個大的話題,除了部落格中介紹的這些方法之外,還有以下方法也是可以參考的:
1. 升級伺服器硬體配置。
2. 使用Windows Server 2008以上版本作業系統(網路效能比2003要好)。
3. 優化作業系統配置(例如禁用不需要的服務)。
4. 禁用除錯模式。
5. 網站使用專用應用程式池。
相關文章
- [翻譯]ASP.NET 2.0網站應用程式的效能優化ASP.NET網站優化
- 用Redis做小型Asp.net網站的效能優化RedisASP.NET網站優化
- 網站效能優化網站優化
- Web 效能優化:21 種優化 CSS 和加快網站速度的方法Web優化CSS網站
- ASP.NET中常用的優化效能的方法ASP.NET優化
- 【譯】Web 效能優化:21種優化CSS和加快網站速度的方法Web優化CSS網站
- ASP.NET十個有效效能優化的方法ASP.NET優化
- Android效能優化一些方法Android優化
- 【THICK】ASP.NET中常用的優化效能的方法ASP.NET優化
- 談談程式碼效能優化中的一些小細節優化
- ASP.NET中常用的26個優化效能方法ASP.NET優化
- 淺談網站效能之前端效能優化網站前端優化
- 網站效能優化實戰(二)網站優化
- 網站效能優化的三重境界網站優化
- 程式碼維護:改進程式碼的一些方法 (轉)
- 網路效能優化常用方法優化
- iOS程式碼效能優化iOS優化
- 優化 iOS 程式效能的 25 個方法優化iOS
- 關於網站效能優化準則網站優化
- Android效能優化——程式碼優化(一)Android優化
- 雅虎網站效能優化的34條軍規!網站優化
- 【tronic】Asp.Net效能優化.ASP.NET優化
- Python 程式碼的效能優化之道Python優化
- IIS網站伺服器效能優化攻略網站伺服器優化
- 大型網站--前端效能優化和規範網站前端優化
- 前端效能優化—js程式碼打包前端優化JS
- 祖傳程式碼如何優化效能?優化
- 淺談JavaScript程式碼效能優化JavaScript優化
- Python 程式碼效能優化技巧Python優化
- .NET(C#)程式碼效能優化C#優化
- JavaScript 程式碼效能優化總結JavaScript優化
- 按照oracle效能改進方法論的步驟來優化系統!Oracle優化
- 提高網站訪問效能之Tomcat優化網站Tomcat優化
- [譯] 提高 10 倍效能:優化靜態網站優化網站
- 網站優化網站優化
- [譯]Web 效能優化: 圖片優化讓網站大小減少 62%Web優化網站
- Web 效能優化方法Web優化
- Asp.net常用優化方法ASP.NET優化