建立ASP.NET監視伺服器進程

來源:互聯網
上載者:User
asp.net|建立|伺服器|進程 產品簡介
您看到過出色的咖啡店店員送咖啡的情景嗎?那簡直就是咖啡豆、蒸汽和牛奶調和咖啡飲料在跳精彩的芭蕾,跳躍著奔向焦急等候的顧客。然而,即便是最好的店員偶爾也會出現問題。比如兩個單子在處理時搞混了,結果送到您面前的是一杯 Soy latte。也可能是杯子上龍飛鳳舞的潦草字跡根本就是寫錯了,或者店員理解錯了。有人要了一杯“卞高奇若”(卡普其諾),可憐的店員絞盡腦汁也弄不懂顧客到底要點什麼。如果出現了類似的問題,就必須停止處理,然後再重新開始。好的服務員可能會推延一下現有的要求,而優秀的服務員卻能夠在沒人察覺的情況下做到這一點。

Microsoft® ASP.NET 在系統可靠性方面取得了優於其任何競爭者的巨大進步。然而,就像那位出色的店員一樣,ASP.NET 偶爾也會出現問題。幸運的是,ASP.NET 是非常優秀的伺服器。它能在後台迅速產生新的進程,然後處理請求。通常只會在請求頁面時發生一點使用者甚至可能都不會注意到的輕微延遲。

而 ASP.NET 系統的管理員可能需要知道發生了什麼。同樣,他們也想瞭解是什麼原因導致了進程失敗。幸運的是,使用 .NET Framework 類庫文檔中的 ProcessInfo 和 ProcessModelInfo 類便可獲得相關資訊。本文中,我們將學習如何建立 ASP.NET HTTP 處理常式,以使用這些對象查看 Web 網站使用的進程的健全狀態和關閉狀況。另外,我們將建立一個配置節處理常式,這樣我們便能夠在安裝處理常式後對其進行配置。

我們將看到什嗎?
ASP.NET 進程負責編譯和管理所有向 ASP.NET 頁面提出的請求。理想狀況下,此進程應該始終存在於伺服器中:活躍地接收請求、編譯頁面並返回 HTML。然而,由於存在許多可能影響進程的潛在事件,我們不得不面對 Web 開發的真實狀況。開發人員可能未能正確處理記憶體流失或線程問題;伺服器可能會丟失與進程的串連;或者甚至會因為在 Web.config 檔案的 <processModel> Element 節中對 idleTimeout、requestLimit、memoryLimit 和類似的項目進行了錯誤的配置而導致出現問題。如果發生了以上任何一種事件,則將建立新的 ASP.NET 輔助進程,新的請求將移交至此進程進行處理。

由於 ASP.NET 進程對頁面處理如此重要,因此監視這些進程同樣重要。使用 ProcessInfo 和 ProcessModelInfo 類可以查看當前和以前進程的有效期間和健全狀態。圖 1 所示為在本文中建立的進程列表。



圖 1:Web 服務器的進程記錄

ProcessInfo class 儲存了給定進程的資料。不得自行建立 ProcessInfo 類,但可以使用 ProcessModelInfo class 來檢索 ProcessInfo 對象。表 1 所示為 ProcessInfo 類的重要屬性。

表 1:ProcessInfo 類的屬性

屬性 資料類型 說明
Age TimeSpan 進程運行(或曾經運行)的總時間。如果這個值超出了在 Web.Config 檔案的 processModel 節中的逾時設定,可導致重新啟動進程。
PeakMemoryUsed Integer 此進程所用記憶體的最大值(以 MB 為單位)。如果這個值超出了在 Web.Config 檔案的 processModel 節設定的 memoryLimit 層級設定,可導致進程重新啟動。
ProcessID Integer 作業系統使用此 ID 來標識進程。每個進程均有唯一的 ID(在進程運行時)。
RequestCount Integer 進程接收到的頁面請求的數量。如果這個值超出了在 Web.Config 檔案的 processModel 中 requestLimit 的層級設定,可導致進程重新啟動。
ShutdownReason ProcessShutdownReason 此枚舉定義進程重新啟動的可能原因。有關可能的值,請參閱表 2。
StartTime DateTime 進程啟動的時間。
Status ProcessStatus 此枚舉定義 ASP.NET 輔助進程的目前狀態。此值可能為 Alive(活動)、ShuttingDown(進程已接收到關閉請求)、ShutDown(進程已正常關閉)或 Terminated(進程已被迫關閉)。

