ASP.NET 效能監視,以及警示系統管理員的時機
Thomas Marquardt
Microsoft Corporation
更新日期:2003 年 7 月
適用於:
Microsoft® ASP.NET
總結: 討論哪些效能計數器最有助於診斷 Microsoft ASP.NET 應用程式中的壓力和效能問題、應設定哪些臨界值,以警示系統管理員發生問題,以及可用來監視 ASP.NET 應用程式健康情況的其他資源。 (17 個列印頁面)
Contents
監視效能計數器
監視事件記錄檔
監視 W3C 和 HTTPERR 記錄
用來監視 ASP.NET 的其他資源
瞭解效能計數器
.NET CLR 例外狀況計數器
.NET CLR 載入計數器
.NET CLR 記憶體計數器
ASP.NET 計數器
ASP.NET 應用程式計數器
進程計數器
處理器計數器
記憶體計數器
系統計數器
Web 服務計數器
結論
監視效能計數器
有許多效能計數器可用於監視應用程式。 選擇要包含在效能記錄中的哪些專案可能很棘手,並瞭解如何解譯它們是藝術。 本文應該可協助您更熟悉這兩項工作。
至少應針對 Microsoft® ASP.NET 應用程式監視下列效能計數器:
- Processor(_Total)\% Processor Time
- 處理 (aspnet_wp) \% 處理器時間
- 進程 (aspnet_wp) \私用位元組
- 進程 (aspnet_wp) \Virtual Bytes
- 進程 (aspnet_wp) \控制碼計數
- Microsoft® .NET CLR Exceptions\# Exceps thrown / sec
- ASP.NET\應用程式重新開機
- ASP.NET\要求遭到拒絕
- ASP.NET\背景工作進程重新開機 (不適用於 IIS 6.0)
- Memory\Available Mb
- Web 服務\目前的連線
- Web Service\ISAPI 擴充要求/秒
以下是用於監視效能的較大效能計數器清單。 效能資料比不足還好,特別是當您遇到不容易重現的問題時。 此清單省略數個通常不需要的效能計數器。 例如,只有在使用功能時,才需要會話狀態和交易效能計數器。
建議使用一些臨界值,根據我的偵錯和測試 ASP.NET 應用程式的經驗。 您可以搜尋本文中的「臨界值」,直接跳到這些閾值。 系統管理員應該根據其體驗,判斷是否要在超過這些閾值時引發警示。 在大部分情況下,警示是適當的,特別是當臨界值超過一段時間時。
監視事件記錄檔
請務必監視來自 ASP.NET 和 Microsoft® Internet Information Server (IIS) 訊息的事件記錄檔。 例如,ASP.NET 每次aspnet_wp背景工作進程終止時,將訊息寫入應用程式記錄。 例如,IIS 6.0 會將訊息寫入應用程式和/或系統記錄檔,例如,每次 w3wp 背景工作進程報告本身狀況不良或當機時。 撰寫 .NET 應用程式很容易讀取應用程式記錄檔,並篩選出來自 ASP.NET 和 IIS 的訊息,並在 (傳送電子郵件或視需要撥出呼叫器) 引發警示。
監視 W3C 和 HTTPERR 記錄
首先,透過 Internet Information Services (IIS) Manager 啟用 IIS 5.0 和 IIS 6.0 的 W3C 記錄。 此記錄可以設定為包含要求的各種資料,例如 URI、狀態碼等等。 掃描記錄檔中是否有錯誤碼,例如 404 找不到,並視需要採取動作來更正連結。 在 IIS 6.0 上,子狀態程式碼會包含在記錄檔中,而且適用于偵錯。 IIS 會使用子狀態碼來縮排特定問題。 例如,404.2 表示處理要求的 ISAPI 延伸模組已鎖定。 您可以在 關於自訂錯誤訊息 主題中找到狀態和子狀態碼的清單。
IIS 6.0 的新功能、格式不正確或不正確的要求,以及應用程式集區無法提供服務的要求,會記錄至 HTTPERR 記錄檔,方法是HTTP.SYS處理 HTTP 要求的核心模式驅動程式。 每個專案都包含 URL 和錯誤的簡短描述。
檢查 HTTPERR 記錄中是否有拒絕的要求。 當核心要求佇列超過時,以及快速失敗保護功能離線應用程式時,HTTP.SYS會拒絕要求。 發生第一個問題時,URL 會以 QueueFull訊息記錄,而第二個發生時,訊息會是 AppOffline。 根據預設,核心要求佇列會設定為 1,000,而且可以在 IIS 管理員的 [應用程式集區屬性] 頁面上設定。 建議將這增加至忙碌網站的 5,000,因為如果應用程式集區在負載非常高時損毀,核心要求佇列就可以輕鬆地超過 1,000。
檢查 HTTPERR 記錄檔中是否有因背景工作進程損毀或停止回應而遺失的要求。 當發生這種情況時,系統會針對每個執行中的要求,使用訊息 Connection_Abandoned_By_AppPool記錄 URL。 執行中要求是傳送至背景工作進程進行處理,但在當機或停止回應之前未完成的要求。
如需 HTTPERR 記錄的詳細資料,請參閱 Microsoft 知識庫文章 820729: HTTP API 中的錯誤記錄。
用來監視 ASP.NET 的其他資源
效能計數器和事件記錄檔不會攔截所有發生的錯誤,因此完全不足以監視 ASP.NET。 我建議撰寫簡單的應用程式,以傳送一或多個頁面的 HTTP 要求,並預期特定回應。 此工具應該監視最後一個位元組的時間 (TTLB) ,以確保頁面會及時提供。 它也應該記錄發生的任何錯誤,因為需要此資訊才能分析問題。
IIS 6.0 資源套件包含 記錄剖析器 2.1,這是用來剖析記錄檔的工具, (W3C 記錄檔、HTTPERR 記錄檔、事件記錄檔) ,並將結果儲存在檔案或資料庫中。 資源套件可以安裝在 Microsoft® Windows® XP 和 Microsoft® Windows Server™ 2003 上。
您也可以撰寫應用程式來收集效能資料、篩選事件記錄檔,以及記錄 Microsoft® SQL Server 資料庫中的重要資料。 使用 System.Diagnostics 命名空間即可輕鬆完成這項操作。 您甚至可以使用 System.Diagnostics.Process 類別來監視背景工作進程重新開機。
若要協助您開始使用,請使用本文頂端的連結,下載數個公用程式的範例程式碼:
- snap.exe的原始程式碼,這是用來記錄處理常式效能資料的命令列工具。 Snap.cs 檔案包含簡短描述,並說明如何編譯工具。
- HttpClient.exe的原始程式碼,這是一個簡單的用戶端,可記錄 HTTP 要求的上一個位元組 (TTLB) 的時間。 HttpClient.cs 檔案包含簡短描述,並說明如何編譯工具。
- qqq.exe的原始程式碼,這是用於壓力測試 ASP.NET 應用程式的命令列工具。 與壓力用戶端搭配使用時,例如 Microsoft® Application Center Test (ACT) ,此工具會將偵錯工具附加至背景工作進程並監視特定效能計數器。 當效能降低時,可以調整為中斷偵錯工具。 qqq.cs 檔案包含簡潔的描述,並說明如何編譯工具。
- pminfo.aspx 頁面使用 System.Web.ProcessModelInfo 類別來顯示aspnet_wp進程重新開機的相關資訊。 歷程記錄會維持到 w3svc 服務停止為止。
- ErrorHandler.dll的原始程式碼。 這是 IHttpModule,您可以新增至 HTTP 管線,以將未處理的例外狀況記錄到事件記錄檔。 最好將錯誤記錄到SQL Server資料庫,但範例會使用事件記錄檔來簡化。
另一個簡單的步驟是實作 Application_Error。 您可以將下列文字新增至 global.asax,並立即開始將大部分未處理的錯誤記錄到應用程式記錄檔:
<%@ import namespace="System.Diagnostics" %> <%@ import namespace="System.Text" %> const string sourceName = ".NET Runtime"; const string serverName = "."; const string logName = "Application"; const string uriFormat = "\r\n\r\nURI: {0}\r\n\r\n"; const string exceptionFormat = "{0}: \"{1}\"\r\n{2}\r\n\r\n"; void Application_Error(Object sender, EventArgs ea) { StringBuilder message = new StringBuilder(); if (Request != null) { message.AppendFormat(uriFormat, Request.Path); } if (Server != null) { Exception e; for (e = Server.GetLastError(); e != null; e = e.InnerException) { message.AppendFormat(exceptionFormat, e.GetType().Name, e.Message, e.StackTrace); } } if (!EventLog.SourceExists(sourceName)) { EventLog.CreateEventSource(sourceName, logName); } EventLog Log = new EventLog(logName, serverName, sourceName); Log.WriteEntry(message.ToString(), EventLogEntryType.Error); //Server.ClearError(); // uncomment this to cancel the error }
Application_Error 會攔截頁面內的剖析器、編譯和執行時間錯誤。 它不會攔截組態問題,也不會在處理要求 aspnet_isapi時攔截在直覺內發生的錯誤。 此外,使用模擬時,模擬權杖必須具有寫入此事件來源的許可權。 您可以將錯誤記錄到SQL Server資料庫,以避免模擬問題。
最後,Microsoft® Debugging Tools for Windows 對於在生產 Web 服務器上偵錯問題非常有用。 您可以從 下載 https://www.microsoft.com/whdc/ddk/debugging/installx86.mspx 這些工具。 有一個名為 sos.dll 的偵錯工具延伸模組,您可以載入偵錯工具windbg.exe或cdb.exe偵錯 Managed 程式碼。 它可以傾印垃圾收集的內容, (GC) 堆積、顯示受控堆疊追蹤、協助調查受控鎖定的爭用、顯示執行緒集區統計資料等等。 這可以下載為.NET Framework 應用程式生產偵錯中所述之偵錯工具組的一部分。
瞭解效能計數器
以下是重要效能計數器的簡短描述,以及如何使用這些計數器。
.NET CLR 例外狀況計數器
_Global_ 計數器實例不應該與這個計數器搭配使用,因為它是由所有 Managed 進程更新。 請改用 aspnet_wp 實例。
#Exceps擲回 /秒。每秒擲回的 Managed 例外狀況總數。 隨著此數目增加,效能會降低。 例外狀況不應該在正常處理過程中擲回。 不過請注意, Response.Redirect、 Server.Transfer和 Response.End 都會導致 ThreadAbortException 多次擲回,而依賴這些方法的月臺將會產生效能負面影響。 如果您必須使用 Response.Redirect,請呼叫 Response.Redirect (url,false) ,但不會呼叫 Response.End,因此不會擲回。 缺點是呼叫 Response.Redirect (url 之後的使用者程式碼會執行 false) 。 您也可以使用靜態 HTML 頁面來重新導向。 Microsoft 知識庫文章312629 提供進一步的詳細資料。
除了監視這個非常有用的效能計數器之外,應該使用 Application_Error 事件來警示系統管理員發生問題。
閾值:RPS 的 5%。 應調查大於此值的值,並視需要設定新的閾值。
.NET CLR 載入計數器
_Global_ 計數器實例不應該與這些效能計數器搭配使用,因為它是由所有 Managed 進程更新。 請改用 aspnet_wp 實例。
目前的 AppDomains。 進程中載入的 AppDomains 目前數目。 此計數器的值應該與 Web 應用程式數目加上 1 相同。 其他 AppDomain 是預設網域。
目前的元件。 進程中載入的目前元件數目。 根據預設,目錄中的 ASPX 和 ASCX 檔案會「批次」編譯。 這通常會根據相依性產生一到三個元件。 例如,如果有 ASPX 頁面在 ASCX 檔案上具有剖析時間相依性,通常會產生兩個元件。 其中一個會包含 ASPX 檔案,另一個 ASCX 檔案。 剖析時間相依性包括由 %@ 匯入 < % > 、 < %@ 參考 % > 和 < %@ 暫存器 % > 指示詞所建立的相依性。 透過 LoadControl 方法載入的控制項不會建立剖析時間相依性。 請注意,global.asax 本身會編譯成元件。
有時候,過多的記憶體耗用量是因為大量載入的元件所造成。 例如,顯示新聞文章的網站會使用一組從資料庫取得新聞的 ASPX 檔案,比每個文章所使用的單一 ASPX 檔案還要好。 網站設計工具應該嘗試動態產生內容、使用快取,並減少 ASPX 和 ASCX 頁面的數目。
元件無法從 AppDomain 卸載。 為了避免耗用過多的記憶體,當重新編譯數目 (ASPX、ASCX、ASAX) 超過編譯 numRecompilesBeforeAppRestart=/ > 所 < 指定的限制時,就會卸載 AppDomain。 請注意,如果 < %@ 頁面 debug=% > 屬性設定為 true,或 < 編譯 debug=/ > 設定為 true,則會停用批次編譯。
載入器堆積中的位元組。 類別載入器在所有 AppDomains 中認可的位元組數目。 此計數器應該會達到穩定狀態。 如果此計數器持續增加,請監視「目前元件」計數器。 每個 AppDomain 可能會載入太多元件。
.NET CLR 記憶體計數器
_Global_ 計數器實例不應該與這些效能計數器搭配使用,因為它是由所有 Managed 進程更新。 請改用 aspnet_wp 實例。
# 所有堆積中的位元組。 Managed 物件認可的位元組數目。 這是大型物件堆積和層代 0、1 和 2 堆積的總和。 這些記憶體區域的類型為 MEM_COMMIT (請參閱 VirtualAlloc) 的平臺 SDK 檔。 此計數器的值一律小於 Process\Private Bytes 的值,它會計算進程的所有MEM_COMMIT區域。 所有堆積中的私用位元組減去 # 位元組是 Unmanaged 物件所認可的位元組數目。 調查過多記憶體使用量的第一個步驟是判斷受控物件還是 Unmanaged 物件正在使用它。
若要調查過多的受控記憶體使用量,建議WINDBG.EXE和SOS.DLL,您可以在.NET Framework 應用程式的生產偵錯中閱讀。 SOS.DLL具有 「!dumpheap –stat」 命令,其中列出 Managed 堆積中物件的計數、大小和類型。 您可以使用 「!dumpheap –mt」 來取得物件的位址,並使用 「!gcroot」 來查看其根目錄。 命令 「!eeheap」 會顯示受控堆積的記憶體使用量統計資料。
診斷記憶體使用量的另一個公用程式是 CLR Profiler,其詳細討論如下。
使用過多的 Managed 記憶體,通常是因為:
- 將大量資料集讀入記憶體中。
- 建立過多的快取項目。
- 上傳或下載大型檔案。
- 剖析檔案時,使用太多規則運算式 (Regular Expression) 或字串。
- 過度 的 ViewState。
- 工作階段狀態中有過多資料,或工作階段過多。
# Gen 0 Collections。 已垃圾收集層代 0 物件的次數。 存留的物件會升階為層代 1。 當需要會議室來設定物件,或有人藉由呼叫 System.GC.Collect來強制集合時,就會執行集合。 涉及較高層代的集合需要較長的時間,因為它們前面是較低層代的集合。 嘗試將層代 2 集合的百分比降到最低。 作為經驗法則,層代 0 集合的數目應該大於第 1 代集合的數目 10 倍,類似于層代 1 和 2。 #Gen N Collections 計數器和 GC 計數器中的 % Time 最適合用來識別過度配置所造成的效能問題。 如需改善效能所需的步驟,請參閱 GC 中 % 時間的描述。
# Gen 1 集合。 已垃圾收集層代 1 物件的次數。 存留的物件會升階為層代 2。
臨界值:第 0 代集合的 10 分之一值。 執行良好的應用程式會遵循 #Gen 0 Collections 計數器描述中所述的經驗法則。
# Gen 2 集合。 已垃圾收集層代 2 物件的次數。 層代 2 是最高的,因此在集合中存留的物件會保留在層代 2 中。 第 2 代集合的成本可能很高,特別是當 Gen 2 堆積的大小過多時。
臨界值:第 1 代集合的 10 分之一值。 執行良好的應用程式會遵循 #Gen 0 Collections 計數器描述中所述的經驗法則。
在 GC 的時間 %。 執行上次垃圾收集所花費的時間百分比。 平均值 5% 或更少會被視為狀況良好,但大於此情況的尖峰並不常見。 請注意,所有線程都會在垃圾收集期間暫停。
GC 中高百分比時間最常見的原因,是依據每個要求進行太多配置。 最常見的原因是將大量資料插入 ASP.NET 快取、移除、重新產生,然後每隔幾分鐘重新插入快取。 通常可以進行少量變更,以大幅減少配置。 例如,因為串連字號串必須進行垃圾收集,所以每個要求可能會耗費大量資源。 具有適當初始容量的 StringBuilder 執行效能優於字串串連。 不過,StringBuilder 也需要進行垃圾收集,如果不正確使用,可能會導致比預期更多的配置,因為內部緩衝區已調整大小。 在每個字串上呼叫 Response.Write 多次會執行比將它們與 StringBuilder 合併得更好,因此如果您可以避免 StringBuilder altogther,請執行。
應用程式通常會在產生回應時,暫時將資料儲存在 StringBuilder 或 MemoryStream 中。 請考慮不在每個要求上重新建立此暫存儲存體,而是考慮實作字元或位元組陣列的可重複使用緩衝集區。 緩衝集區是具有 GetBuffer 和 ReturnBuffer 常式的物件。 GetBuffer常式會嘗試從緩衝區的內部存放區傳回緩衝區,但如果存放區是空的,則會建立新的緩衝區。 如果尚未達到儲存緩衝區數目上限, 則 ReturnBuffer 常式會將緩衝區傳回至存放區,否則會釋放它。 這個緩衝集區實作的缺點是需要鎖定執行緒安全。 或者,您可以使用 HttpCoNtext.ApplicationInstance 來存取 global.asax 中定義的實例欄位,以避免鎖定的效能影響。 每個管線實例都有一個 global.asax 實例,因此一次只能從一個要求存取欄位,使其成為儲存可重複使用字元或位元組緩衝區的絕佳位置。
若要減少 GC 中的 % 時間,您必須知道您的配置模式。 使用 CLR Profiler 來分析單一要求或最多幾分鐘的輕量壓力。 (這些工具是入侵的,而且不會用於 producton。) [配置圖表] 檢視會顯示為每個物件類型配置的總記憶體,以及執行配置的呼叫堆疊。 使用此專案來修剪過多的配置。 依大小檢視的長條圖檢視 (從 [檢視] 功能表選取 [長條圖配置的類型],) 摘要說明已設定物件的大小。 避免配置大於 85,000 個位元組的短期物件。 這些物件會配置在大型物件堆積中,而且收集的成本較高。 在 [依大小顯示長條圖] 檢視中,您可以使用滑鼠選取物件,然後按一下滑鼠右鍵以查看配置的物件。 減少配置是程式碼修改和分析的反復程式。
臨界值:平均為 5% 或更少;短期尖峰大於此情況很常見。 應該調查大於這個的平均值。 應該視需要設定新的閾值。
ASP.NET 計數器
此類別中的效能計數器只會在 w3svc 服務啟動時重設為 0。
應用程式重新開機。 應用程式重新開機的數目。 重新建立應用程式域和重新編譯頁面需要一段時間,因此應該調查未預期的應用程式重新開機。 發生下列其中一項時,會卸載應用程式域:
- 修改 machine.config、 web.config或 global.asax。
- 修改應用程式的 bin 目錄或其內容。
- 當 ASPX、ASCX 或 ASAX) (編譯數目超過編譯 numRecompilesBeforeAppRestart=/ > 所 < 指定的限制時。
- 修改虛擬目錄的實體路徑。
- 修改程式碼存取安全性原則。
- Web 服務已重新開機。
針對生產環境的 Web 服務器陣列,建議您在更新內容之前從輪替中移除伺服器,以獲得最佳效能和可靠性。 對於生產中的單一 Web 服務器,當伺服器處於負載時,即可更新內容。 知識庫文章810281中所述的 Hotfix 對於在應用程式重新開機後遇到錯誤的任何人都感興趣,例如共用違規與類似「無法存取 < 檔案 FileName > ,因為它正由另一個進程使用」錯誤。
知識庫文章 820746: FIX:某些防毒軟體程式可能會導致 Web 應用程式意外重新開機 v1.0,以及 1.1 版的 知識庫文章821438 中,修正了涉及防毒軟體和應用程式重新開機的問題。
臨界值:0。 在完美的世界中,應用程式域將在程式生命週期中存留。 應該調查過多的值,並視需要設定新的閾值。
執行中的應用程式。 執行中的應用程式數目。
要求目前。 ASP.NET ISAPI 目前處理的要求數目。 這包括已排入佇列、執行中或等候寫入用戶端的佇列。 此效能計數器已新增至 知識庫文章329959中所述之預先 SP3 Hotfix 中 ASP.NET v1.0。
當此計數器超過processModel組態區段中定義的requestQueueLimit時,ASP.NET 將會開始拒絕要求。 請注意,在 aspnet_wp 中執行時,requestQueueLimit 適用于 IIS 5.0 上的 ASP.NET,但可能令人意外地,在 w3wp 中執行時也適用于 IIS 6.0。 在 IIS 6.0 中執行時,已知數個 processModel 組態設定仍適用。 其中包括 requestQueueLimit、responseDeadlockInterval、maxWorkerThreads、maxIoThreads、minWorkerThreads 和 minIoThreads。 在 2003 年 6 月 1.1 日 Hotfix 匯總套件 ASP.NET 1.1版中修正的 Framework v1.1 中的 Bug,允許 ASP.NET 在 IIS 6.0 中執行時處理無限數目的要求。 修正會導致當 Requests Current 超過 requestQueueLimit 時,ASP.NET 拒絕要求。
針對傳統 ASP 應用程式,佇列的要求會在要求遭到拒絕時提供警告。 針對 ASP.NET,要求目前與應用程式佇列中的要求一起提供這項功能。ASP.NET 死結偵測機制也會使用此計數器。 如果要求目前大於 0,且未收到來自背景工作進程回應的持續時間大於processModel responseDeadlockInterval=/> 所 < 指定的限制,則會終止進程並啟動新的進程。 在知識庫文章 328267中所述的 SP3 Hotfix 中,已修改演算法,讓 Requests Current 必須大於processModel/> 組態區段中所指定的maxWorkerThreads 加 maxIoThreads加maxIoThreads的總和。 < 請注意,根據預設,要求執行逾時為 90 秒,且刻意小於 responseDeadlockInterval。 您可以透過 <HTTPRuntime executionTimeout=/> 組態設定或Server.ScriptTimeout屬性來修改要求執行逾時,但一律應該小於responseDeadlockInterval。
要求執行時間。 執行最後一個要求所花費的毫秒數。 在 Framework 1.0 版中,背景工作進程收到要求時會開始執行時間,並在 ISAPI ASP.NET 傳送HSE_REQ_DONE_WITH_SESSION至 IIS 時停止。 針對 IIS 第 5 版,這包括將回應寫入用戶端所花費的時間,但針對 IIS 第 6 版,回應緩衝區會以非同步方式傳送,因此不會包含將回應寫入用戶端所花費的時間。 因此,在 IIS 第 5 版上,具有慢速網路連線的用戶端會大幅增加此計數器的值。
在 Framework 1.1 版中,建立要求的 HttpCoNtext 開始執行時間,並在回應傳送至 IIS 之前停止。 假設使用者程式碼不會呼叫 HttpResponse.Flush,這表示執行時間會在將任何位元組傳送至 IIS 之前停止,或傳送至用戶端以取得該情況。
ASP.NET\要求執行時間是實例計數器,而且非常變動。 另一方面,可以輕易地平均最後一個位元組 (TTLB) ,並用來計算一段時間內效能的較佳估計值。 TTLB 可以透過以 Managed 程式碼撰寫的簡單 HTTP 用戶端來計算,或者您可以使用計算 TTLB 的其中一個 HTTP 用戶端,例如 Application Center Test (ACT) 。
請注意,如果 <編譯 debug=/> 設定為 TRUE,則會停用批次編譯,並 < 忽略HTTPRuntime executionTimeout=/> 組態設定以及Server.ScriptTimeout的呼叫。 如果 <processModel responseDeadlockInterval=/> 設定未設定為 Infinite,這可能會導致問題,因為偵錯頁面的要求理論上可以永遠執行。
臨界值:N.A. 此計數器的值應該穩定。 體驗可協助設定特定網站的閾值。 啟用進程模型時,要求執行時間會包含將回應寫入用戶端所需的時間,因此取決於用戶端連線的頻寬。
要求已排入佇列。 目前已排入佇列的要求數目。 在 IIS 5.0 上執行時,inetinfo 與 aspnet_wp 之間會有一個佇列,而且每個虛擬目錄都有一個佇列。 在 IIS 6.0 上執行時,會有一個佇列,其中要求會從機器碼張貼到 Managed ThreadPool,以及每個虛擬目錄的佇列。 此計數器包含所有佇列中的要求。 inetinfo 與 aspnet_wp 之間的佇列是一個具名管道,透過此管道將要求從一個進程傳送到另一個進程。 如果aspnet_wp進程中的可用 I/O 執行緒不足,此佇列中的要求數目就會增加。 在 IIS 6.0 上,當傳入要求和背景工作執行緒不足時,就會增加。
請注意,當 Requests Current 計數器超過< processModel requestQueueLimit=/ >時,就會拒絕要求。 許多人認為當要求佇列計數器超過 requestQueueLimit 時,就會發生這種情況,但這不是這種情況。 超過此限制時,要求將會遭到拒絕,並顯示 503 狀態碼和訊息「伺服器太忙碌」。如果要求因為這個原因而遭到拒絕,它永遠不會觸達 Managed 程式碼,而且不會收到錯誤處理常式的通知。 通常這只有在伺服器負載非常繁重時才會發生問題,雖然每小時的「高載」負載也可能造成此問題。 對於不尋常的高載負載案例,您可能對 知識庫文章 810259中所述的 Hotfix 感興趣,這可讓您從每個 CPU 的預設值 1 增加 I/O 執行緒數目下限。
每個虛擬目錄都有一個佇列,可用來維護背景工作角色和 I/O 執行緒的可用性。 如果可用的背景工作執行緒數目或可用的 I/O 執行緒數目低於HTTPRuntime minFreeThreads=/> 所 < 指定的限制,此佇列中的要求數目就會增加。 當超過HTTPRuntime appRequestQueueLimit=/> 所 < 指定的限制時,會以 503 狀態碼拒絕要求,而用戶端會收到包含「伺服器太忙碌」訊息的 HttpException。
根據本身,此計數器不是效能問題的清楚指標,也無法用來判斷何時會拒絕要求。 在 知識庫文章329959中,引進了兩個新的效能計數器來解決此問題:要求目前和應用程式佇列中的要求。 請參閱這兩個計數器的描述,以及拒絕的要求。
要求遭到拒絕。 被拒絕之要求的個數。 當超過其中一個佇列限制時,系統會拒絕要求, (請參閱要求已排入佇列) 的描述。 要求可能會因為許多原因而遭到拒絕。 後端延遲,例如 SQL 伺服器緩慢所造成的,通常會在管線實例數目突然增加之前,並降低 CPU 使用率和 Requests/秒。由於處理器或記憶體限制導致最終拒絕要求的處理器或記憶體限制,伺服器可能會在負載過重期間造成負擔過重。
應用程式的設計可能會導致過多的要求執行時間。 例如,批次編譯是一項功能,當收到頁面的第一個要求時,目錄中的所有頁面都會編譯成單一元件。 如果目錄中有數百個頁面,則此目錄中的第一個要求可能需要很長的時間才能執行。 如果 < 超過編譯 batchTimeout=/> ,批次編譯將會在背景執行緒上繼續,而且要求的頁面將會個別編譯。 如果批次編譯成功,元件將會保留至磁片,而且可以在應用程式重新開機之後重複使用。 不過,如果已修改應用程式 bin 資料夾中的 global.asax、web.config、machine.config或元件,批次編譯器將會因為相依性變更而再次執行。
仔細設計大型網站可能會對效能造成重大影響。 在此情況下,最好只有數個頁面會根據查詢字串資料而改變行為。 一般而言,您需要將要求執行時間降到最低,最好是透過平均時間到最後一個位元組 (TTLB) ,使用從網站要求一或多個頁面的 HTTP 用戶端進行監視。
下列效能計數器最適合用來探索拒絕要求的原因:
- Process\% Processor Time
- Process\Private Bytes
- Process\Thread Count
- Web Service\ISAPI 擴充要求/秒
- ASP.NET\Requests Current
- ASP.NET\Requests Queued
- ASP.NET\要求等候時間
- ASP.NET 應用程式\管線實例計數
- ASP.NET 應用程式佇列中的應用程式\要求
閾值:0。 這個計數器的值應該是 0。 應該調查大於此值的值。
要求等候時間。 最近要求在佇列中等候或具名管道所花費的毫秒數,這些要求存在於 inetinfo 和 aspnet_wp (請參閱要求已排入佇列) 的描述。 這不包括在應用程式佇列中等候的任何時間。
閾值:1000。 平均要求應該花費 0 毫秒在佇列中等候。
正在執行的背景工作進程。 目前aspnet_wp背景工作進程的數目。 在短時間內,新的背景工作進程和正在取代的背景工作進程可能會共存。 雖然很少見,但有時候會在死結結束時處理死結。 如果您懷疑這種情況,請考慮使用工具來監視背景工作進程的實例數目。 或者,可以使用 Memory\Available Mbytes 效能計數器,因為這些擱置進程會耗用記憶體。
閾值:2。 在關閉先前的背景工作進程期間,可能有兩個實例。 如果已啟用 webGarden ,閾值應#CPUs加 1。 大於此值的值可能表示在非常短時間內重新開機過多的進程。
背景工作進程重新開機。 aspnet_wp進程重新開機的數目。
閾值:1。 程式重新開機的成本很高且不想要。 值取決於進程模型組態設定,以及未預期的存取違規、記憶體流失和死結。 如果aspnet_wp重新開機,應用程式事件記錄檔專案將會指出原因。 如果發生存取違規或死結,要求將會遺失。 如果使用進程模型設定來預先回收進程,則必須設定適當的臨界值。
ASP.NET 應用程式計數器
當應用程式域或 Web 服務重新開機時,此類別中的效能計數器會重設為 0。
快取總專案。 快取中的目前專案數 (User 和 Internal) 。 在內部,ASP.NET 使用快取來儲存成本高昂的物件,包括組態物件、保留的元件專案、 MapPath 方法所對應的路徑,以及同進程會話狀態物件。
注意 效能計數器的「快取總計」系列有助於診斷同進程會話狀態的問題。 將太多物件儲存在快取中通常是記憶體流失的原因。
快取總點擊率。 使用者和內部) 所有快取要求的總點擊與遺漏比率 (。
快取總交易率。 每秒快取的新增和移除數目 (使用者和內部) 。 高流動率表示正在快速新增和移除專案,這可能很昂貴。
快取 API 專案。 使用者快取中目前的專案數。
快取 API 點擊率。 使用者快取要求的總點擊與遺漏比率。
快取 API 流動率。 每秒對使用者快取的新增和移除次數。 高流動率表示正在快速新增和移除專案,這可能很昂貴。
輸出快取專案。 目前在輸出快取中的專案數目。
輸出快取命中比率。 輸出快取要求的總點擊與遺漏比率。
輸出快取流失率。 每秒新增和移除輸出快取的數目。 高流動率表示正在快速新增和移除專案,這可能很昂貴。
管線實例計數。 使用中管線實例的數目。 只有一個執行緒可以在管線實例內執行,因此此數目會提供針對指定應用程式所處理的並行要求數目上限。 管線實例數目應該穩定。 突然增加表示後端延遲, (請參閱上述拒絕的要求描述) 。
編譯總計。 已編譯的 ASAX、ASCX、ASHX、ASPX 或 ASMX 檔案數目。 這是編譯的檔案數目,而不是產生的元件數目。 元件會保留至磁片,並重複使用,直到建立時間、上次寫入時間或檔案相依性變更的長度為止。 ASPX 頁面的相依性包括 global.asax、web.config、machine.config、bin 資料夾中的相依元件,以及頁面所參考的 ASCX 檔案。 如果您重新開機應用程式而不修改任何檔案相依性,則會重載保留的元件,而不需要任何編譯。 只有當檔案一開始剖析並編譯成元件時,這個效能計數器才會遞增。
不過,根據預設,不論建立多少個元件,此計數器都會針對剖析並編譯成元件的每個檔案遞增一次。
如果編譯失敗,計數器將不會遞增。
前置處理期間發生錯誤。 組態和剖析錯誤的總數。 每次發生組態錯誤或剖析錯誤時,此計數器都會遞增。 即使快取組態錯誤,計數器也會在每次發生錯誤時遞增。
注意 請勿只依賴「錯誤」效能計數器來判斷伺服器是否狀況良好。 當 AppDomain 卸載時,它們會重設為零。 不過,他們可以用來深入探討特定問題。 一般而言,請使用 Application_Error 事件,向系統管理員發出問題警示。
編譯期間發生錯誤。 編譯錯誤的總數。 系統會快取回應,而且此計數器只會遞增一次,直到檔案變更強制重新編譯為止。 實作自訂錯誤處理以引發事件。
執行期間發生錯誤。 執行時間錯誤的總數。
執行期間未處理的錯誤。 執行時間未處理的例外狀況總數。 這不包含下列專案:
- 事件處理常式清除的錯誤 (例如,Page_Error或Application_Error) 。
- 重新導向頁面所處理的錯誤。
- try/catch 區塊內發生的錯誤。
執行期間未處理的錯誤/秒。執行時間每秒未處理的例外狀況總數。
錯誤總計。 前置處理期間的錯誤總和、編譯期間的錯誤,以及執行期間的錯誤。
Errors Total/sec。前置處理期間的錯誤總數、編譯期間的錯誤,以及每秒執行期間的錯誤總數。
正在執行的要求。 目前正在執行的要求數目。 當 HttpRuntime 開始處理要求,並在 HttpRuntime 完成要求之後遞減時,就會遞增此計數器。 在 Framework 的 v1.1 中,此效能計數器中有一個 Bug,此效能計數器已修正于 ASP.NET 2003 年 6 月 1.1 日 Hotfix 匯總套件中。 不幸的是,知識庫文章不會說明 Bug。 修正之前,計數器包含將回應寫入用戶端所花費的時間。
應用程式佇列中的要求。 應用程式要求佇列中的要求數目 (請參閱上述) 已排入佇列的要求描述。 除了要求目前要求之外,應用程式佇列中的要求也會在要求遭到拒絕時提供警告。 如果只有幾個虛擬目錄,可能會適合將預設 appRequestQueueLimit 增加至 200 或 300,特別是針對負載過重的應用程式緩慢。
找不到要求。 找不到資源的要求數目。
要求未獲授權。 要求數目因為未經授權的存取而失敗。
要求逾時。已逾時的要求數目。
要求成功。 已成功執行的要求數目。
要求總計。 啟動應用程式之後的要求數目。
Requests/Sec。每秒執行的要求數目。 我偏好 「Web Service\ISAPI 擴充要求/秒」,因為它不受應用程式重新開機的影響。
進程計數器
使用這些計數器時,感興趣的程式會aspnet_wp和直覺。
% 處理器時間。 此進程執行緒使用處理器花費的時間百分比。
閾值:70%。 超過此值一段時程表示需要購買硬體或優化您的應用程式。
控制碼計數。
閾值:10000。 aspnet_wp中有 2000 個控制碼計數可疑,10,000 個遠超過可接受的限制。 如果所有進程的控制碼計數總計超過大約 40,000,這在對 IIS 的阻斷服務攻擊期間完全可達成,就會發生明顯的效能降低。
私人位元組。 此進程所擁有的認可記憶體目前大小,以位元組為單位。 記憶體流失是由一致且長時間增加的私用位元組所識別。 這是偵測記憶體流失的最佳效能計數器。
在 IIS 5.0 上執行時,應在 processModel memoryLimit=/ > 組態區段中設定 < Private Bytes 的記憶體限制。 在 IIS 6.0 上執行時,應在 IIS 管理員中設定記憶體限制。 開啟應用程式集區的 [屬性 ],然後在 [ 回收 ] 索引標籤上,針對 [最大使用的記憶體] (指定限制 ,以 MB 為單位) 。 此限制對應至私人位元組。 背景工作進程的私用位元組會與記憶體限制進行比較,以判斷何時要回收進程。 System.Web.Cacheing.Cache 也會使用 Private Bytes 和記憶體限制來判斷何時要從快取中排除專案,因而避免回收進程。 建議使用 60% 的實體 RAM 來避免分頁的記憶體限制,特別是當新進程因記憶體耗用量過長而取代舊進程時。 請注意, 知識庫文章330469 解決 ASP.NET 問題,其中無法監視具有大量執行中進程之伺服器上的私人位元組。 此 Hotfix 也可讓快取記憶體管理員在有大量執行中的進程時正常運作。
請務必調整具有大量實體 RAM 的機器上的記憶體限制,讓快取記憶體管理員和進程回收正常運作。 例如,假設您有使用預設記憶體限制之實體 RAM (GB) 4 GB 的伺服器。 這是問題。 實體 RAM 百分比為 2.4 GB,大於預設虛擬位址空間 2 GB。 那麼,記憶體限制應該設定為什麼?
有幾件事需要考慮:首先,當「進程\虛擬位元組」在虛擬位址空間限制的 600 MB 內, (通常為 2 GB) ,而第二個測試顯示「進程\虛擬位元組」通常大於「進程\虛擬位元組」,通常大於「進程\私人位元組」,而不是超過 600 MB。 這項差異是因為 GC 所維護的MEM_RESERVE區域部分,因此可在需要時快速認可更多記憶體。 這表示當「Process\Private Bytes」 超過 800 MB 時, 發生 OutOfMemoryException 的可能性會增加。 在此範例中,機器有 4 GB 的實體 RAM,因此您必須將記憶體限制設定為 20%,以避免記憶體不足的狀況。 您可以實驗這些數位,以最大化電腦上的記憶體使用量,但如果您想要安全播放,範例中的數位將會正常運作。
總而言之,請將記憶體限制設定為小於 60% 的實體 RAM 或 800 MB。 由於 v1.1 支援 3 GB 虛擬位址空間,如果您將 /3GB 新增至 boot.ini,則可以安全地使用 1,800 MB,而不是 800 MB 作為上限。
請注意,執行測試時,如果您想要強制 GC 並穩定受控記憶體,您可以呼叫 System.GC.GetTotalMemory (true) 一次。 這個方法會呼叫 GC。重複收集WaitForPendingFinalizers () 直到記憶體穩定在 5% 內為止。
閾值:至少 60% 的實體 RAM 和 800 MB。 大於 60% 的實體 RAM 值會開始對效能造成影響,特別是在應用程式與進程重新開機期間。 當私人位元組在虛擬位址空間限制為 2 GB 的進程中超過 800 MB 時,OutOfMemoryException 的關聯性大幅增加。
執行緒計數。 此進程中作用中的執行緒數目。 當負載太高時,執行緒計數通常會增加。
閾值:75 + ( (maxWorkerThread + maxIoThreads) * #CPUs) 。 如果使用 aspcompat 模式,應該增加閾值 :閾值:75 + ( (maxWorkerThread + maxIoThreads) * #CPUs * 2) 。
虛擬位元組: 此進程的虛擬位址空間目前大小,以位元組為單位。
除非在 boot.ini中使用 /3GB 參數啟用 3 GB 位址空間,否則使用者模式進程的虛擬位址空間限制為 2 GB。 當達到此限制時效能會降低,而且通常會導致進程或系統當機。 位址空間會隨著接近 2 GB 或 3 GB 的限制而分散,因此建議分別採用 1.4 或 2.4 GB 的保守臨界值。 如果您在這裡遇到問題,您會看到 擲回 System.OutOfMemoryException ,而且這可能會造成進程損毀。
在 IIS 6.0 上執行時,可以在 IIS 管理員中設定虛擬記憶體限制。 不過,若設定不正確,可能會導致 ASP.NET 發生問題。 ASP.NET 從快取中排除專案以避免超過 Private Bytes 限制,但演算法在此判斷中會使用 Private Bytes 和 Private Bytes 限制。 它不會監視虛擬位元組或虛擬位元組限制。 假設虛擬位元組與私人位元組之間的差異通常不超過 600 MB,如果您擔心虛擬記憶體流失或片段的可能性,您可以將虛擬位元組限制設定為大於私用位元組限制 600 MB 的值。 如果需要這樣做,請在應用程式集區的 [回收] 索引標籤上,以MB 為單位設定最大虛擬記憶體 (的限制) 。
架構 1.0 版不支援背景工作進程或狀態服務中的 3 GB 位址空間。 不過,如需在 inetinfo.exe內啟用 3 GB 位址空間的指示,請參閱 知識庫文章320353 。 版本 1.1 完全支援背景工作進程和狀態服務的 3 GB 位址空間。
閾值:600 MB 小於虛擬位址空間的大小;1.4 或 2.4 GB。
處理器計數器
% 處理器時間。 所有線程使用處理器所花費的時間百分比。
閾值:70%。 超過此值一段時程表示需要購買硬體或優化您的應用程式。
記憶體計數器
可用的 Mbytes。 可用的實體 RAM 數量。
閾值:20% 的實體 RAM。 應該調查小於此值的值,而且可能表示需要購買硬體。
系統計數器
- CoNtext 參數/秒。處理器切換執行緒內容的速率。 高數位可能表示使用者和核心模式之間的高鎖定爭用或轉換。 內容交換器/秒應該以線性方式隨著輸送量、負載和 CPU 數目而增加。 如果以指數方式增加,就會發生問題。 分析工具應該用於進一步調查。
Web 服務計數器
- 目前的連線。 此計數器的臨界值取決於許多變數,例如 (ISAPI、CGI、靜態 HTML 等) 、CPU 使用率等要求類型。 臨界值應透過體驗來開發。
- Total Method Requests/sec.主要用來作為診斷效能問題的計量。 比較這與 「ASP.NET Applications\Requests/sec」 和 「Web Service\ISAPI Extension Requests/sec」 比較,以便查看靜態頁面的百分比與aspnet_isapi.dll所呈現的頁面百分比。
- ISAPI 擴充要求/秒。主要用來作為診斷效能問題的計量。 與 「ASP.NET Applications\Requests/sec」 和 「Web Service\Total Method Requests/sec」 比較這點可能很有趣。請注意,這包括所有 ISAPI 延伸模組的要求,而不只是aspnet_isapi.dll。
結論
在上線之前,請先仔細壓力和應用程式效能測試,以避免發生重大問題。 許多人似乎遇到兩個主要輪轉區塊:
- 您必須使用 HTTP 用戶端,以模擬您預期網站體驗的流量和負載。
- 您必須在幾乎與生產環境相同的環境中測試整個應用程式。
它不容易模擬實際的網站流量,但我可以確實說,遇到問題的大部分應用程式從未經過充分壓力測試。 本文應該可協助您瞭解效能計數器,並建立一些實用的工具來監視效能。 若要套用負載,建議您使用 Microsoft Visual Studio® .NET 隨附®的 Microsoft Application Center Test (ACT) 。 您可以在 Microsoft Application Center Test 1.0 Visual Studio .NET Edition深入瞭解此壓力工具。 我也會建議 Microsoft® Web 應用程式壓力工具 (WAST) 。 您可以從 TechNet免費下載。 如果您的應用程式使用 ViewState,您必須使用 ACT,因為 WAST 無法動態剖析回應。
我不知道它與生產環境有關,但絕對有一些特殊之處。 我無法計算我聽過語句的時間:「問題只會發生在我們的生產網站上」。一般而言,差異在於應用程式本身。 實驗室中通常有一些無法模擬的應用程式部分。 例如,廣告伺服器已省略測試,或是用來模擬實際資料庫的資料庫大幅不同。 有時候網路或 DNS 差異是原因,有時它與伺服器執行所在的硬體不同。
我已在偵錯和監視 ASP.NET 應用程式的效能數年,但仍有一些需要協助的時間。 如果您發現自己位於這個位置, ASP.NET 網站上的 論壇是一個適合回答的地方。 但是,如果您真的在系結中,請使用該網站提供的連絡資訊來連絡 Microsoft 產品支援 人員。 請注意,如果 Microsoft 決定問題是 Microsoft 產品中瑕疵的結果,您就不會支付該事件的費用。
希望這份檔已提供您確保應用程式可靠性和效能所需的工具和資訊。 如果您有任何問題,請在 ASP.NET Web 上張貼,我將會盡最大努力回答。 祝您好運!
關於作者
Thomas Marquardt 是 Microsoft ASP.NET 小組的開發人員。 自 2000 年 7 月起,他正在偵錯及調查 ASP.NET 應用程式的效能問題。 Thomas 想要感謝 Microsoft ASP.NET 開發經理 Dmitry Robsman,這些年有數小時的說明和指引。