최근에 진행된 지원 케이스에서 ASP.Net 페이지의 서비스 속도 저하와 관련된 이슈에서 조금은 특이한 부분이 있어서 정리차원에서 블로그 글을 포스팅 합니다.
우선 문제 상황에 대한 간단한 내용을 보면 다음과 같습니다.
Windows 2003 서버에 .Net Framework 2.0 (또는 그 이상)이 설치되어 있고 ASP.Net 페이지들은 단순하게 사용자의 입력을 받고 서비스를 호출 한 후 결과를 보여주는 기능을 하고 있습니다. 이때 서비스는 역시 .Net Framework 2.0 C#으로 제작된 Serviced Component 형태로 COM+ 서버에서 작동 중 이었습니다.
COM+는 다시 실제 Business Logic을 구현하고 Exchange 2007 메일 서버에 EWS로 접근 하여 ASPX 페이지들이 보여줄 자료를 가공하는 역활을 하도록 제작되어 있습니다.
서비스 중에 느끼게 되는 문제의 형태는
1. Peak Time에 CPU나 메모리 사용량이 높거나 많지 않고,
2. netstat 등으로 확인해 보면 IIS 또는 COM+ 프로세스에서 사용하는 Network Connection 역시 많지 않은 상황 있었습니다.
어떤 이유에서 인지 서버들이 늘어난 처리 요청에 따라서 적절하게 시스템 리소스를 사용하지 못하고 의도 되지 않은 어떤 설정에 의해서 성능 저하를 가져오는 상태에 있었습니다.
문제 확인을 위해서 사용자가 많은 시점에 IIS의 Worker Process (W3WP.EXE)와 COM+ 프로세스 (DLLHOST.EXE)의 행모드 덤프(Hang-mode Debug Dump)를 수집 해서 상태 파악을 시도 했습니다.
W3WP.EXE에서 실행되는 모든 사용자 요청은 실제 아래의 형태와 같이 COM+ 서버에 전달된 자료 처리 요청에 대한 결과를 대기 중인 상태에 있었습니다.
ESP EIP
02c9eee8 7c96860c [ComPlusMethodFrameStandaloneCleanup: 02c9eee8] System.EnterpriseServices.IRemoteDispatch.RemoteDispatchAutoDone(System.String)
02c9eef8 0435ef72 System.EnterpriseServices.RemoteServicedComponentProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)
02c9ef40 794abdb3 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)
02c9f1e0 79f3cb53 [TPMethodFrame: 02c9f1e0] SomeBusinessModule.GetDataList(SomeBusinessData.DataEntry, System.String)
02c9f1f4 042a5feb ViewBusinessData.Page_Load(System.Object, System.EventArgs)
02c9f224 698a1928 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
02c9f234 0300d73f System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
02c9f248 02eba5a4 System.Web.UI.Control.OnLoad(System.EventArgs)
02c9f258 042a06cc BasePage.OnLoad(System.EventArgs)
02c9f264 02eba5f0 System.Web.UI.Control.LoadRecursive()
02c9f278 02ecbbf6 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
02c9f430 02ecb521 System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
02c9f460 02ecb487 System.Web.UI.Page.ProcessRequest()
02c9f498 02ecb3a7 System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)
02c9f4a0 02ecb33a System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
02c9f4b4 042a0165 ASP.ViewBusinessData_aspx.ProcessRequest(System.Web.HttpContext)
02c9f4b8 02d788df System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
02c9f4ec 02d4a071 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
02c9f52c 02d4a39b System.Web.HttpApplication.ResumeSteps(System.Exception)
02c9f574 02d4912d System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
02c9f590 02d4e0bd System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
02c9f5c4 02d4dd72 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)
02c9f5d0 02d4c447 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
02c9f780 79f1ef33 [ContextTransitionFrame: 02c9f780]
02c9f7d0 79f1ef33 [GCFrame: 02c9f7d0]
02c9f928 79f1ef33 [ComMethodFrame: 02c9f928]
같은 시점에 수집된 DLLHOST.EXE 덤프의 내용을 분석해 봤습니다.
우선 프로세스 기본 정보를 보면 서버는 4개의 CPU가 장착되어 있고 운영체제로 Windows 2003 SP2 를 사용하고 있다는 것을 알 수 있습니다.
Windows Server 2003 Version 3790 (Service Pack 2) MP (4 procs) Free x86 compatible
Product: Server, suite: Enterprise TerminalServer SingleUserTS
kernel32.dll version: 5.2.3790.4480 (srv03_sp2_gdr.090321-1244)
Machine Name:
Debug session time: Fri Jul 3 08:18:50.000 2009 (GMT+9)
…
프로세서의 사용 정보와 ThreadPool의 상태를 확인해 보면 사용자 요청이 많은 시간대 임에도 불구 하고 CPU 사용량이 8% 정도 이며 100개 까지 생성 될 수 있는 Worker Thread들 중 실행 중인 Thread가 1개 (Running : 1) 뿐 임을 할 수 있습니다.
Work Request in Queue: 0
--------------------------------------
Number of Timers: 0
--------------------------------------
CPU utilization 8%
--------------------------------------
Worker Thread: Total: 1 Running: 1 Idle: 0 MaxLimit: 100 MinLimit: 4
Completion Port Thread:Total: 0 Free: 0 MaxFree: 8 CurrentLimit: 0 MaxLimit: 1000 MinLimit: 4
문제 확인을 위해서 SyncBlock을 확인해 보니 아래와 같이 많은 숫자의 Thread들이 System.Net.ServicePoint 관련 SyncBlock에 대해 블로킹 된 상태로 사용 Thread의 완료를 기다리는 상태 임을 확인 할 수 있습니다.
0:000> !SyncBlk
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
352 1a3387e4 115 1 1a353728 23e8 17 09332f2c System.Net.ServicePoint
Waiting threads: 14 15 16 18 20 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 …
353 001728ec 3 1 1a353728 23e8 17 013a2ec8 System.Collections.ArrayList
Waiting threads: 19
354 1a391dcc 3 1 00162c70 24b4 19 013a2f1c System.Net.Connection
Waiting threads: 17
-----------------------------
Total 458
CCW 225
RCW 0
ComClassFactory 0
Free 150
실행 중인 Managed Thread들 중에 위의 SyncBlock 리스트의 Head에 해당하는 17번, 19번 Thread의 Call Stack은 아래와 같습니다.
이들은 System.Net.Connection 객체의 사용이 완료되어서 Close/Release를 진행 중인 상태에 있었습니다.
0:019> !ClrStack
OS Thread Id: 0x24b4 (19)
ESP EIP
1a29f7b0 7c96860c [GCFrame: 1a29f7b0]
1a29f880 7c96860c [HelperMethodFrame_1OBJ: 1a29f880] System.Threading.Monitor.Enter(System.Object)
1a29f8d8 7a5b0034 System.Net.ConnectionGroup.Disassociate(System.Net.Connection)
1a29f904 7a5aeaa7 System.Net.Connection.PrepareCloseConnectionSocket(System.Net.ConnectionReturnResult ByRef)
1a29f968 7a5ae293 System.Net.Connection.AbortOrDisassociate(System.Net.HttpWebRequest, System.Net.WebException)
1a29f9a0 7a57d9ff System.Net.HttpWebRequest.Abort(System.Exception, Int32)
1a29f9d4 7a57dbd1 System.Net.HttpWebRequest.AbortWrapper(System.Object)
1a29f9e8 793d91f6 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(System.Object)
1a29fb78 79e88f63 [GCFrame: 1a29fb78]
0:017> !ClrStack
OS Thread Id: 0x23e8 (17)
ESP EIP
00dfe0d4 7c96860c [GCFrame: 00dfe0d4]
00dfe1a4 7c96860c [HelperMethodFrame_1OBJ: 00dfe1a4] System.Threading.Monitor.Enter(System.Object)
00dfe1fc 7a5ae107 System.Net.Connection.CloseOnIdle()
00dfe228 7a5b0403 System.Net.ConnectionGroup.DisableKeepAliveOnConnections()
00dfe25c 7a58be63 System.Net.ServicePoint.ReleaseConnectionGroup(System.String)
00dfe28c 7a5c227f System.Net.NegotiateClient.Update(System.String, System.Net.WebRequest)
00dfe2ac 7a5a43c7 System.Net.AuthenticationState.Update(System.Net.HttpWebRequest)
00dfe2ec 7a57c04c System.Net.HttpWebRequest.DoSubmitRequestProcessing(System.Exception ByRef)
00dfe320 7a57e50a System.Net.HttpWebRequest.ProcessResponse()
00dfe358 7a57e4a3 System.Net.HttpWebRequest.SetResponse(System.Net.CoreResponseData)
00dfe39c 7a57e11a System.Net.HttpWebRequest.CheckWriteSideResponseProcessing()
00dfe3a8 7a57f51e System.Net.HttpWebRequest.EndSubmitRequest()
00dfe3d8 7a57dec6 System.Net.HttpWebRequest.SetRequestSubmitDone(System.Net.ConnectStream)
00dfe3ec 7a5ab8ff System.Net.Connection.CompleteStartRequest(Boolean, System.Net.HttpWebRequest, System.Net.TriState)
00dfe41c 7a5ab56b System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest)
00dfe460 7a58b1b4 System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
00dfe498 7a57ef21 System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
00dfe4c8 7a57cae2 System.Net.HttpWebRequest.GetResponse()
00dfe510 6990bf7d System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(System.Net.WebRequest)
00dfe540 6990c915 System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(System.Net.WebRequest)
00dfe544 69919eb1 System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(System.String, System.Object[])
00dfe588 19aa5560 ExchangeServiceBinding.FindItem(FindItemType)
00dfe598 1a300e14 AccessMailServer.GetMailList(...)
00dfefc8 79e88f63 [HelperMethodFrame_PROTECTOBJ: 00dfefc8] System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
00dff10c 794be820 System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(System.RuntimeMethodHandle, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
00dff12c 794bdf4b System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage, Int32, Boolean)
00dff1ac 794b6233 System.Runtime.Remoting.RemotingServices.ExecuteMessage(System.MarshalByRefObject, System.Runtime.Remoting.Messaging.IMethodCallMessage)
00dff1bc 673fd83d System.EnterpriseServices.ServicedComponentProxy.LocalInvoke(System.Runtime.Remoting.Messaging.IMessage)
00dff1fc 673fd64e System.EnterpriseServices.ServicedComponentProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)
00dff20c 673fb5a4 System.EnterpriseServices.ServicedComponent.RemoteDispatchHelper(System.String, Boolean ByRef)
00dff21c 673fb317 System.EnterpriseServices.ServicedComponent.System.EnterpriseServices.IRemoteDispatch.RemoteDispatchAutoDone(System.String)
00dff424 79f1ef33 [GCFrame: 00dff424]
00dff57c 79f1ef33 [ComMethodFrame: 00dff57c]
나머지 Thread들은 전부 아래와 같은 형태로 네트워크 관련 처리를 위해서 System.Net.ServicePoint 객체를 사용하기 위한 Monitor에 대해서 Waiting을 하고 있는 상태 였습니다.
ESP EIP
1a90e874 7c96860c [GCFrame: 1a90e874]
1a90e9ac 7c96860c [HelperMethodFrame: 1a90e9ac] System.Threading.Monitor.Enter(System.Object)
1a90ea00 7a58b151 System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
1a90ea38 7a57ef21 System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
1a90ea68 7a57bd92 System.Net.HttpWebRequest.GetRequestStream()
1a90ea9c 69919e6c System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(System.String, System.Object[])
1a90eae0 1a307f60 AccessMailServer.GetItem(GetItemType)
1a90eaf0 1a2f8414 SomeBusinessModule.GetChangedPArts(DataEntry, System.String)
1a90eb2c 1a2f8f74 SomeBusinessModule.Method1(DataEntry, System.String ByRef)
1a90eb84 1a2f2ff9 SomeBusinessModule.SendData(DataEntry, System.String ByRef)
1a90ec40 79e88f63 [ProtectByRefsFrame: 1a90ec40]
1a90efc8 79e88f63 [HelperMethodFrame_PROTECTOBJ: 1a90efc8] System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
1a90f10c 794be820 System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(System.RuntimeMethodHandle, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
1a90f12c 794bdf4b System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage, Int32, Boolean)
1a90f1ac 794b6233 System.Runtime.Remoting.RemotingServices.ExecuteMessage(System.MarshalByRefObject, System.Runtime.Remoting.Messaging.IMethodCallMessage)
1a90f1bc 673fd83d System.EnterpriseServices.ServicedComponentProxy.LocalInvoke(System.Runtime.Remoting.Messaging.IMessage)
1a90f1fc 673fd64e System.EnterpriseServices.ServicedComponentProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)
1a90f20c 673fb5a4 System.EnterpriseServices.ServicedComponent.RemoteDispatchHelper(System.String, Boolean ByRef)
1a90f21c 673fb317 System.EnterpriseServices.ServicedComponent.System.EnterpriseServices.IRemoteDispatch.RemoteDispatchAutoDone(System.String)
1a90f424 79f1ef33 [GCFrame: 1a90f424]
1a90f57c 79f1ef33 [ComMethodFrame: 1a90f57c]
위현상은 아래의 .Net Framework 성능 조정과 관련된 KB 문서에서 언급하고 있는 Connection 설정인 MaxConnection=2와 유사한 것으로 보입니다.
Contention, poor performance, and deadlocks when you make Web service requests from ASP.NET applications
http://support.microsoft.com/kb/821268/en-us
덤프에서 확인해 보면 실제 ServicePoint객체에서 확인 가능한 Connection Limit가 2로 설정되어 있음을 확인 할 수 있습니다. 즉, 문제가 되고 있는 현상은 .Net Framework과 관련된 설정이 성능에 문제를 일으키고 있다는 것 입니다. 하지만 위의 KB 문서를 보면 .Net Framework 2.0의 경우는 autoConfig를 설정하는 경우 maxconnection이 12*CPU 갯수라고 지정되어 있으며 문제 서버의 경우 AutoConfig가 Enable 되어 있는 상태 였습니다.
Name: System.Net.ServicePoint
MethodTable: 7a772e10
EEClass: 7a7d0b68
Size: 116(0x74) bytes
GC Generation: 2
(C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
MT Field Offset Type VT Attr Value Name
790fed1c 40020af 38 System.Int32 1 instance -1 m_ConnectionLeaseTimeout
7a77a4c4 40020b0 4 ...TimerThread+Queue 0 instance 05310044 m_ConnectionLeaseTimerQueue
79104f64 40020b1 54 System.Boolean 1 instance 0 m_ProxyServicePoint
79104f64 40020b2 55 System.Boolean 1 instance 0 m_UserChangedLimit
79104f64 40020b3 56 System.Boolean 1 instance 1 m_UseNagleAlgorithm
7a772738 40020b4 3c System.Int32 1 instance 0 m_HostLoopbackGuess
790fed1c 40020b5 40 System.Int32 1 instance -1 m_ReceiveBufferSize
79104f64 40020b6 57 System.Boolean 1 instance 1 m_Expect100Continue
79104f64 40020b7 58 System.Boolean 1 instance 0 m_Understands100Continue
7a772504 40020b8 59 System.Byte 1 instance 3 m_HttpBehaviour
790fa3e0 40020b9 8 System.String 0 instance 0535b350 m_LookupString
790fed1c 40020ba 44 System.Int32 1 instance 2 m_ConnectionLimit
790fea70 40020bb c ...ections.Hashtable 0 instance 0535b400 m_ConnectionGroupList
7a746d44 40020bc 10 System.Uri 0 instance 0535b0dc m_Address
790fa3e0 40020bd 14 System.String 0 instance 0535b13c m_Host
790fed1c 40020be 48 System.Int32 1 instance 80 m_Port
7a77a4c4 40020bf 18 ...TimerThread+Queue 0 instance 093325fc m_IdlingQueue
7a77a50c 40020c0 1c ...TimerThread+Timer 0 instance 053c42ac m_ExpiringTimer
79105ef0 40020c1 60 System.DateTime 1 instance 0535b3ec m_IdleSince
790fa3e0 40020c2 20 System.String 0 instance 7a72fa60 m_ConnectionName
790fed1c 40020c3 4c System.Int32 1 instance 0 m_CurrentConnections
79104f64 40020c4 5a System.Boolean 1 instance 0 m_HostMode
7a772d88 40020c5 24 ...et.BindIPEndPoint 0 instance 00000000 m_BindIPEndPointDelegate
790f9c18 40020c7 28 System.Object 0 instance 00000000 m_ServerCertificateOrBytes
790f9c18 40020c8 2c System.Object 0 instance 00000000 m_ClientCertificateOrBytes
790fa3e0 40020c9 30 System.String 0 instance 053622c8 m_HostName
79124228 40020ca 34 System.Object[] 0 instance 0536233c m_IPAddressInfoList
790fed1c 40020cb 50 System.Int32 1 instance 0 m_CurrentAddressInfoIndex
79104f64 40020cc 5b System.Boolean 1 instance 1 m_ConnectedSinceDns
79104f64 40020cd 5c System.Boolean 1 instance 0 m_AddressListFailed
79105ef0 40020ce 68 System.DateTime 1 instance 0535b3f4 m_LastDnsResolve
79104f64 40020cf 5d System.Boolean 1 instance 0 m_IPAddressesAreLoopback
79107d2c 40020c6 7ec System.AsyncCallback 0 shared static m_ConnectCallbackDelegate
>> Domain:Value 000de060:NotInit <<
실제 이부분이 설정의 문제인지 .Net Framework의 버그 인지 확인을 위해서 아래의 MSDN 문서를 확인해 본 결과 이는 실제 설계된 동작임을 알 수 있습니다.
즉, IIS Worker Process에서 실행되는 ASP.Net 응용프로그램을 제외한 (즉, W3WP 프로세스 이외에) 모든 프로세스들은 실행 시 autoConfig 설정이 적용용되지 않고, 별도의 설정을 하지 않는 경우 시스템 디폴트 값을 따르게 된다는 것 입니다.
ASP.Net 2.0
processModel Element (ASP.NET Settings Schema)
http://msdn.microsoft.com/en-us/library/7w2sway1.aspx
이 포스팅에서 설명하는 문제는 machine.config (또는 DLLHOST.EXE.CONFIG ) 설정을 변경 후 KB821268에서 언급하고 있는 시스템 가이드를 참조하여 변경 한 이후 해결이 되었습니다.
이외 비슷하게 ASP.Net 이외에 별도의 프로세스에서 Network에 접근하여 자료를 수집/분석/제공하는 서비스를 이용하는 경우 성능 조정을 위한 파라미터를 설정해 주셔야 합니다.
이전 포스팅에서 Tess의 IIS 6.0 + ASP.Net 1.1 이하 버젼에서의 Hang Dump 분석과 관련된 정보를 올렸습니다.
비교적(겨우 2년 전이네요 :-) 최근에 Tess의 블로그에 ASP.Net 2.0 에서 같은 맥락으로 Hang Dump 분석시 참고가 되는 글이 올라와서 같이 번역(사실 거의 복사에 가깝습니다만) 해서 올립니다.
Tess의 글에서 언급하고 있습니다만 서버 프로세스가 처리를 하지 않거나 메모리 사용량이 늘어나거나 CPU 점유율이 높아지면서 Hang Dump를 수집하게 되면 고객들 께서는 "무슨 일을 하기에" 그런 일이 벌어지는지 문의를 하십니다.
바로 이전 포스팅과 본 포스팅은 "무슨일" 이 아니라 "나머지 무시할 수 있는 것"들에 대한 얘기 입니다. 즉, 사용자의 Request를 처리하지 않는 "Normal"한 (또는 Idle 상태의) Thread들은 어떻게 생겼는가 에 대해서 언급하고 있습니다.
일단 이전 포스팅에서 IIS 6.0의 W3WP 프로세스의 Thread들이 소개 되어 있기 때문에 간단하게 넘기고 여기서는 제목 처럼 .Net Framework 2.0(또는 ASP.Net 2.0)에서 이전의 .Net Framework 1.1과 달라진 부분에 집중 해 보겠습니다.
우선 놀고 있는 CLR Worker Thread를 보죠.
IIS나 ASP.Net 관련 Dump 분석에서 많이 참고하는 Tess의 MSDN 블로그에 덤프 분석에 유용하게 사용 될 수 있는 Posting이 있어서 소개 합니다.
이 포스트는 Tess의 Things to ignore when debugging an ASP.NET hang(http://blogs.msdn.com/tess/archive/2005/12/20/505862.aspx) 을 약간 번역(오역?) 한 내용 입니다. 기술 내용의 특징상 사람이 보려고 만든 내용은 아닐 듯 한데 생각보다 많은 분들이 관련 내용에 관심을 가지시더군요.
어떤 문제가 발생한 덤프를 분석한다는 것이 쉬운 일은 아닙니다. 특히, 어느 특정 시점에 작동 중이 프로세스의 Snapshot인 Dump만으로 이전/이후 상황을 설명하고 파악한다는 것은 나름 많은 기반 지식과 경험이 필요한 일 입니다.
분석 중 가장 필요한 내용 중 하나가 정상 적인 Thread의 Stack trace를 빨리 무시(?) 해 나가는 것 입니다.
아래의 Stack Trace들은 IIS 6.0 W3WP.EXE 프로세스에서 실행 중인 Thread들의 내용입니다. 특이 이들 Thread들은 대부분 대기 상태인 Worker Thread들이기 때문에 (일이 없어서 쉬는 상태 - Idle) 덤프 분석 중 무시 하실 수 있습니다. 분석의 속도를 높여 줄 수 있겠지요.
Tess의 포스트에서 노트로도 나옵니다만 아래 Thread의 Stack Trace는 실제 프로세스 덤프에서 확인 하실 수 있는 대표적인 것들만 요약한 것이며 더 많은 복잡한 Thread들이 작동 중일 수 있습니다.
원래 IIS에서 실행되는 Thread들의 종료가 많기 때문에 Tess는 아래와 같이 Thread들을 분류 하고 있습니다.
- CLR Threads
- W3WP Threads
- RPC Threads
- Other COM Threads
CLR Threads
.Net Framework과 관련된 Thread들 입니다. .Net Framework의 ThreadPool은 5가지 종류의 Thead 가 있습니다.
프로그래머가 작성한 코드 (Managed 내지는 .Net CLR 코드) 는 Completion Port/IO Threads와 Worker Thread들에 의해서 실행 됩니다.
Gate Thread( 문지기)는 서버 CPU 사용량, GC(Garbage Collection) 주기와 Worker Queue의 크기를 전반적으로 고려해서 필요한 경우 Worker Thread와 IO Thread들을 만들거나 파괴 합니다. Wait Thread들은 동기화 객체들에 대해서 대기하는 경우 사용 됩니다. 즉, 개발자가 사용하는 WaitHandle 클래스를 사용하는 경우 결과적으로 "WaitForSingleObject"가 호출이 되겠지요. 마지막으로 Timer Callback을 구현하는데는 Timer Thread들에 사용 됩니다.
그럼 이들 Thread들이 ASP.Net 1.1을 서비스하는 W3WP.exe 프로세스의 덤프에서 어떻게 나타나는지 보도록 하겠습니다.
Idle CLR WorkerThread
| 11 Id: fb8.268 Suspend: 0 Teb: 7ffaa000 Unfrozen ChildEBP RetAddr Args to Child 0199fdf8 7c822124 77e6baa8 00000234 00000000 ntdll!KiFastSystemCallRet 0199fdfc 77e6baa8 00000234 00000000 0199fe40 ntdll!NtWaitForSingleObject+0xc 0199fe6c 77e6ba12 00000234 00009c40 00000000 kernel32!WaitForSingleObjectEx+0xac 0199fe80 791d401f 00000234 00009c40 00000000 kernel32!WaitForSingleObject+0x12 0199fea4 791fdacc 00000000 00000000 80a56bcc mscorsvr!ThreadpoolMgr::WorkerThreadStart+0x3a 0199ffb8 77e66063 000b6da8 00000000 00000000 mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44 0199ffec 00000000 791fda8b 000b6da8 00000000 kernel32!BaseThreadStart+0x34 |
Idle CLR Completion Port / IO Thread
| 9 Id: fb8.ef8 Suspend: 0 Teb: 7ffac000 Unfrozen ChildEBP RetAddr Args to Child 0191fec0 7c821bf4 77e6611a 0000023c 0191ff1c ntdll!KiFastSystemCallRet 0191fec4 77e6611a 0000023c 0191ff1c 0191ff08 ntdll!NtRemoveIoCompletion+0xc 0191fef0 791fdb22 0000023c 0191ff18 0191ff1c kernel32!GetQueuedCompletionStatus+0x29 0191ff24 791fdacc 00000001 809a05fe 7ffac000 mscorsvr!ThreadpoolMgr::CompletionPortThreadStart+0x49 0191ffb8 77e66063 000b6da8 00000000 00000000 mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44 0191ffec 00000000 791fda8b 000b6da8 00000000 kernel32!BaseThreadStart+0x34 |
Idle CLR Gate Thread
10 Id: fb8.bdc Suspend: 0 Teb: 7ffab000 Unfrozen
ChildEBP RetAddr Args to Child
0195fe50 7c821364 77e42439 00000000 0195fe94 ntdll!KiFastSystemCallRet
0195fe54 77e42439 00000000 0195fe94 00000000 ntdll!NtDelayExecution+0xc
0195febc 77e424b7 000001f4 00000000 0195ffb8 kernel32!SleepEx+0x68
0195fecc 791bf4f9 000001f4 0b2646e6 00000939 kernel32!Sleep+0xf
0195ffb8 77e66063 00000000 00000000 00000000 mscorsvr!ThreadpoolMgr::GateThreadStart+0x54
0195ffec 00000000 791bf4a5 00000000 00000000 kernel32!BaseThreadStart+0x34
|
Idle CLR Wait Thread
|
25 Id: 230.ac0 Suspend: 0 Teb: 7ff4c000 Unfrozen ChildEBP RetAddr Args to Child 1b88ff6c 7c573a4e 00000001 1b88ff84 00000000 NTDLL!ZwDelayExecution+0xb 1b88ff8c 7923558c ffffffff 00000001 198ba828 KERNEL32!SleepEx+0x32 1b88ffb4 7c57438b 00000000 198ba828 197f7498 mscorsvr!ThreadpoolMgr::WaitThreadStart+0x45 1b88ffec 00000000 7923556a 1973b3d0 00000000 KERNEL32!BaseThreadStart+0x52 |
Idle CLR Timer Thread
|
18 Id: fb8.914 Suspend: 0 Teb: 7ff5f000 Unfrozen ChildEBP RetAddr Args to Child 0224ff38 7c821364 77e42439 00000001 0224ff7c ntdll!KiFastSystemCallRet 0224ff3c 77e42439 00000001 0224ff7c 000003e8 ntdll!NtDelayExecution+0xc 0224ffa4 791cc578 000003e8 00000001 00000000 kernel32!SleepEx+0x68 0224ffb8 77e66063 00000000 00000000 00000000 mscorsvr!ThreadpoolMgr::TimerThreadStart+0x30 0224ffec 00000000 791cc548 00000000 00000000 kernel32!BaseThreadStart+0x34 |
.Net Framework의 수행 과정에서 빠질 수 없는 중요 Thread 몇가지를 아래에서 설명하고 있습니다.
이들중 가장 중요한 것으로 GC(Garbage Collector) Thread가 있습니다. GC Thread는 CLR의 Managed Heap 메모리를 관리합니다.
프로세서(Processor, CPU가 여러개 설치 되어 있거나 최근의 Multi-Core CPU를 사용하는 경우) 서버 버젼의 GC Thread는 CPU 들 마다 하나 씩 생성이 됩니다. Hyper-Threading 방식의 다중 CPU의 경우에는 서버 설정에 따라서 2개 CPU당 (Task Manager에서 확인되는) 하나의 GC Thread가 만들어 질 수 있습니다.
잠시 서버 버젼이라는 얘기가 나와서 부연 설명을 하자면 .Net Framework 1.1에서는 Server 버젼과 Workstation 버젼의 2개의 GC가 존재하며 서버 버젼의 경우 프로세스에 MSCORSVR.DLL 이, 클라이언트의 경우 (WinForm Application과 같은 경우) MSCORWKS.DLL이 로딩됩니다.
GC Thread와 달리 Finalizer Thread는 프로세스당 하나가 실행 됩니다. Hang이나 메모리 사용량이 많은 문제가 있는 프로세스에서는 Finalizer를 자세히 관찰할 필요가 있습니다. Finalize가 정상 작동 하지 않고 멈춰있는 경우 Finalzing이 정상적으로 되지 못해 완전히 파괴되지 못한 객체들 때문에 memory leak (점진적인 메모리 점유 현상)이 발생할 수 있고 이때문에 잦은 GC 가 발생하여 CPU 사용량이 높아지는 경우도 있습니다.
마지막으로 Debugging 시 사용되는 Debugger Thread도 나오네요.
Idle CLR GC Thread
|
13 Id: fb8.c10 Suspend: 0 Teb: 7ffa8000 Unfrozen ChildEBP RetAddr Args to Child 01d6fefc 7c822124 77e6baa8 000002b4 00000000 ntdll!KiFastSystemCallRet 01d6ff00 77e6baa8 000002b4 00000000 00000000 ntdll!NtWaitForSingleObject+0xc 01d6ff70 77e6ba12 000002b4 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac 01d6ff84 791fe6b0 000002b4 ffffffff 00000000 kernel32!WaitForSingleObject+0x12 01d6ffac 792356be 00000000 01d6ffec 77e66063 mscorsvr!gc_heap::gc_thread_function+0x2f 01d6ffb8 77e66063 000d2ed8 00000000 00000000 mscorsvr!gc_heap::gc_thread_stub+0x1e 01d6ffec 00000000 792356a0 000d2ed8 00000000 kernel32!BaseThreadStart+0x34 |
Idle CLR Finalizer Thread
|
17 Id: fb8.7b0 Suspend: 0 Teb: 7ffa4000 Unfrozen ChildEBP RetAddr Args to Child 01e6fdf8 7c822114 77e6711b 00000002 01e6fe48 ntdll!KiFastSystemCallRet 01e6fdfc 77e6711b 00000002 01e6fe48 00000001 ntdll!NtWaitForMultipleObjects+0xc 01e6fea4 77e61075 00000002 793eee08 00000000 kernel32!WaitForMultipleObjectsEx+0x11a 01e6fec0 7927826b 00000002 793eee08 00000000 kernel32!WaitForMultipleObjects+0x18 01e6fee0 791fecf4 000002dc 00000000 792376a4 mscorsvr!WaitForFinalizerEvent+0x5a 01e6ff24 79245681 00000000 809a05fe 7ffa4000 mscorsvr!GCHeap::FinalizerThreadStart+0x96 01e6ffb8 77e66063 000d5500 00000000 00000000 mscorsvr!Thread::intermediateThreadProc+0x44 01e6ffec 00000000 79245640 000d5500 00000000 kernel32!BaseThreadStart+0x34 |
Idle CLR Debugger Thread
|
12 Id: fb8.b30 Suspend: 0 Teb: 7ffa9000 Unfrozen ChildEBP RetAddr Args to Child 01adfe70 7c822114 77e6711b 00000003 01adfec0 ntdll!KiFastSystemCallRet 01adfe74 77e6711b 00000003 01adfec0 00000001 ntdll!NtWaitForMultipleObjects+0xc 01adff1c 77e61075 00000003 01adff5c 00000000 kernel32!WaitForMultipleObjectsEx+0x11a 01adff38 79238fd6 00000003 01adff5c 00000000 kernel32!WaitForMultipleObjects+0x18 01adffa0 79238f4d 00000000 00000000 00000000 mscorsvr!DebuggerRCThread::MainLoop+0x90 01adffb0 7923a714 01adffec 77e66063 019d1eb0 mscorsvr!DebuggerRCThread::ThreadProc+0x68 01adffb8 77e66063 019d1eb0 00000000 00000000 mscorsvr!DebuggerRCThread::ThreadProcStatic+0xb 01adffec 00000000 7923a709 019d1eb0 00000000 kernel32!BaseThreadStart+0x34 |
W3wp Thread들
W3WP 프로세서에서는 기본적으로 main Thread, W3WP Thread Pool Thread와 Compression Thread(HTTP Stream 압축용) 가 생성/작동 됩니다.
Main Thread는 프로세스의 시작고 종료를 담당 합니다. 웹서버에 전달되는 Request들은 Thread Pool Thread가 처리 합니다.
아래 Thread들의 Stack Trace들 여기 일없이 대기 중인 것 들 입니다.
W3wp main thread
|
. 0 Id: fb8.fd8 Suspend: 0 Teb: 7ffdf000 Unfrozen ChildEBP RetAddr Args to Child 0006fc08 7c822124 77e6baa8 00000184 00000000 ntdll!KiFastSystemCallRet 0006fc0c 77e6baa8 00000184 00000000 00000000 ntdll!NtWaitForSingleObject+0xc 0006fc7c 77e6ba12 00000184 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac 0006fc90 5a36467a 00000184 ffffffff 00000000 kernel32!WaitForSingleObject+0x12 0006fca0 5a366e63 00254ff8 5a3af41d 00000000 w3dt!WP_CONTEXT::RunMainThreadLoop+0x10 0006fca8 5a3af41d 00000000 64711da9 00000000 w3dt!UlAtqStartListen+0x2d 0006fcb8 5a3bc259 0100141c 010013e4 010012d0 w3core!W3_SERVER::StartListen+0xbd 0006ff0c 0100187c 00000007 002538e0 00000000 w3core!UlW3Start+0x26e 0006ff44 01001a23 00000007 002538e0 002543d0 w3wp!wmain+0x22a 0006ffc0 77e523cd 00000000 00000000 7ffd7000 w3wp!wmainCRTStartup+0x12b 0006fff0 00000000 010018f8 00000000 78746341 kernel32!BaseProcessStart+0x23 |
Idle w3wp ThreadPoolThread
2 Id: fb8.c5c Suspend: 0 Teb: 7ffd9000 Unfrozen ChildEBP RetAddr Args to Child 00c8ff24 7c821bf4 77e6611a 00000170 00c8ff80 ntdll!KiFastSystemCallRet 00c8ff28 77e6611a 00000170 00c8ff80 00c8ff6c ntdll!NtRemoveIoCompletion+0xc 00c8ff54 5a30249e 00000170 00c8ff7c 00c8ff80 kernel32!GetQueuedCompletionStatus+0x29 00c8ff8c 5a3026bc 00000000 00258580 5a300000 w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x33 00c8ffa0 5a301db9 00000102 00000000 00000000 w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x24 00c8ffb8 77e66063 00258580 00000000 00000000 w3tp!THREAD_MANAGER::ThreadManagerThread+0x39 00c8ffec 00000000 5a301d80 00258580 00000000 kernel32!BaseThreadStart+0x34 |
Idle w3wp Compression Thread
|
7 Id: fb8.b20 Suspend: 0 Teb: 7ffaf000 Unfrozen ChildEBP RetAddr Args to Child 017dfa84 7c822124 77e6baa8 000001d0 00000000 ntdll!KiFastSystemCallRet 017dfa88 77e6baa8 000001d0 00000000 00000000 ntdll!NtWaitForSingleObject+0xc 017dfaf8 77e6ba12 000001d0 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac 017dfb0c 5a3b8147 000001d0 ffffffff 00000000 kernel32!WaitForSingleObject+0x12 017dffb8 77e66063 00000000 00000000 00000000 w3core!HTTP_COMPRESSION::CompressionThread+0x126 017dffec 00000000 5a3b8021 00000000 00000000 kernel32!BaseThreadStart+0x34 |
RPC Threads
놀고 있는 (Idle) LRPC Worker Thread들이 보인다면 이는 프로세스가 좀더 많은 리모트 COM 객체를 활성화 하거나 로컬 또는 리모트 COM method call들을 처리 할 수 있다는 뜻 입니다.
RPC Threading Model에 대해서는 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/scalability.asp 을 참고하세요.
Idle RPC Worker Thread
|
29 Id: fb8.7fc Suspend: 0 Teb: 7ffa1000 Unfrozen ChildEBP RetAddr Args to Child 02ddfeac 7c821bf4 77e6611a 00000078 02ddff04 ntdll!KiFastSystemCallRet 02ddfeb0 77e6611a 00000078 02ddff04 02ddfef4 ntdll!NtRemoveIoCompletion+0xc 02ddfedc 77c604c3 00000078 02ddff14 02ddff04 kernel32!GetQueuedCompletionStatus+0x29 02ddff18 77c60655 ffffffff 02ddff6c 02ddff70 rpcrt4!COMMON_ProcessCalls+0xa1 02ddff84 77c5f9f1 02ddffac 77c5f7dd 00090250 rpcrt4!LOADABLE_TRANSPORT::ProcessIOEvents+0x117 02ddff8c 77c5f7dd 00090250 00000000 00000000 rpcrt4!ProcessIOEventsWrapper+0xd 02ddffac 77c5de88 0008e610 02ddffec 77e66063 rpcrt4!BaseCachedThreadRoutine+0x9d 02ddffb8 77e66063 029515e8 00000000 00000000 rpcrt4!ThreadStartRoutine+0x1b 02ddffec 00000000 77c5de6d 029515e8 00000000 kernel32!BaseThreadStart+0x34 |
Idle LRPC Worker Thread
|
33 Id: fb8.b24 Suspend: 0 Teb: 7ffdb000 Unfrozen ChildEBP RetAddr Args to Child 02e1fe18 7c821c54 77c7538c 00000138 02e1ff74 ntdll!KiFastSystemCallRet 02e1fe1c 77c7538c 00000138 02e1ff74 00000000 ntdll!ZwReplyWaitReceivePortEx+0xc 02e1ff84 77c5778f 02e1ffac 77c5f7dd 0009d660 rpcrt4!LRPC_ADDRESS::ReceiveLotsaCalls+0x198 02e1ff8c 77c5f7dd 0009d660 00000000 00000000 rpcrt4!RecvLotsaCallsWrapper+0xd 02e1ffac 77c5de88 0008e610 02e1ffec 77e66063 rpcrt4!BaseCachedThreadRoutine+0x9d 02e1ffb8 77e66063 05057c08 00000000 00000000 rpcrt4!ThreadStartRoutine+0x1b 02e1ffec 00000000 77c5de6d 05057c08 00000000 kernel32!BaseThreadStart+0x34 |
기타 COM Threads
STA컴퍼넌트(Single threaded component)들은 Main STA Thread에서 처리가 됩니다. Main STA는 최초로 실행된 COM STA Thread가 생성을 하게 되구요.
이전과 마찬 가지로 STA Thread들이 놀고 있다는 얘기는 현재 전달되어 Request가 적거나 없고 앞으로 전달 되는 Request들을 더 많이 처리 할 수 있다는 뜻 입니다.
Host STA Thread
|
31 Id: fb8.b3c Suspend: 0 Teb: 7ff4e000 Unfrozen ChildEBP RetAddr Args to Child 049cff14 7739c78d 7739c7c0 049cff58 00000000 ntdll!KiFastSystemCallRet 049cff34 77694ff1 049cff58 00000000 00000000 user32!NtUserGetMessage+0xc 049cff74 776cf35b 00007530 77e6ba20 02a40fe0 ole32!CDllHost::STAWorkerLoop+0x72 049cff90 776cf2a3 049cffb8 776b2307 77790438 ole32!CDllHost::WorkerThread+0xc8 049cff98 776b2307 77790438 00000000 02a40fe0 ole32!DLLHostThreadEntry+0xd 049cffac 776b2374 00000000 049cffec 77e66063 ole32!CRpcThread::WorkerLoop+0x1e 049cffb8 77e66063 02a40fe0 00000000 00000000 ole32!CRpcThreadCache::RpcWorkerThreadEntry+0x20 049cffec 00000000 776b2354 02a40fe0 00000000 kernel32!BaseThreadStart+0x34 |
Idle STA Thread
|
14 Id: e5c.d90 Suspend: 1 Teb: 7ffac000 Unfrozen ChildEBP RetAddr Args to Child 0140fdcc 77f4372d 77e41bfa 00000003 0140fe1c SharedUserData!SystemCallStub+0x4 0140fdd0 77e41bfa 00000003 0140fe1c 00000001 ntdll!NtWaitForMultipleObjects+0xc 0140fe78 77d076f5 00000003 0140fea0 00000000 kernel32!WaitForMultipleObjectsEx+0x11a 0140fed4 77d077f5 00000002 0140ff74 ffffffff USER32!RealMsgWaitForMultipleObjectsEx+0x13f 0140fef0 7563439d 00000002 0140ff74 00000000 USER32!MsgWaitForMultipleObjects+0x1d 0140ff84 77bc91ed 000b6eb8 00000000 00000000 COMSVCS!CSTAThread::WorkerLoop+0x1e3 0140ffb8 77e4a990 00268a58 00000000 00000000 msvcrt!_threadstartex+0x6f 0140ffec 00000000 77bc917e 00268a58 00000000 kernel32!BaseThreadStart+0x34 |
COM Threading에 대해서는 다음의 URL을 참고 하세요.
COM Threading and Application Architecture in COM+ Applications
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomser/html/comthread.asp
최근 고객사에서 발생한 BizTalk Server 2006 R2(BizTalk Adapter 1.0)과 SAP Server (4.6c) 간의 RFC통신(Inbound) 시에 Table 형 자료의 필드 값이 한글이 지정되는 경우 이상한 Garbage 문자들이 끼여들어서 오류가 발생하는 문제가 접수 되었습니다.
문제가 발생하는 시점에 보면 아래와 같은 오류 메시지가 이벤트에 기록이 되면 Orchestration으로의 자료 전달시 오류가 발생합니다.
3/19/2009 오후 2:27:10 1 1 5815 BizTalk Server 2006 N/A HCIFWEB1
A response message sent to adapter "WCF-Custom" on receive port "ReceivePort_From_SAP_RFC" with URI "sap://Client=XXX;lang=EN;@A/SOME_IP_ADDR/12?ListenerGwHost=SOME_IP_ADDR&ListenerGwServ=SAP_GW_SRV&ListenerProgramId=SAP_BIZTALK" is suspended.
Error details: System.Xml.XmlException: '.', 16진수 값 0x00은(는) 잘못된 문자입니다. 줄 1, 위치 377
위치: Microsoft.BizTalk.Component.XmlAsmStreamWrapper.Read(Byte[] buffer, Int32 offset, Int32 count)
위치: System.Xml.XmlTextReaderImpl.InitStreamInput(Uri baseUri, String baseUriStr, Stream stream, Byte[] bytes, Int32 byteCount, Encoding encoding)
위치: System.Xml.XmlTextReaderImpl..ctor(Stream stream, Byte[] bytes, Int32 byteCount, XmlReaderSettings settings, Uri baseUri, String baseUriStr, XmlParserContext context, Boolean closeInput)
위치: System.Xml.XmlReader.CreateReaderImpl(Stream input, XmlReaderSettings settings, Uri baseUri, String baseUriStr, XmlParserContext inputContext, Boolean closeInput)
위치: System.Xml.XmlReader.Create(Stream input, XmlReaderSettings settings, String baseUri)
위치: System.Xml.XmlReader.Create(Stream input, XmlReaderSettings settings)
위치: Microsoft.BizTalk.Adapter.Wcf.Runtime.BizTalkBodyWriter.WriteBizTalkBody(XmlDictionaryWriter writer)
위치: Microsoft.BizTalk.Adapter.Wcf.Runtime.BizTalkBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
위치: System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
위치: System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer)
위치: System.ServiceModel.Channels.Message.OnGetReaderAtBodyContents()
위치: System.ServiceModel.Channels.Message.GetReaderAtBodyContents()
위치: Microsoft.Adapters.SAP.SAPInboundCountractReply.AdapterReply(Message message, TimeSpan timeout)
위치: Microsoft.Adapters.AdapterUtilities.AdapterInboundReply.Reply(Message message, TimeSpan timeout)
위치: Microsoft.ServiceModel.Channels.Common.Channels.AdapterRequestContext.Reply(Message message, TimeSpan timeout)
위치: Microsoft.ServiceModel.Channels.Common.Channels.AdapterRequestContext.Reply(Message message)
위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.Reply(MessageRpc& rpc) MessageId: {xxxxxxxxx} InstanceID: {YYYYYYYYYY}
문제는 자료를 아래와 같이 필드의 길이에 맞는 ASCII 문자만을 보낼 경우는 문제가 없었습니다. (아래의 Schema는 원래 자료의 내용을 바탕으로 재구성하였으며 SAP 서버에서 실제 생성된 것은 아닙니다.)
<?xml version="1.0" encoding="utf-8"?>
<SAP_Data_Root xmlns="http://Microsoft.LobServices.Sap/2007/03/Rfc/">
<TableDataElement>
<TableData01 xmlns="http://Microsoft.LobServices.Sap/2007/03/Types/Rfc/">
<ProductCode>A100</ProductCode>
<StandardCode>111</StandardCode>
<TransitionType>2</TransitionType>
<ProductName>333</ProductName>
<RealNAME></RealNAME>
<ShippingDate></ShippingDate>
</TableData01>
</TableDataElement>
</SAP_Data_Root>
한글을 포함한 자료를 SAP에서 보내게 되면 아래와 같이 공백과 함께 NULL Entity(�) 가 Field의 길이에 맞게 Padding 되는 듯하면서 추가되고 있는 것을 볼 수 있습니다. 이들 문자에 의해서 XML Validation이 실패하면서 Request를 정상처리하지 못하고 있었습니다.
<?xml version="1.0" encoding="utf-8"?>
<SAP_Data_Root xmlns="http://Microsoft.LobServices.Sap/2007/03/Rfc/">
<TableDataElement>
<TableData01 xmlns="http://Microsoft.LobServices.Sap/2007/03/Types/Rfc/">
<ProductCode>A100</ProductCode>
<StandardCode>111</StandardCode>
<TransitionType>1</TransitionType>
<ProductName>한글 한글 한글 ������</ProductName>
<RealNAME>한글 2 한 ���</RealNAME>
<ShippingDate></ShippingDate>
</TableData01>
</TableDataElement>
</SAP_Data_Root>
관련 문제는 SAP RFC SDK 7.1 UNICODE 를 SAP RFC SDK 7.0 UNICODE로 downgrade 하면서 해결 되었습니다. 아마도 SAP RFC SDK 7.1 UNICODE 버젼에 MBCS 스트링 자료 처리에 문제가 있었을 것으로 보입니다만 정확한 원인 확인은 좀 더 시간일 걸릴 것으로 보입니다.
SAP RFC SDK를 다운로드 하는 방법은 아래의 Blog 글을 참고하세요. 물론 SAP쪽의 지원 계약이 있으셔야 다운로드가 가능합니다.
http://blogs.msdn.com/adapters/archive/2007/10/07/obtaining-the-rfc-sdk-unicode-libraries-from-sap-service-marketplace.aspx
BizTalk Server 설치 이후에 SAP의 TABLE Type이 지원되는 않을 경우, 아래의 KB에서 언급하는 Hotfix를 설치해야 할 수 있습니다.
FIX: The Windows Communication Foundation (WCF) based SAP adapter from BizTalk Server 2006 Adapter Pack v1.0 does not support the SAP TABLE type
http://support.microsoft.com/kb/956635
PDA들은 Windows Mobile(Windows CE라고 불린던) 을 쓴다 치더라도 기능이 좀 어중간한 ARM7 CPU 보드에서 .Net Framework을 쓸 수 있으면 좋겠구나 하는 생각을 왔습니다.
처음 .Net Micro Framework에 대해서 들었을 때는 드디어 그게 가능해 졌구나 하는 생각을 했습니다. 하지만, 좀 자세히 들어가서 보니 조금은 실망스러운 것이 역시나 인증된 (즉, 상대적으로 가격이 비싼) 보드 매이커의 제품만을 사용해야 한다는 것 이었습니다.
얼마전에 출시된 .Net Micro Framework Porting Kit을 이용해서 새로운 플랫폼이나 기존의 플랫폼에 .NetMF의 포팅이 쉬워졌네요.
Getting Started with the Porting Kit
http://blogs.msdn.com/netmfteam/pages/getting-started-with-the-porting-kit.aspx
그런데, 여기에 더 놀라운 것은 기존의 Embedded Software 개발시 구입해야 했던 비싼 개발 도구를 반드시 쓸 필요는 없다는 것 이지요. .NetMF팀에서 GCC로 이미 테스트를 했고 써도 된 답니다.
Update on Using GCC to Port the .NET Micro Framework in .NET Micro Framework Porting
https://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.dotnet.framework.microframework.porting&tid=e6575c5e-f1ce-4bab-897f-96be45b818f9&cat=en_US_38A7B5A8-BCC6-4cc8-BE52-832E765A449B&lang=en&cr=US&sloc=&p=1
In version 3.0, .NET Micro Framework team added support for the Gnu Compiler
Collection (GCC) for evaluation purposes as noted in the documentation. Due
to customer requests, we have reviewed this policy and now fully support the
GCC as a toolchain for porting the .NET Micro Framework. We on the .NET Micro
Framework team wish to thank all of our partners, customers, and enthusiasts
for their feedback, ideas, and input.
Please be aware that it is our experience that using GCC to port the .NET
Micro Framework results in firmware that is larger and slower than the
firmware produced by toolchains such as RVDS or MDK. We have reduced the
memory footprint of the framework in the version 3.0 release to extend the
.NET Micro Framework support for even smaller processors. To get the smallest
and most efficient binaries, we still recommend the use of the ARM or Keil
toolchains.
아래의 링크들을 참고 하시기 바랍니다.
Precompiled GCC Toolchains for the Porting Kit
http://msmicroframework.blogspot.com/2009/02/precompiled-gcc-toolchains-for-porting.html
Configuring Eclipse + OpenOCD + GCC to Debug NativeSample
http://msmicroframework.blogspot.com/2009/02/configuring-eclipse-openocd-gcc-to.html
How to use Eclipse and GDB to debug the .NET Micro Framework
http://discovertheexperience.blogspot.com/2008/11/how-to-use-eclipse-and-gdb-to-debug-net_09.html
Sourcery G++ Lite 2007q3-53 for ARM EABI
http://www.codesourcery.com/sgpp/lite/arm/portal/release316
.NET Micro Framework Porting Kit V3.0 with GCC Support?
http://discovertheexperience.blogspot.com/2008/11/net-micro-framework-porting-kit-v30.html
자주 참고하는 정보들이라 스크랩 을 겸해서 올립니다.
링크에서 Physical Memory관련 설정도 확인 할 수 있습니다.
Memory Limits for Windows Releases
http://msdn.microsoft.com/en-us/library/aa366778(VS.85).aspx
Memory and Address Space Limits
The following table specifies the limits on memory and address space for supported releases of Windows.
| Memory type | Limit in 32-bit Windows | Limit in 64-bit Windows |
| User-mode virtual address space for each 32-bit process | 2 GB Up to 3 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE and 4GT | 2 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE cleared (default) 4 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE set |
| User-mode virtual address space for each 64-bit process | Not applicable | With IMAGE_FILE_LARGE_ADDRESS_AWARE set (default): x64: 8 TB Intel IPF: 7 TB 2 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE cleared |
| Kernel-mode virtual address space | 2 GB From 1 GB to a maximum of 2 GB with 4GT | 8 TB |
| Paged pool | Limited by available kernel-mode virtual address space or the PagedPoolLimit registry key value. Windows Vista: Limited only by kernel mode virtual address space. Starting with Windows Vista with Service Pack 1 (SP1), the paged pool can also be limited by the PagedPoolLimit registry key value. Windows Home Server and Windows Server 2003: 530 MB Windows XP: 490 MB Windows 2000: 350 MB | 128 GB Windows Server 2003 and Windows XP: Up to 128 GB depending on configuration and RAM. Windows 2000: Not applicable |
| Nonpaged pool | Limited by available kernel-mode virtual address space, the NonPagedPoolLimit registry key value, or physical memory. Windows Vista: Limited only by kernel mode virtual address space and physical memory. Starting with Windows Vista with SP1, the nonpaged pool can also be limited by the NonPagedPoolLimit registry key value. Windows Home Server, Windows Server 2003, and Windows XP/2000: 256 MB, or 128 MB with 4GT. | 75% of RAM up to a maximum of 128 GB Windows Vista: 40% of RAM up to a maximum of 128 GB. Windows Server 2003 and Windows XP: Up to 128 GB depending on configuration and RAM. Windows 2000: Not applicable |
| System cache virtual address space (physical size limited only by physical memory) | Limited by available kernel-mode virtual address space or the SystemCacheLimit registry key value. Windows Vista: Limited only by kernel mode virtual address space. Starting with Windows Vista with SP1, system cache virtual address space can also be limited by the SystemCacheLimit registry key value. Windows Home Server, Windows Server 2003, and Windows XP/2000: 860 MB with LargeSystemCache registry key set and without 4GT; up to 448 MB with 4GT. | Always 1 TB regardless of physical RAM Windows Server 2003 and Windows XP: Up to 1 TB depending on configuration and RAM. Windows 2000: Not applicable |
Advances in Memory Management for Windows
http://www.microsoft.com/whdc/system/sysinternals/memmgt.mspx
Dynamic Allocation of Kernel Virtual Address Space
In Windows Vista and later Windows releases, kernel VA space is dynamically allocated. The sizes and locations of important system resources—including the paged and nonpaged memory pools—are no longer fixed, but instead are dynamically adjusted according to operational requirements. As a result, system tuning is automatic. Administrators are not typically required to manually reconfigure systems to prevent resource imbalances.
Figure 2. Kernel Virtual Address Space
기타 메모리 관련 참고 사항 (위 문서에서 언급하고 있는 내용들 입니다) :
MSDN:
Windows Vista ISV Security
http://msdn2.microsoft.com/en-us/library/bb430720.aspx
Memory Management Registry Keys
http://msdn2.microsoft.com/en-us/library/bb870880.aspx
Windows Driver Kit:
http://msdn2.microsoft.com/en-us/library/aa972908.aspx
Kernel-Mode Driver Architecture Design Guide
Memory Management
Interrupt Affinity and Priority
Standard Event Objects
Kernel-Mode Driver Architecture Reference
Standard Driver Routines
Driver Support Routines
Driver Development Tools
Boot Options for Driver Testing and Debugging
Network Design Guide
NDIS MSI-X
Windows Hardware and Driver Central:
Driver Signing Requirements for Windows [home page]
http://www.microsoft.com/whdc/winlogo/drvsign/drvsign.mspx
Digital Signatures for Kernel Modules on Systems Running
Windows Vista
Summary of Windows Kernel-Mode Driver Signing Requirements
Windows PC Accelerators: Performance Technology for Windows Vista
http://www.microsoft.com/whdc/system/sysperf/accelerator.mspx
What Is Really in That MDL?
http://www.microsoft.com/whdc/driver/tips/mdl.mspx
Interrupt Architecture Enhancements in Windows
http://www.microsoft.com/whdc/system/bus/PCI/MSI.mspx
NUMA I/O Optimizations
http://download.microsoft.com/download/a/f/d/afdfd50d-6eb9-425e-84e1-b4085a80e34e/SVR-T332_WH07.pptx
Microsoft TechNet:
Inside the Windows Vista Kernel: Part 3 (April 2007)
http://www.microsoft.com/technet/technetmag/issues/2007/04/VistaKernel/
Book:
Windows Internals, Fourth Edition,
Russinovich, Mark, and David A. Solomon. Redmond, WA: Microsoft Press, 2005
http://www.microsoft.com/MSPress/books/6710.aspx
1. 시작 > 모든 프로그램 > Debug Diagnostics Tool 1.1 > DebugDiag 1.1 (x86) 을 선택하셔서 DebugDiag 1.1 을 실행 하세요.
2. 기본 설정일 경우 아래와 같은 다이얼로그 박스가 기본적으로 표시됩니다. 그렇지 않은 경우 DebugDiag 의 메인 화면에서 “Add Rule” 버튼을 클릭 하시기 바랍니다.
3. Rule Type을 선택하는 화면에서 3번째 형태인 “Memory and Handle Leak”을 선택하시고 “Next”버튼을 클릭 하세요.
4. 현재 버젼에서는 DebugDiag의 LeakTrack Rule 을 이용해서 여러개의 프로세스를 동시에 감시할 수 없습니다. 아래 그림과 같이 현재 실행 중인 프로세스 중에 문제 프로세스를 선택하시고 “Next”를 선택 합니다.
5. 다음 화면에서 아래 그림과 같이 Leak Rule을 설정 합니다. 일단 프로세스에 대한 Leak Rule의 작동과 동시에 Tracking을 시작하도록 하고
6. 원래 10개의 덤프를 수집하도록 한 “Maximum number of userdumps created by this rule”을 적절한 값을 설정해 주시기 바랍니다. 아래 그림에서는 5로 변경해 놓은 상태 입니다.
7. 좀더 자세한 모니터링을 위해서 화면 중간의 “Configure…” 버튼을 클릭 합니다.
8. 새로 표시되는 아래와 같은 다이얼로그 박스 화면에서 “Generate a userdump when virtual bytes reach” 를 설정하세요.
9. 이경우 프로세스의 메모리 사용량이 500메가 바이트가 넘는 시점 부터 덤프를 생성하기 시작합니다. 프로세스 초기 실행시 메모리 사용량에 따라서 이값을 변경해 주시면 됩니다.
즉, 최초 실행 시 Private Bytes가 200메가 바이트라면 이값을 250메가 바이트로 설정해 주시면 메모리 사용량이 증가하기 시작하는 시점에 덤프를 생성하기 시작합니다.
10. LeakTrace은 프로세스 실행시에 메모리나 핸들을 사용하는 콜들을 Hooking해서 관련 Call이 일어나는 Thread의 Stack Trace를 메모리에 저장하게 됩니다. 이들 메모리에 의해서 실제 프로세스에서 나타나는 메모리 문제가 좀더 빨리 진행 될 수도 있으니 유의 하시기 바랍니다.
11. “add each addition ???MB there after” 를 선택 하시면 이후 어느 정도 메모리가 증가할 때 마다 추가적으로 덤프를 수집하도록 할 수 있습니다. 아래 설정에서는 200 메가 바이트가 증가하게 되면 덤프를 수집하도록 해 놨습니다.
12. 만일 Leak과 함께 Crash 현상이 같이 발생하는 경우 “Auto-create a crash rule to get userdump on unexpected process exit.”를 선택 하시면 프로세스 종료시에 덤프가 생성 됩니다. 이는 Hang과 Crash를 동시에 감시하도록 합니다.
13. “Save & Close” 버튼을 클릭하셔서 새로 표시된 다이얼로그 박스를 닫으신 후 “Next” 버튼을 클릭하세요.
14. 다음 화면에서 새로생성된 “Rule”의 이름과 덤프가 저장될 기본 위치를 확인 하세요.
15. “Next” 버튼을 클릭하세요.
16. 마지막으로 “Activate the rule now”를 선택 하셔서 Rule이 바로 모니터링을 시작하도록 하신 후 “Finish” 버튼을 클릭 하세요.
17. 여러개의 프로세스에 대한 LeakTrack을 하고 싶으신 경우 각각의 프로세스에 대해서 별도의 Rule을 추가하시거나 아래 그림과 같이 개별 프로세스에 대한 LeakTrace을 Eanble하시고 메모리 상태를 감시하면서 감시하시면서 Hang Dump를 수집하실 수 있습니다.
* LeakTrack이 Enable된 프로세스는 아래 그림과 같이 “LeakTrack Status” column에 “Tracking”이라고 표시가 됩니다.
Private Bytes와 Virtual Bytes 및 성능모니터로 Leak 을 확인하는 방법은 아래의 링크 내용을 참고하세요.
Using Performance Monitor to Find a User-Mode Memory Leak
http://msdn.microsoft.com/en-us/library/cc267846.aspx
The Private Bytes counter indicates the total amount of memory that a process has allocated, not including memory shared with other processes.
The Virtual Bytes counter indicates the current size of the virtual address space that the process is using.
이 포스트는 아래 블로그 포스팅 내용을 한글화 한 것 입니다.
Identify the version of installed BizTalk
http://blogs.msdn.com/kerreybpi/archive/2009/01/12/identify-the-version-of-installed-biztalk.aspx
현재 서버에서 작동 중인 BizTalk Server의 버젼을 확인을 쉽게 할 수 있는 방법 입니다.
아래그림과 같이 레지스트리 에티터를 여신 후 HKEY_LOCAL_MACHINE -> Software -> Microsoft -> BizTalk Server -> 3.0 아래에 ProductVersion 값을 확인 하시면 됩니다.
위의 값고 아래 테이블을 참고하세요.
| ProductVersion Value | BizTalk Server Version |
| 3.0.4902.0 | BizTalk Server 2004 |
| 3.0.6070.0 | BizTalk Server 2004 SP1 |
| 3.0.7405.0 | BizTalk Server 2004 SP2 |
| 3.5.1602.0 | BizTalk Server 2006 |
| 3.6.1404.0 | BizTalk Server 2006 R2 |
| 3.6.1404.0 보다 큰 경우 | BizTalk Server 2009 |
BizTalk Server 용 응용프로그램을 만들때 일반적으로 File Receive Location(또는 FTP Receive Location)을 이용하게 됩니다.
일단 메시지 파일을 Receive Location에서 설정된 Pickup 폴더에 복사하고 이파일이 없어지는 것을 보고 일단 메시지가 전달된 것으로 생각할 수 있습니다.
문제는 이 파일의 복사본을 유지하고 싶은 경우 현재 BizTalk Server가 지원하지 않는다는 것 입니다. 관련 기능을 원하시는 경우 아래의 CodePlex에서 제공되는 Message Archive Pipeline Component를 사용해 보시기 바랍니다.
대신 소스 코드가 같이 제공이 되고 있기 때문에 관련 Component에 기능추가 역시 가능 합니다. 물론 기능사용 전에 라이센스 역시 주의 해서 읽어 보시기 바랍니다.
BizTalk 2006 Message Archiving Pipeline Component
http://www.codeplex.com/btsmsgarchcomp
위의 URL에서 다운로드 가능한 컴퍼넌트를 BizTalk Server에 설치 하신 후 Receive/Send Pipeline의 Decode stage에 넣어주신 후 관련 컴퍼넌트의 Properties를 설정해 주시면 됩니다.
사용법은 다음과 같습니다.
1. 웹사이트에서 복사하신 파일의 압축을 푸신 후 Modhul.BizTalk.Pipelines.ArchiveMessages.dll 파일을 BizTalk 서버의 설치 폴더내 Pipeline Component 폴더 (일반적으로 C:\Program Files\Microsoft BizTalk Server 2006\Pipeline Components) 에 복사 하세요.

2. Message File의 Archive 기능이 필요한 BizTalk Application Project에서 Receive Pipeline 을 추가하시고 (이미 있는 경우는 다음으로 진행하세요)
3. 파이프 라인 파일을 여신 후 BizTalk Pipeline Components Toolxbox 에서 오른쪽 마우스 버튼을 클릭하셔서 “아이템 선택”을 클릭하시면 아래와 같은 다이얼로그 박스가 나타납니다.
4. 아래 그림과 같이 “BizTalk Pipeline Components” 탭을 선택 하시고 Browser 버튼을 선택하셔서 1번에서 복사한 폴더로 이동 하신 후 컴퍼넌트를 선택하세요.
5. 컴퍼넌트의 선택이 정상적으로 완료되면 아래와 같이 Toolbox 내에 “Archive Messages”라는 컴퍼넌트가 추가 됩니다.
6. 추가된 컴퍼넌트를 선택하신 후 Drag 하셔서 “Decode” stage내의 추가 하시기 바랍니다.
7. 선택된 컴퍼넌트의 설정가능한 속성은 아래와 같습니다. 저장될 폴더 위치와 파일 이름등이 제공되고 있습니다. 기존에 사용 중인 MacroDefinition 파일이 있으시면 File이나 FTP 관련 부분을 추가 하신 후 MacroDefinitionFile Property에 위치를 적어주셔도 됩니다.
좀더 자세한 기능은 Readme.txt파일을 확인하시기 바랍니다.
실제 파일을 저장하는 부분은 “ArchiveMessages.cs” 파일내의 StreamOnReadEvent EnentHandler에서 아래와 같이 코딩되어 있습니다.
private void StreamOnReadEvent(object src, EventArgs args)
{
ReadEventArgs rargs = args as ReadEventArgs;
if (rargs != null)
{
try
{
using (
FileStream FileArchiveStream =
new FileStream(_archiveFilePath, FileMode.Append, FileAccess.Write))
{
using (BinaryWriter FileBinaryWriter = new BinaryWriter(FileArchiveStream))
{
FileBinaryWriter.Write(rargs.buffer, 0, rargs.bytesRead);
// Close the file writer.
FileBinaryWriter.Flush();
FileBinaryWriter.Close();
}
}
}
catch (IOException Ex)
{
...
}
}
else
{
....
}
}
파일이 저장되도록 하기 위한 Event Handler의 등록은 IComponent Interface의 Execute Method를 Implement하는 코드에 나타납니다.
IComponent.Execute Method
http://msdn.microsoft.com/en-us/library/microsoft.biztalk.component.interop.icomponent.execute.aspx
public IBaseMessage Execute(IPipelineContext Context, IBaseMessage InMsg)
{
// Validate the Macro Definition configuration file.
if (ValidationHelper.ValidateMacroDefinitionsXmlConfiguration(_macroDefinitionsFile))
{
// Validate number of macro identifiers.
if ((ValidationHelper.ValidateMacros(InMsg.MessageID, "Archive Directory", _archiveDirectoryMacroPath) &&
(ValidationHelper.ValidateMacros(InMsg.MessageID, "Archive Filename", _archiveFilenameMacroPath))))
{
if (InMsg.BodyPart != null)
{
// Expand macros and build the archive file path.
_archiveFilePath = BuildArchiveFilePath(InMsg);
// Wrap original stream in a Forward Only Event Stream (FOES) and
// configure the read-event.
Stream dataStream = InMsg.BodyPart.GetOriginalDataStream();
CForwardOnlyEventingReadStream eventingStream = new CForwardOnlyEventingReadStream(dataStream);
eventingStream.ReadEvent += new ReadEventHandler(StreamOnReadEvent);
// Assign FOES wrapper back to the BodyPart.
InMsg.BodyPart.Data = eventingStream;
}
}
}
return (InMsg);
}
아래의 블로그 글에 약간의 살을 붙여서 글을 올립니다.
Blocking on sql can occur if the Maximum job history log size is greater than 1000 on the sql server agent
http://blogs.msdn.com/biztalkcpr/archive/2008/05/08/blocking-on-sql-can-occur-if-the-maximum-job-history-log-size-is-greater-than-1000-on-the-sql-server-agent.aspx
위의 글에서 언급하는 것과 같이 특별한 이유 없이 (즉, MessageBox나 DTADB의 크기나 부하에 크게 연관이 없이) 서비스 작동 중 BizTalk 서버의 메시지 전달 속도가 간헐적으로 현저하게 저하되는 문제가 발생하는 경우가 있습니다. 이때 문제 원인 확인을 위해서 SQL Profiler 로그를 확인한 결과 다음의 stored procedure에 의해서 SQL Blocking이 발생하고 있는 경우 아래의 내용을 참고하셔서 SQL Agent Job의 Maximum job history log의 size를 설정해 주시기 바랍니다.
CREATE PROCEDURE sp_jobhistory_row_limiter @job
SELECT @current_rows_per_job = COUNT(*) FROM msdb.dbo.sysjobhistory with (TABLOCKX) WHERE (job_id = @job_id) ...
위의 SP는 MsgBoxPerfCounters_GetPurgeJobInfo SP에 의해서 호출이되며 각각의 BizTalk Agent Job들이 얼마나 호출되었는지를 확인하는 위해서 사용 됩니다.
원본 블로그 글의 경우 이 SP가 만드는 Temp Table의 Row Count가 50000을 넘어가면서 문제가 나타났다고 합니다.
다음 내용은 SQL 2005서버에서의 설정 방법 입니다.
1. BizTalk Server가 사용하는 SQL Server 에서 아래의 그림과 같이 “SQL Server Management Studio”를 실행 하신 후 왼쪽의 Object Explorer에서 “SQL Server Agent”를 선택 하시고 오른쪽 마우스 버튼을 클릭 하신 후 속성창을 실행하세요.
2. 아래의 그림과 같은 SQL Server Agent Properties 창에서 왼쪽 항목의 마지막에 있는 “History” 를 선태하세요.
3. 아래의 그림에서 오른쪽의 붉은 박스 내용과 비교하셔서 “Limit size of history log” 항목을 선택하시고 “Maximum job history rows per job” 항목의 값이 1000을 넘지 않도록 설정해 주시기 바랍니다.

IIS 6.0에서 사용하던 ADSUtil.vbs를 이용하는 방법과 IIS 7.0의 최신 방법을 이용하는 두가지 방법이 있습니다.
1) IIS 7.0 서버에 IIS 6 Management Compatibility 모듈이 설치되어 있는 경우, IIS 6.0에서 사용하던 ADSUTIL.VBS를 이용하는 것과 동일한 방법으로 설정이 가능합니다:
cscript adsutil.vbs set w3svc/NTAuthenticationProviders "Negotiate,NTLM"
2) IIS 6 Management Compatibility 모듈이 설치되어 있지 않은 경우는 appcmd.exe를 이용하셔서 다음과 같이 설정하실 수 있습니다 :
appcmd.exe set config -section:system.webServer/security/authentication/windowsAuthentication /+"providers.[value='Negotiate']" /commit:apphost
appcmd.exe set config -section:system.webServer/security/authentication/windowsAuthentication /+"providers.[value='NTLM']" /commit:apphost
두번째 방법에 대한 설명은 아래의 Technet 자료에서 확인 하실 수 있습니다.
IIS 7.0: Configure Windows Authentication
http://technet.microsoft.com/en-us/library/cc754628.aspx
Tech에서 설명하고 있는 샘플 커맨드 라인에 오류가 있습니다. 제거또는 추가시 반드시 "/" 다음에 -, +를 붙여주셔야 합니다.
추가된 윈도우 인증 방식은 아래 화면과 같이 확인 가능합니다.
appcmd list config /section:windowsAuthentication
IIS 7.0: Appcmd.exe
http://technet.microsoft.com/en-us/library/cc772200.aspx
아래 내용들 역시 참고하시기 바랍니다.
Windows Authentication Providers <providers>
http://www.iis.net/ConfigReference/system.webServer/security/authentication/windowsAuthentication/providers
IIS 6.0에서 Kerberos인증과 NTLM인증을 사용하도록 하는 설정 방법은 아래 KB에 자세하게 나와있습니다.
Windows Server 2003에서 IIS 웹 사이트 인증을 구성하는 방법
http://support.microsoft.com/kb/324274
Kerberos 인증 설정에서 흔히 발생하는 문제의 해결 방법, 확인 사항과 Delegation 설정 관련 방법은 아래의 KB문서를 참고 하세요.
DelegConfig - A Tool To help resolve Kerberos authentication and delegation issues
http://blogs.msdn.com/webtopics/archive/2008/04/25/delegconfig-a-tool-to-help-resolve-kerberos-authentication-and-delegation-issues.aspx
이미 BizTalk 서버를 이용해서 개발하시거나 관리하시는 분들은 잘 아시고 계실 것으로 압니다만 MessageBoxViewer는 BizTalk서버의 실행 상태나 설정등을 한눈에 알아 볼 수 있도록 해주는 훌륭한 도구 입니다.
메시지박스 뷰어는 http://blogs.technet.com/jpierauc/pages/msgboxviewer.aspx 에서 다운로드 하실 수 있습니다.
사용법은 아주 간단합니다. 물론 항상 BizTalk 서버가 실행 중인 시스템에서 실행해 주셔야 합니다.
아래 그림과 같이 압축 파일을 푸신 후 GUI 펄더내의 MsgBoxViewer.exe파일을 실행하시면 됩니다. 만일 GUI Tool을 사용할 수 없는 경우 (화면의 크기등에 의해서) Console 폴더 아래의 BtsDBCollect.exe를 실행하셔도 됩니다.
실행이 되면 나타나는 아래와 같은 화면에서 표시된 "Start to Collect" 버튼을 클릭해 주시고 수집이 완료되면 EXE파일이 있는 폴더에 생성된 HTML 파일을 보내주시면 됩니다. HTML 파일은 UTF-8로 저장이 되어 있습니다. 리포트에서 이상한 메시지가 나타나면 HTML Browser의 Encoding을 변경해 보시기 바랍니다.
실행이 완료되면 아래 그림과 같이 DialogBox가 표시 됩니다.
물론 바로 HTML 리포트를 보셔도 그냥 Cancel 하셔도 됩니다.
대부분의 경우 Default 설정을 따라서 수집하는 것으로 많은 자료가 수집이 됩니다. 하지만 SQL Connection이 늦은 경우나 BizTalk 이 사용하는 DB의 부하등으로 Query의 수행시간이 긴 경우는 별도의 설정을 해 줘야 합니다.
아래 Option 부분만을 확대한 그림을 보시면 일단 BizTalk 서버의 설정을 통해서 DB 서버의 이름과 MgmtDB(Management DB) 정도등이 기본적으로 채워져 있습니다.
일단 초기 실행에서 많은 자료들이 채워지지 않은 경우는 일단 SQL Query Timeout 내지는 WMI Timeout 이 문제가 될 수 있습니다. 기본적으로 30초 정도면 문제가 없겠습니다만 서버의 부하나 DB서버의 문제등으로 인해서 이 값으로는 원하는 결과를 얻을 수 없는 경우가 많습니다.
그럴 경우 이 값을 5분에서 10분 정도로 설정해 주시면 됩니다. Query Timeout의 경우는 300을, WMI Timeout의 경우는 00:05:00으로 설정해 주시면 됩니다.
서버의 부하나 문제 상태 확인은 기본적으로 성능 모니터를 이용하셔도 됩니다만 MessageBox Viewer를 이용하셔서도 비슷한 효과를 볼 수 있습니다. 아래쪽에 보시면 Collect Each "58" Minute(s) 란을 Check 해주시면 됩니다. 다만 10분 이하의 시간은 의미가 없거나 서버에 부하를 줄 수 있습니다. 주의 하셔야 합니다.
최근에 업데이트된 MessageBoxViewer의 기능들의 열람은 아래의 그림과 같은 Optional Queries를 참고해 보시면 됩니다.
BizTalk 서버의 성능이 과도한 Request나 메모리 사용이 아닌 DB 서버단에서 발생하는 Locking등과 같은 문제일 경우 아래의 그림에서 처럼 SP_WHO3를 지원해 주기 때문에 어느 정도 (물론 정확한 타이밍에 수집이 되어야겠지요) 확인이 가능합니다. SQL 서버의 성능과 많이 사용 되는 Query등도 확인이 가능 합니다.
SQL 이외에 눈에 띠는 기능으로 서버에 설치된 BizTalk 관련 Hotfix나 CLR Thread Pool, Registry, BizTalk Configuration 등의 설정 성태를 알려주는 부분과 성능 카운터 및 BizTalk 관련 주요 Event를 알려주는 기능을 지원 합니다.
아래 그림을 보시면 BizTalk 성능 카운터를 통해서 MessageAgent의 성능 문제 발생 시점의 관련 내용을 보여주고 있습니다.
붉게 표시된 부분은 Message Delivery와 Publish관련 Throttling이 발생하고 있는 상황으로 BizTalk의 응답이 현재하게 저하된 상태에서 수집된 자료 입니다.
Throttling의 원인은 프로세스 메모리 상태에 의해서 발생하고 있었습니다.
Host Throttling Performance Counters
http://msdn.microsoft.com/en-us/library/aa578302.aspx
Message delivery throttling state
A flag indicating whether the system is throttling message delivery (affecting XLANG message processing and outbound transports).
- 0: Not throttling
- 1: Throttling due to imbalanced message delivery rate (input rate exceeds output rate)
- 3: Throttling due to high in-process message count
- 4: Throttling due to process memory pressure
- 5: Throttling due to system memory pressure
- 9: Throttling due to high thread count
- 10: Throttling due to user override on delivery
최근 진행된 SCOM/SSRS 관련 Troubleshooting에서 처음으로 64bit Windows 2008에서 작동 중인 IIS 프로세스 디버깅을 시도 해 봤습니다.
물론 Managed ASP.Net 서비스 인 관계로 Psscor2 64bit 버젼으로 분석은 가능 했습니다만 초기에 덤프 수집이 쉽지 않더군요.
우선 문제는
1. DebugDiag를 설치하여 Hang Dump를 시도 하였으나 실패 오류 메시지와 함께 덤프가 생성되지 않았습니다.
2. WinDBG를 이용한 “cscript adplus.vbs –iis –hang”명령이 작동하지 않습니다. 오류 메시지가 뜨네요. 내용은 –iis가 테스트 된 적이 없기 때문에 지원을 하지 않는다는 내용 이었습니다.
할 수 없이 cscript adplus.vbs –hang –pn w3wp.exe 를 통해서 Hang Dump를 시도했고 이부분은 문제가 없이 진행이 가능 했습니다.
Windows 2008, IIS 7.0의 지원시에 Crash 및 Hang dump의 수집을 위해서는 WinDBG와 Process Name 또는 Process ID를 확인하고 덤프를 수집하는 것이 좋을 것으로 보입니다. 물론 좀 있으면 바뀌겠지만요.
또다른 문제로 관련 케이스의 문제 사항이 IIS ApplicationPool의 Non-responsive 상태 였습니다. 즉, IE에서 관련 URL을 열면 모든 Request에 대해서 대기 상태에 빠진다는 것 이었습니다.
특이한 것은 모든 작업 중인 Thread들이 아래와 같은 Stack Trace를 보여 준다는 것이었습니다.
Child-SP RetAddr Call Site
0000000005a3d830 00000642749e9170 DomainNeutralILStubClass.IL_STUB(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
0000000005a3d910 00000642749e9234 System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)
0000000005a3d9a0 0000064274a17eaa System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags)
0000000005a3d9f0 0000064274a4c884 System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)
0000000005a3da80 0000064274a487c3 System.Net.PooledStream.Read(Byte[], Int32, Int32)
0000000005a3dab0 0000064274a7df75 System.Net.Connection.SyncRead(System.Net.HttpWebRequest, Boolean, Boolean)
0000000005a3db50 0000064274a7dfb5 System.Net.HttpWebRequest.EndWriteHeaders(Boolean)
0000000005a3dbb0 0000064274a41072 System.Net.HttpWebRequest.WriteHeadersCallback(System.Net.WebExceptionStatus, System.Net.ConnectStream, Boolean)
0000000005a3dbe0 0000064274a7e1ae System.Net.ConnectStream.WriteHeaders(Boolean)
0000000005a3dc80 0000064274a4a275 System.Net.HttpWebRequest.EndSubmitRequest()
0000000005a3dcd0 0000064274a4ae1a System.Net.Connection.CompleteStartRequest(Boolean, System.Net.HttpWebRequest, System.Net.TriState)
0000000005a3dd30 0000064274a71574 System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest)
0000000005a3ddc0 0000064274a7bc9d System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
0000000005a3de30 0000064274a7f951 System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
0000000005a3de90 000006424ba875ba System.Net.HttpWebRequest.GetResponse()
0000000005a3df20 000006424ba87640 System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(System.Net.WebRequest)
0000000005a3dfb0 0000064280d22f41 System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(System.Net.WebRequest)
0000000005a3dfe0 000006424ba78803 Microsoft.ReportingServices.UI.Global+RSWebServiceWrapper.GetWebResponse(System.Net.WebRequest)
0000000005a3e020 0000064280d21f25 System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(System.String, System.Object[])
0000000005a3e0d0 0000064280d21cb4 Microsoft.SqlServer.ReportingServices2005.ReportingService2005.ListSecureMethods()
0000000005a3e110 0000064280d21aa4 Microsoft.SqlServer.ReportingServices2005.RSConnection.GetSecureMethods()
0000000005a3e180 0000064280d2199d Microsoft.ReportingServices.UI.Global+RSWebServiceWrapper.GetSecureMethods()
0000000005a3e1f0 0000064280d21827 Microsoft.SqlServer.ReportingServices2005.RSConnection.IsSecureMethod(System.String)
0000000005a3e240 0000064280d12334 Microsoft.SqlServer.ReportingServices2005.RSConnection.ValidateConnection()
0000000005a3e2a0 0000064280d12235 Microsoft.ReportingServices.UI.Global.SecureAllAPI()
0000000005a3e2d0 0000064280d11a33 Microsoft.ReportingServices.UI.ReportingPage.EnsureHttpsLevel(Microsoft.ReportingServices.Diagnostics.HttpsLevel)
0000000005a3e310 000006428000a119 Microsoft.ReportingServices.UI.ReportingPage.ReportingPage_Init(System.Object, System.EventArgs)
0000000005a3e430 00000642bc901d50 System.Web.UI.Control.OnInit(System.EventArgs)
0000000005a3e470 00000642bc8d8a88 System.Web.UI.Page.OnInit(System.EventArgs)
0000000005a3e4a0 00000642bc8ffb62 System.Web.UI.Control.InitRecursive(System.Web.UI.Control)
0000000005a3e500 00000642bc900a5b System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0000000005a3e5d0 00000642bc90111b System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0000000005a3e630 00000642bc90190f System.Web.UI.Page.ProcessRequest()
0000000005a3e690 0000064280d11900 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0000000005a3e6f0 00000642bcb2447e ASP.pages_folder_aspx.ProcessRequest(System.Web.HttpContext)
0000000005a3e720 00000642bcb27ba1 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
0000000005a3e7d0 00000642bcb237b5 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
0000000005a3e870 00000642bcb29d36 System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)
0000000005a3e920 00000642bcafbdfa System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
0000000005a3e980 00000642bc92c721 System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
0000000005a3ea10 00000642bc9a4e30 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)
0000000005a3ea50 000006427f67ba32 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
0:028> !do 000000017fcfb278
Name: System.String
MethodTable: 00000642788c1a90
EEClass: 00000642788c1998
Size: 130(0x82) bytes
GC Generation: 1
(C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: http://localhost/ReportServer/ReportService2005.asmx
Fields:
MT Field Offset Type VT Attr Value Name
00000642788ca730 4000096 8 System.Int32 1 instance 53 m_arrayLength
00000642788ca730 4000097 c System.Int32 1 instance 52 m_stringLength
00000642788c4fa8 4000098 10 System.Char 1 instance 68 m_firstChar
00000642788c1a90 4000099 20 System.String 0 shared static Empty
>> Domain:Value 0000000001f27770:0000064278878f28 0000000001fa75a0:0000064278878f28 00000000081b0690:0000064278878f28 0000000001fbccb0:0000064278878f28 <<
000006427890a8e8 400009a 28 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 0000000001f27770:000000015fbf0748 0000000001fa75a0:00000001bfbf09d0 00000000081b0690:00000000ffd35bc8 0000000001fbccb0:000000017fd0eea8 <<
자, 그럼 왜 이 W3WP.EXE는 Request 를 처리하지 못하고 계속 Waiting 상태에 빠졌을까요.
이유는 이렇습니다. ASP.Net 2.0의 경우 1.1과 달리 대부분의 경우 KB821268의 설정을 자동 적으로 설정해 주게되어 있습니다.
아래에 붉게 표시된 줄을 유심히 보시기 바랍니다.
· Set the values of the maxWorkerThreads parameter and the maxIoThreads parameter to 100.
· Set the value of the maxconnection parameter to 12*N (where N is the number of CPUs that you have).
· Set the values of the minFreeThreads parameter to 88*N and the minLocalRequestFreeThreads parameter to76*N.
· Set the value of minWorkerThreads to 50. Remember, minWorkerThreads is not in the configuration file by default. You must add it.
문제 시점에 수집된 덤프에서 아래와 같이 위의 수식을 잘 적용한 내용이 보이네요.
0:000> vertarget
Windows Server 2008/Windows Vista SP1 Version 6001 (Service Pack 1) MP (8 procs) Free x64
Product: LanManNt, suite: Enterprise TerminalServer SingleUserTS
kernel32.dll version: 6.0.6001.18000 (longhorn_rtm.080118-1840)
Machine Name:
Debug session time: Mon Dec 8 17:22:44.000 2008 (GMT+9)
System Uptime: 0 days 2:25:21.165
Process Uptime: 0 days 2:22:45.000
Kernel time: 0 days 0:00:02.000
User time: 0 days 0:00:52.000
0:000> !do 0x00000000ffbf8188
Name: System.Web.RequestQueue
MethodTable: 00000642bcf65d18
EEClass: 00000642bcf65c58
Size: 88(0x58) bytes
GC Generation: 2
(C:\Windows\assembly\GAC_64\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll)
Fields:
MT Field Offset Type VT Attr Value Name
00000642788ca730 4001203 28 System.Int32 1 instance 704 _minExternFreeThreads
00000642788ca730 4001204 2c System.Int32 1 instance 608 _minLocalFreeThreads
00000642788ca730 4001205 30 System.Int32 1 instance 5000 _queueLimit
00000642788e7c68 4001206 40 System.TimeSpan 1 instance 00000000ffbf81c8 _clientConnectedTime
00000642788dca58 4001207 3c System.Boolean 1 instance 1 _iis6
00000642788d5080 4001208 8 ...Collections.Queue 0 instance 00000000ffbf81e0 _localQueue
00000642788d5080 4001209 10 ...Collections.Queue 0 instance 00000000ffbf8338 _externQueue
00000642788ca730 400120a 34 System.Int32 1 instance 25 _count
00000642788f6358 400120b 18 ...ding.WaitCallback 0 instance 00000000ffbf8490 _workItemCallback
00000642788ca730 400120c 38 System.Int32 1 instance 0 _workItemCount
00000642788dca58 400120d 3d System.Boolean 1 instance 0 _draining
00000642788e7c68 400120e 48 System.TimeSpan 1 instance 00000000ffbf81d0 _timerPeriod
00000642788ec7e8 400120f 20 ...m.Threading.Timer 0 instance 00000000ffbf8510 _timer
아래 블로그의 포스팅 내용을 보시면 다음과 같은 내용이 있습니다.
ANSWER: POP QUIZ: What are Free Threads in the Threadpool
http://blogs.msdn.com/tom/archive/2008/07/22/answer-pop-quiz-what-are-free-threads-in-the-threadpool.aspx
So if you have maxWorkerThreads set to 100 on a single processor machine and minFreeThreads set to 88, that means 12 threads can run aspx requests at the same time and 88 threads are available for web service calls, timers, etc.
아래의 ThreadPool의 덤프 내용과 비교해 보면 400 (아마도 50 * CPU) – 704 = -304이 나오게 되죠. 즉, ASPX 페이지를 처리할 수 있는 Thread가 없다는 것 입니다. 그래서 Service Hang이 발생한다는 것 입니다. 아마도 프로세스 갯수가 4개이하 였다면 생기지 않았을 가능성이 높습니다.
0:000> !ThreadPool
Work Request in Queue: 0
--------------------------------------
Number of Timers: 28
--------------------------------------
CPU utilization 1%
--------------------------------------
Worker Thread: Total: 9 Running: 8 Idle: 1 MaxLimit: 400 MinLimit: 4
Completion Port Thread:Total: 1 Free: 1 MaxFree: 16 CurrentLimit: 0 MaxLimit: 400 MinLimit: 4
이 문제를 해결하기 위해서는 과감하게 .Net Framework 2.0의 Auto 설정을 깨고 메뉴얼로 설정을 바꿔야 합니다.
일반적으로 C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG 폴더 아래에 있는 machine.config 와 web.config의 설정을 아래와 같이 변경해 주시면 됩니다.
- Machine.config 에서
<processModel autoConfig="true"/> 를 찾으신 후 아래의 라인으로 변경 합니다.
<processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50"/>
- 같은 폴더 아래의 web.config 파일을 여신 후 아래의 내용을 <system.web> configuration section 아래에 추가 합니다.
<httpRuntime minFreeThreads="352" minLocalRequestFreeThreads="304" appRequestQueueLimit="5000"/>
아래의 URL들을 참고하세요.
Chapter 17 — Tuning .NET Application Performance
http://msdn.microsoft.com/en-us/library/ms998583.aspx
Contention, poor performance, and deadlocks when you make Web service requests from ASP.NET applications
http://support.microsoft.com/kb/821268/en-us
Support WebCast: Microsoft ASP.NET Threading
http://support.microsoft.com/default.aspx?scid=/servicedesks/webcasts/en/transcripts/wct060503.asp
http://support.microsoft.com/default.aspx?scid=kb;en-us;820913
ASP.NET Thread Usage on IIS 7.0 and 6.0
http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
Identifying Performance Bottlenecks
http://msdn.microsoft.com/en-us/library/aa578679.aspx
Threads, DB sessions, and throttling
http://biztalkperformance.members.winisp.net/BlogPages/MaxWorkerThreads.htm
The number of running orchestrations increases and then remains constant after you reach the thread pool limit, and orchestration execution time may increase in BizTalk Server
http://support.microsoft.com/kb/900455
Configuration Parameters that Affect Adapter Performance
http://msdn.microsoft.com/en-us/library/aa561380.aspx
Suspended Messages are Included in the Message Count in Database Throttling Threshold
http://msdn.microsoft.com/en-us/library/aa577623.aspx
MSBTS_HostSetting.ProcessMemoryThreshold Property (WMI)
http://msdn.microsoft.com/en-us/library/aa559112.aspx
How to Configure the DTA Purge and Archive Job
http://msdn.microsoft.com/en-us/library/aa558715.aspx
BizTalk Server로 서비스를 진행하는 사이트에서 갑작스럽게 서비스의 속도가 떨어지거나 오류 발생이 늘어나는 경우 가장 우선 적으로 성능 모니터 (Performance Monitor)를 통해서 기본적으로 확인할 부분이 있습니다.
우선 서버에 전달되고 처리되는 요청의 전반적인 현황을 확인하기 위해서는 아래와 같은 모니터 객체를 성능모니터에 추가하셔서 관측 하시면 됩니다.
아래 카운터를 이용하시면 서버에 전달되고 처리되는 요청의 흐름을 확인 하실 수 있습니다.
서비스에서 Orchestration의 처리량을 확인하기 위해서는 "XLANG/s Operations" 객체에서 "Orchestrations completed/sec" 카운터를 추가하시면 초당 처리되는 Orchestration의 갯수를 확인하실 수 있습니다.
초당처리되는 절대량이라기 보다는 전체적인 비율(Ratio)가 맞을거 같습니다. 따라서 증/가감에 따라서 서버의 Orchestration 처리에 문제가 있음을 확인 할 수 있습니다.
판별하기 힘든 이유로 서버의 응답이 느려지는 경우 Throttling 카운터 들을 확인해 보시는 것도 좋겠습니다.
Throttling State 카운터는 "Message delivery", "Message publishing"과 "Process memory usage throttling"의 3가지가 있습니다.
자세한 정보는 MSDN 문서 (http://msdn.microsoft.com/en-us/library/aa561922.aspx) 를 참고하세요.
BizTalk Application Counters
| Object | Instance | Counter | Description |
| BizTalk Messaging | RxHost | Documents Received/Sec | BizTalk에 전달되는 요청의 초당 갯수 |
| BizTalk Messaging | TxHost | Documents Processed/Sec | BizTalk에 처리되는 요청의 초당 갯수 |
| XLANG/s Orchestrations | PxHost | Orchestrations Completed/Sec. | Orchestration의 처리 비율 (초당) |
| BizTalk : MessageBox: General Counters | MsgBoxName | Spool Size | Cumulative size of all Host Queues |
| BizTalk : MessageBox: General Counters | MsgBoxName | Tracking Data Size | Size of TrackingData table on the MessageBox |
| BizTalk:MessageBox:Host Counters | PxHost:MsgBoxName | Host Queue - Length | 특정 Host Queue의 길이 (즉, 요청 갯수). 길이가 길어지면 처리 지연이 의심 됩니다. |
| BizTalk:MessageBox:Host Counters | TxHost:MsgBoxName | Host Queue - Length | Number of messages in the specific Host Queue |
| BizTalk:Message Agent | RxHost | Database Size | Size of publishing (PxHost) Queue |
| BizTalk:Message Agent | PxHost | Database Size | Size of publishing (TxHost) Queue |
| BizTalk:Message Agent | HostName | Message Delivery Throttling State | Affects XLANG and Outbound transports |
| BizTalk:Message Agent | HostName | Message Publishing Throttling State | Affects XLANG and Inbound transports |