某進程關閉後,關閉原因將被設定為 ProcessShutdownReason Enumeration 中的某一個值。

表 2:進程關閉的可能原因

值 說明
None 此值表明進程仍在運行。
Timeout 進程因其生存期超出了在 Web.Config 檔案的 processModel 節中設定的逾時值而重啟。如果這種情況頻繁發生,也許應考慮增加逾時值。不過,一般來說因這種原因而重新啟動可以接受。
IdleTimeout 進程重新啟動的原因是缺少用戶端。如果在 Web.Config 檔案的 processModel 節中的 idleTimeout 值所設定的時間期限內沒有用戶端請求,將發生此類重新啟動。這通常也是可以接受的重新啟動的原因。
RequestsLimit 進程重新啟動的原因是接收到的請求數量超過了在 Web.Config 檔案的 processModel 節中設定的值 (requestLimit)。一般來說,這種重新啟動的原因也可以接受,主要用於您希望進程偶爾重新啟動的情況。
MemoryLimitExceeded 進程重新啟動的原因是因為超出了通過 Web.Config 檔案中的 memoryLimit 值設定的記憶體限制。這通常表示進程的某個 ASP.NET 應用程式部分發生了問題(可能是記憶體流失)。如果此類現象頻繁發生,請監視每個 Web 應用程式的記憶體使用量是否正常。
RequestQueueLimit 進程重新啟動的原因是在等候響應的請求總數超出了 Web.Config 檔案的 requestQueueLimit 值。通常這是某些情況將導致 Web 服務器延遲的訊號。可能需要增加記憶體或伺服器,或提高磁碟機或處理器的速度。
DeadlockSuspected 進程重新啟動的原因是可能停止了正在處理的請求。正如這個關閉原因的名稱那樣,最可能導致這種情況的原因為:如果兩個或多個線程需要另一個線程完成後才能繼續進行(例如 A 線程需要 B 線程完成向某檔案的寫入後才能繼續進行,而同時 B 線程需要 A 線程完成計算後才能繼續進行),我們將這種情況稱為線程處於“Deadlock”(死結)狀態。如果有這種可能,進程將因此而關閉。一般來說,您肯定不希望看到這種關閉原因,如果您不幸看到了,請查看在應用程式中使用的所有線程處理或資源使用方式。
PingFailed 當 ASP.NET 輔助進程管理頁面時,有時會收到從 IIS 進程發來的 ping 以確定是否仍需要此進程。如果 ping 失敗,則 IIS 進程可能會關閉該 ASP.NET 進程。這個關閉原因說明了可能在伺服器接收訊息的過程中確實存在通訊問題或 ASP.NET 輔助進程因某種原因而停止工作。
Unexpected 一般來說,您肯定不想看到此訊息,因為它表明是“某種其他原因”終止了 ASP.NET 輔助進程。除了監視每個進程或對所有運行中的代碼執行代碼校對,幾乎沒有任何辦法解決此問題。

建立進程查看處理常式
在 ASP.NET 中,主要使用兩種方法來建立 HTTP 處理常式。第一種是通過建立帶有 ASHX 副檔名的檔案,另一種是建立實現 System.Web.IHttpHandler 的類,請參閱 IHttpHandler Interface。本文將著重介紹第二種形式。要建立 HTTP 處理常式,需要建立一個程式集(通常是一個程式碼程式庫項目)和一個實現 System.Web.IHttpHandler 的類。然後將該類註冊到 Web.Config(或 machine.config)檔案中,然後它就可以接收請求了。如果查看 machine.config 檔案(在相應命名的 httpHandlers 節中),將看到許多當前登入的 HTTP 處理常式,包括 System.Web.UI.PageHandlerFactory(ASP.NET 頁面的主處理常式)。在編寫 HTTP 處理常式時,其實就是在定義處理請求的新方法。

所有 HTTP 處理常式均通過實現 System.Web.IHttpHandler Interface 來建立。此介面需要建立一個屬性和一個方法,如表 3 所示。

表 3:IHttpHandler 介面的成員

成員 類型 說明
IsReusable 屬性 (Boolean) 確定該處理常式的執行個體是否可以重複使用。通常,該屬性應返回 true,除非處理常式需要對某個資源的獨佔訪問。
ProcessRequest 方法 HTTP 處理常式的“主”方法。將在此添加對請求的所有處理。該類傳遞當前 ASP.NET 上下文。可以從此上下文中檢索請求對象和響應對象。

實現 IHttpHandler
建立 HTTP 處理常式的大量工作集中在實現處理常式的 ProcessRequest。通常,需要儲存當前內容相關的請求和響應對象,然後使用響應對象的編寫方法建立輸出。以下給出了用於進程查看處理常式的 ProcessRequest 資源的 Microsoft Visual Basic® .NET 源。

Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
_context = context
_writer = New HtmlTextWriter(context.Response.Output)

'we only want to do this if we're enabled
If _config.Enabled Then
_writer.WriteLine("<html>")
_writer.WriteLine("<head>")
_writer.WriteLine(Me.StyleSheet)
_writer.WriteLine("</head>")

_writer.WriteLine("<body>")
_writer.WriteLine("<span class=""content"">")

'write content here
'create table
Dim t As New Table()
With t
.Width = Unit.Percentage(100)
.CellPadding = 0
.CellSpacing = 0
End With

'the meat of the routine
'make certain this is a destination machine
If (PermittedHost(_context.Request.UserHostAddress)) Then
CreateHeader(t)
AddProcesses(t)
CreateFooter(t)
Else
CreateErrorReport(t)
End If

'write to the stream
t.RenderControl(_writer)

_writer.WriteLine("</span>\r\n</body>\r\n</html>")
End If
End Sub

ProcessRequest 的實現會儲存當前上下文和編寫者。然後,它通過呈現頁面的起始 HTML 標籤將新的 HTML 頁面建立為輸出。下一步,它將建立一個用于格式化輸出的表格。最後,如果啟用了處理常式,並且發出請求的用戶端是合法的 IP 位址之一,則通過以下三種方法建立輸出: CreateHeader、AddProcesses 和 CreateFooter。這些方法將相應的值呈現在表格的儲存格中。這些代碼有很大一部分是重複的,為了簡短起見,以下僅給出了 AddProcesses 及其相關的方法。

Private Sub AddProcesses(ByVal table As _
System.Web.UI.WebControls.Table)
Dim procs As ProcessInfo() = _
ProcessModelInfo.GetHistory(_config.RequestLimit)
Dim row As TableRow

_list = New ProcessInfoCollection
For Each proc As ProcessInfo In procs
row = AddRow(table)
_list.Add(proc)
AddCell(row, proc.ProcessID.ToString())
AddCell(row, proc.Status.ToString())
AddCell(row, proc.StartTime.ToString("g"))
AddCell(row, FormatAge(proc.Age))
AddCell(row, proc.PeakMemoryUsed.ToString("N0") + " MB")
AddCell(row, proc.RequestCount.ToString("N0"))
AddCell(row, proc.ShutdownReason.ToString())
Next
End Sub
Private Function AddCell( _
ByVal row As System.Web.UI.WebControls.TableRow, _
ByVal text As String) As System.Web.UI.WebControls.TableCell
Dim c As New TableCell()
c.Text = text
row.Cells.Add©
Return c
End Function

細心的(和有技術背景的)讀者可能已經注意到,我完全可以通過呈現 DataGrid 並將 ProcessInfoCollection 綁定到 DataGrid 來簡化此代碼,但那樣就失去了編寫程式的樂趣。

安裝 HTTP 處理常式
建立完 HTTP 處理常式後,必須進行安裝才能使用。這包括使類可用,並在設定檔中添加相應的資訊以啟用處理常式。

如果建立的是僅被單個 vroot 使用的簡單處理常式,則可以將 DLL 複製至該 vroot 的 bin 目錄即可使用該類。如果建立了一個由多個 vroot 使用的 HTTP 處理常式(類似於 ProcessHandler),則此處理常式必須安裝到全域組件快取 (GAC) 中。要將此處理常式安裝到 GAC 中,類必須具有嚴格名稱。要具有嚴格名稱,它必須有關聯的嚴格名稱鍵。必須使用命令列可執行檔 sn.exe 建立嚴格名稱鍵檔案。有關此程式的詳細資料,請參閱 NET Framework Tools 文檔的 Strong Name Tool (Sn.exe) 一節。

處理常式可用後,下一步就是添加配置以使其可以處理請求,方法是在 Web.Config 或 machine.config 檔案的 httpHandlers 節中添加條目。此條目指定了將通過處理常式路由的副檔名和操作。進程查看處理常式的條目如下所示。

<add verb="*" path="process.axd"
type="Microsoft.Samples.Msdn.Web.ProcessHandler,
MsdnProcessHandler, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=f5f94c20bb90ce64" />

此條目意味著在某個請求使用任何 HTTP 命令尋找“檔案” process.axd(實際上不存在)時,它將向位於程式集 MsdnProcessHandler 中的 Microsoft.Samples.Msdn.Web.ProcessHandler 類發送請求。該類將實現 IHttpHandler,然後由 IHttpHandler 負責產生輸出。

添加配置
許多 ASP.NET 應用程式使用 appSetting 標籤添加自訂配置。這對於大多數應用程式來說已經完全足夠了。然而,有時應用程式可以使用更有針對性的解決方案。這種情況下,您可以為應用程式建立節。

建立配置節包括兩個步驟。首先,必須建立設定物件。此對象或結構具有表示所需配置資料的屬性。此對象可以具有、但通常不具有任何方法。其次要建立一個節處理常式。此節處理常式負責從 web.congfig 檔案中讀取相應的資訊,並且將其轉化為設定物件。

ProcessViewer 的設定物件具有四個屬性,如下表所述。

表 4:ProcessViewer 設定物件的屬性

屬性 資料類型 說明
Enabled Boolean 如果 ProcessViewer 可用,則為 true。這樣便可以暫時關閉處理常式而無需將其從 web.config 檔案中刪除。
LocalOnly Boolean 如果只能從本機電腦查看 ProcessViewer 的輸出,則為 true。這是最為安全的方案,防止其他人查看 Web 應用程式的進程記錄。
RequestLimit Integer 該屬性限定了顯示項目數的最大值。ProcessModelInfo.GetHistory 最多返回 100 個項目。此屬性用於在需要時減少此數量。
PermittedHosts String array 如果 LocalOnly 為 false,則任何電腦均可以訪問 Process.axd handler 來查看應用程式的進程記錄。這就可能會有安全風險。因此,可以分配允許訪問處理常式的 IP 位址的列表。此屬性可用於限制對管理員工作站的訪問。

建立自訂配置的第二步是建立解釋設定檔的 XML 的類,並使用該資訊填充設定物件。此類必須實現 System.Configuration.IConfigurationSectionHandler 介面。此介面只有一個方法,稱為 Create。以下給出了 ProcessViewerSectionHandler 的 Visual Basic .NET 源(請參閱 C# 源的下載)。

Public Function Create(ByVal parent As Object, _
ByVal configContext As Object, _
ByVal section As System.Xml.XmlNode) As Object _
Implements Configuration.IConfigurationSectionHandler.Create
' 節具有以下格式:
'<processView
' localOnly="true|false"
' requestLimit="<=100"
' enabled="true|false"
' permittedHosts="comma-delimited list of IP addresses" />
Dim result New ProcessViewerConfiguration()
Dim config As New ConfigurationHelper(section)

Dim max As Integer
Dim hosts As String
Const delimiter As String = ", "
Const MaximumReturnCount As Integer = 100
'確認設定,並設定
result.Enabled = config.GetBooleanAttribute("enabled")
result.LocalOnly = config.GetBooleanAttribute("localOnly")

max = config.GetIntegerAttribute("requestLimit")
If max <= MaximumReturnCount Then
result.requestLimit = max
End If

hosts = config.GetStringAttribute("permittedHosts")
result.PermittedHosts = hosts.Split(delimiter.ToCharArray())
Return result
End Function

Create 方法傳遞了三個對象:

parent - 表示父配置節(如果可用)。
configContext - 表示 HttpConfigurationContext 對象,即 Web 配置的剩餘部分。可以使用此對象從當前 web.config 檔案中檢索值。
section - 最為重要的參數,實際的配置節。使用此對象填充設定物件。
以上代碼使用了 ConfigurationHelper 對象。此對象是一個用於從節中檢索特定資料類型的簡單對象。此類的代碼如下所示。

Friend Class ConfigurationHelper
Dim _section As XmlNode
Public Sub New(ByVal configSection As XmlNode)
_section = configSection
End Sub
'接受 true/false、yes/no
Public Function GetBooleanAttribute(ByVal name As String) As Boolean
Dim value As String
Dim result As Boolean

value = GetStringAttribute(name).ToLower()
If ((Boolean.TrueString.ToLower() = value) _
OrElse (value = "yes")) Then
result = True
Else
result = False
End If

Return result
End Function

Public Function GetIntegerAttribute(ByVal name As String) As Integer
Dim value As String
Dim result As Integer

value = GetStringAttribute(name)
result = Int32.Parse(value)

Return result
End Function

Public Function GetStringAttribute(ByVal name As String) As String
Dim theAttribute As XmlAttribute
Dim result As String

theAttribute = _section.Attributes(name)
If Not theAttribute Is Nothing Then
result = theAttribute.Value
End If
Return result
End Function

End Class

要使用這個節處理常式和設定物件,必須將其註冊在相應的 ASP.NET 設定檔中。因為可以在任何進程中調用該類,所以最好將其添加到 machine.config 檔案中。在 machine.config 類的 configSection 節中的相應位置註冊節處理常式(我將其添加到了 system.web 節中)

<sectionGroup name="system.web">
... other sections
<section name="processView"
type="Microsoft.Samples.Msdn.Web.ProcessViewerSectionHandler,
MsdnProcessHandler, Version=1.0.0.0,
Culture=neutral,
PublicKeyToken=f5f94c20bb90ce64" />
</sectionGroup>

註冊完畢後,便可以向 machine.config 檔案中添加節,並且該類將成為可配置類。

小結
建立 HTTP 處理常式可以提供超出 ASP.NET. 功能的強有力機制,使得開發人員避開頁面模型,並建立、修改或擴充 Web 網站的內容。通過添加用於查看 ASP.NET 的進程記錄的 HTTP 處理常式,可以診斷代碼或伺服器中導致客戶投訴的問題,例如代碼中存在記憶體流失或未處理的異常,或伺服器的記憶體不足。

建立並安裝 HTTP 處理常式後,您將可以更敏銳地發現在此重要進程中發生的狀況。到時候您就會有時間來喝杯咖啡,而不是忙於追查 Web 網站進程重新啟動的原因了。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.