Welcome to MSDN Blogs Sign in | Join | Help

Yong Hee Park's Blog

Developer Support Engineer for Internet [MSFT]

Syndication

.Net Framework 2.0, ASP.Net, COM+ & machine.config

 

최근에 진행된 지원 케이스에서 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

 

 

Attribute

Description

autoConfig

    Specifies whether to automatically configure the following settings to achieve optimal performance based on the machine configuration:

  • The maxWorkerThreads attribute.

  • The maxIoThreads attribute.

  • The minFreeThreads attribute of the httpRuntime element.

  • The minLocalRequestFreeThreads attribute of the httpRuntime element.

  • The maxConnection attribute of the <connectionManagement> Element (Network Settings) element.

    The values are set according to the KB article at http://support.microsoft.com/?id=821268.

    This attribute does not affect the .NET Framework client applications; only ASP.NET applications.

    The autoConfig attribute can be one of the following values.

    Term Definition

    True Indicates that ASP.NET automatically configures the attributes in the preceding list to achieve optimal performance based on the machine configuration.

    False Indicates that ASP.NET should use the explicitly defined values for the attributes in the preceding list.

    The default in the Machine.config file is True, unless there is a previously existing configuration.

 

 

이 포스팅에서 설명하는 문제는 machine.config (또는 DLLHOST.EXE.CONFIG ) 설정을 변경 후 KB821268에서 언급하고 있는 시스템 가이드를 참조하여 변경 한 이후 해결이 되었습니다.

 

이외 비슷하게 ASP.Net 이외에 별도의 프로세스에서 Network에 접근하여 자료를 수집/분석/제공하는 서비스를 이용하는 경우 성능 조정을 위한 파라미터를 설정해 주셔야 합니다.

Posted Wednesday, July 15, 2009 7:08 PM by Yong Hee Park | 0 Comments

ASP.Net 2.0 (Whidbey) 에서 Hang Dump 분석

이전 포스팅에서 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를 보죠.

Idle CLR Worker Thread

16 Id: efc.a00 Suspend: 1 Teb: fff88000 Unfrozen
ChildEBP RetAddr Args to Child
0219fc84 7d4d8c56 00000228 00000000 0219fcc8 ntdll!ZwWaitForSingleObject+0x15
0219fcf4 79e718fd 00000228 00009c40 00000000 kernel32!WaitForSingleObjectEx+0xac
0219fd38 79e718c6 00000228 00009c40 00000000 mscorwks!PEImage::LoadImage+0x199
0219fd88 79e7187c 00009c40 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
0219fd98 79f5e51b 00009c40 00000000 00000000 mscorwks!CLREvent::Wait+0x17
0219fe18 79f8b1c5 001880e0 00009c40 00000000 mscorwks!ThreadpoolMgr::SafeWait+0x73
0219fe94 79f7997f 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::WorkerThreadStart+0xf5
0219ffb8 7d4dfff1 0019c440 00000000 00000000 mscorwks!ThreadpoolMgr::intermediateThreadProc+0x49
0219ffec 00000000 79f79939 0019c440 00000000 kernel32!BaseThreadStart+0x34
 
혹시 이전 번젼과 차이가 느껴지시나요? 참고를 위해서 이전 버젼의 CLR Worker Thread의 Stack Trace를 비교해 보시죠.
이전 포스팅에서 잠시 언급을 했습니다만, .Net Framework 1.1은 GC Version이 서로 많이 다르고
서버 프로세스와 일반 클라이언트 프로세스에 로딩 되는 DLL 역시 바뀝니다.
 
ASP.Net 2.0에서는 서버 프로세스에서도 mscrowks (Workstation version)이 올라가고 있다는 뜻일까요? 그렇지는 않습니다.
이는 현재 구현상 이름이 남아 있는 것 뿐이 실행시 모양은 차이가 있습니다.
아래 GC Thread 부분을 참고하세요.
 

Idle CLR WorkerThread for ASP.Net 1.1

  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
14 Id: efc.11c8 Suspend: 1 Teb: fff8e000 Unfrozen
ChildEBP RetAddr Args to Child
0209fe7c 7d50664c 00000234 0209fee8 0209fec0 ntdll!NtRemoveIoCompletion+0x15
0209fea8 79f795de 00000234 0209feec 0209fee8 kernel32!GetQueuedCompletionStatus+0x29
0209ff14 79f7997f 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::CompletionPortThreadStart+0x11a
0209ffb8 7d4dfff1 0019c440 00000000 00000000 mscorwks!ThreadpoolMgr::intermediateThreadProc+0x49
0209ffec 00000000 79f79939 0019c440 00000000 kernel32!BaseThreadStart+0x34
 

 

Idle CLR Gate Thread

15 Id: efc.1534 Suspend: 1 Teb: fff8b000 Unfrozen
ChildEBP RetAddr Args to Child
0211fe18 7d4d0ec5 00000000 0211fe58 00000000 ntdll!ZwDelayExecution+0x15
0211fe80 79f56b45 000001f4 00000000 fcffff56 kernel32!SleepEx+0x68
0211feb4 79f56b15 000001f4 00000000 fcffff0a mscorwks!EESleepEx+0xa3
0211fee8 79f405ed 000001f4 00000000 79f569e7 mscorwks!__DangerousSwitchToThread+0x70
0211fef4 79f569e7 000001f4 9e2c9368 000003f4 mscorwks!__SwitchToThread+0xb
0211ffb8 7d4dfff1 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::GateThreadStart+0xa1
0211ffec 00000000 79f56952 00000000 00000000 kernel32!BaseThreadStart+0x34
 

위에서 언급했던 Server GC와 Workstation GC의 차이는 아래의 Stack Trace에서 차이가 납니다.

 

Idle GC Thread

18 Id: efc.12b8 Suspend: 1 Teb: fff82000 Unfrozen
ChildEBP RetAddr Args to Child
0257fe6c 7d4d8c56 000002dc 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15
0257fedc 79e718fd 000002dc ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
0257ff20 79e718c6 000002dc ffffffff 00000000 mscorwks!PEImage::LoadImage+0x199
0257ff70 79e7187c ffffffff 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
0257ff80 7a0d6f16 ffffffff 00000000 00000000 mscorwks!CLREvent::Wait+0x17
0257ffa8 7a0d722e 00000000 fcb9fe5a 0257ffec mscorwks!SVR::gc_heap::gc_thread_function+0x2f
0257ffb8 7d4dfff1 001b20e8 00000000 00000000 mscorwks!SVR::gc_heap::gc_thread_stub+0x9b

0257ffec 00000000 7a0d7192 001b20e8 00000000 kernel32!BaseThreadStart+0x34
 
아래의 Stack Trace는 Client Application 상에서 실행되고 있는 GC Thread의 Snapshot 입니다,.
특히, 붉게 표시된 부분은 GC가 위의 Thread와 달리 열심히 살아 있는 (즉, 사용되고 있는) 객체를 표시하고 있는 중이라는 것을 보실 수 있습니다.
위의 내용과 비교해 보시면 mscorwks!SVR이 아니네요.
 

ChildEBP RetAddr
0776fa8c 68d05dda mscorwks!WKS::gc_heap::mark_object_simple1+0x148
0776fab8 68c9f515 mscorwks!WKS::gc_heap::mark_object_simple+0x19d
0776faec 68c9efc1 mscorwks!WKS::gc_heap::c_drain_mark_list+0x95
0776fb18 68c9f9b3 mscorwks!WKS::gc_heap::c_mark_phase+0xaa

0776fb34 68d0ed65 mscorwks!WKS::gc_heap::gc1+0x59
0776fb4c 68d0edb7 mscorwks!WKS::gc_heap::gc_thread_function+0x9f
0776fb54 75e04911 mscorwks!WKS::gc_heap::gc_thread_stub+0x73

0776fb60 76e3e4b6 KERNEL32!BaseThreadInitThunk+0xe
0776fba0 76e3e489 ntdll!__RtlUserThreadStart+0x23
0776fbb8 00000000 ntdll!_RtlUserThreadStart+0x1b

 

Idle Finalizer Thread

GC와 떨어져서 언급 할 수 없는 Finalizer의 경우도 역시 마찬가지 입니다.

 

20 Id: efc.132c Suspend: 1 Teb: fff7c000 Unfrozen
ChildEBP RetAddr Args to Child
0267fcd0 7d4e1cda 00000002 0267fd1c 00000001 ntdll!NtWaitForMultipleObjects+0x15
0267fd78 7d4e3e16 00000002 7a398698 00000000 kernel32!WaitForMultipleObjectsEx+0x11a
0267fd94 7a0849d8 00000002 7a398698 00000000 kernel32!WaitForMultipleObjects+0x18
0267fdb4 7a085307 001b0c60 0267fe6c 0267feb4 mscorwks!SVR::WaitForFinalizerEvent+0x7a
0267fdc8 79ed890c 0267feb4 00000000 00000001 mscorwks!SVR::GCHeap::FinalizerThreadWorker+0x75
0267fdd8 79ed88aa 0267feb4 0267fe60 79f54f64 mscorwks!Thread::UserResumeThread+0xfb
0267fe6c 79ed87d1 0267feb4 fc89ff4a 00000000 mscorwks!Thread::DoADCallBack+0x355
0267fea8 79ed976c 0267feb4 00000000 001cad20 mscorwks!Thread::DoADCallBack+0x541
0267fed0 79ed9737 7a085292 00000008 7a0854b0 mscorwks!ManagedThreadBase_NoADTransition+0x32
0267fedc 7a0854b0 7a085292 fc89fef6 00000000 mscorwks!ManagedThreadBase::FinalizerBase+0xb
0267ff14 79ed8d16 00000000 00000000 00000000 mscorwks!SVR::GCHeap::FinalizerThreadStart+0xbb
0267ffb8 7d4dfff1 001b0ca8 00000000 00000000 mscorwks!Thread::intermediateThreadProc+0x49
0267ffec 00000000 79ed8cd0 001b0ca8 00000000 kernel32!BaseThreadStart+0x34
 

Idle CLR Debugger Thread

17 Id: efc.1964 Suspend: 1 Teb: fff85000 Unfrozen
ChildEBP RetAddr Args to Child
022cfe34 7d4e1cda 00000003 022cfe80 00000001 ntdll!NtWaitForMultipleObjects+0x15
022cfedc 7d4e3e16 00000003 022cff20 00000000 kernel32!WaitForMultipleObjectsEx+0x11a
022cfef8 79f0cb1e 00000003 022cff20 00000000 kernel32!WaitForMultipleObjects+0x18
022cff58 79f0ca7b fcc2fe6a 00000000 00000000 mscorwks!DebuggerRCThread::MainLoop+0xcf
022cff88 79f0c9be fcc2fe5a 00000000 00000000 mscorwks!DebuggerRCThread::ThreadProc+0xca
022cffb8 7d4dfff1 00000000 00000000 00000000 mscorwks!DebuggerRCThread::ThreadProcStatic+0x82
022cffec 00000000 79f0c978 00000000 00000000 kernel32!BaseThreadStart+0x34
 

Idle Timer Thread

22 Id: efc.136c Suspend: 1 Teb: fff76000 Unfrozen
ChildEBP RetAddr Args to Child
0284fecc 7d4d0ec5 00000001 0284ff0c 00000000 ntdll!ZwDelayExecution+0x15
0284ff34 79f667c7 00002710 00000001 0284ffa4 kernel32!SleepEx+0x68
0284ffb0 79f66758 00000000 7d4dfff1 0219e75c mscorwks!ThreadpoolMgr::TimerThreadFire+0x6d
0284ffb8 7d4dfff1 0219e75c 00000000 00000000 mscorwks!ThreadpoolMgr::TimerThreadStart+0x54
0284ffec 00000000 79f66702 0219e75c 00000000 kernel32!BaseThreadStart+0x34
 

Idle Appdomain Unload Thread

21 Id: efc.12d8 Suspend: 1 Teb: fff79000 Unfrozen
ChildEBP RetAddr Args to Child
0275fcbc 7d4d8c56 000002d0 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15
0275fd2c 79e718fd 000002d0 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
0275fd70 79e718c6 000002d0 ffffffff 00000000 mscorwks!PEImage::LoadImage+0x199
0275fdc0 79e7187c ffffffff 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
0275fdd0 79f78d81 ffffffff 00000000 00000000 mscorwks!CLREvent::Wait+0x17
0275fe94 79ed8d16 001babd0 00000000 00000000 mscorwks!AppDomain::ADUnloadThreadStart+0x2fb
0275ffb8 7d4dfff1 001b8670 00000000 00000000 mscorwks!Thread::intermediateThreadProc+0x49
0275ffec 00000000 79ed8cd0 001b8670 00000000 kernel32!BaseThreadStart+0x34
 
이전에는 없던 AppDomain Unload Thread라는 것이 생겼는데요. 관련 설명은 다음의 MSDN URL을 참고하세요.
 
AppDomain.Unload 메서드
http://msdn.microsoft.com/ko-kr/library/system.appdomain.unload.aspx
 

설명

.NET Framework 버전 2.0에는 응용 프로그램 도메인 언로드 전용 스레드가 있습니다. 이 스레드를 사용하면 특히 .NET Framework이 호스팅된 경우 안전성이 향상됩니다. 스레드가 Unload를 호출하면 대상 도메인이 언로드되도록 표시됩니다. 그러면 전용 스레드가 도메인의 언로드를 시도하고 도메인의 모든 스레드가 중단됩니다. 스레드가 비관리 코드를 실행하거나 finally 블록을 실행하고 있는 등의 이유로 중단되지 않는 경우 일정한 시간이 지난 후 원래 Unload를 호출한 스레드에서 CannotUnloadAppDomainException이 throw됩니다. 중단할 수 없는 스레드가 결국 종료되면 대상 도메인은 언로드되지 않습니다. 따라서 .NET Framework 버전 2.0에서는 실행 중인 스레드를 종료시키지 못할 수 있으므로 domain이 언로드되지 않을 수도 있습니다.

 

Posted Friday, April 17, 2009 4:16 PM by Yong Hee Park | 1 Comments

ASP.Net 2.0 이전 버젼에서 Hang Dump 분석시 참고 내용

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

Posted Friday, April 17, 2009 2:43 PM by Yong Hee Park | 1 Comments

BizTalk Adapter Pack 1.0과 SAP Server 4.6c간의 RFC 통신시 XML Validation Error

최근 고객사에서 발생한 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(&#x0;) 가 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>한글 한글 한글                                                        &#x0;&#x0;&#x0;&#x0;&#x0;&#x0;</ProductName>
      <RealNAME>한글 2 한                     &#x0;&#x0;&#x0;</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

Posted Monday, April 06, 2009 5:12 PM by Yong Hee Park | 1 Comments

Microsoft .NET Micro Framework (NETMF) Porting Kit 3.0

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

 

Posted Friday, March 27, 2009 2:11 AM by Yong Hee Park | 1 Comments

Windows 버젼별 메모리 관련 설정들 및 링크들

자주 참고하는 정보들이라 스크랩 을 겸해서 올립니다.

링크에서 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.

image

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

Posted Friday, March 13, 2009 4:33 PM by Yong Hee Park | 1 Comments

DebugDiag 1.1에서 LeakTrack을 이용하여 Memory 와 Handle 관련 Leak 확인을 위한 덤프 생성 방법

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”버튼을 클릭 하세요.

clip_image002

4. 현재 버젼에서는 DebugDiag의 LeakTrack Rule 을 이용해서 여러개의 프로세스를 동시에 감시할 수 없습니다. 아래 그림과 같이 현재 실행 중인 프로세스 중에 문제 프로세스를 선택하시고 “Next”를 선택 합니다.

clip_image004

5. 다음 화면에서 아래 그림과 같이 Leak Rule을 설정 합니다. 일단 프로세스에 대한 Leak Rule의 작동과 동시에 Tracking을 시작하도록 하고

6. 원래 10개의 덤프를 수집하도록 한 “Maximum number of userdumps created by this rule”을 적절한 값을 설정해 주시기 바랍니다. 아래 그림에서는 5로 변경해 놓은 상태 입니다.

7. 좀더 자세한 모니터링을 위해서 화면 중간의 “Configure…” 버튼을 클릭 합니다.

clip_image006

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” 버튼을 클릭하세요.

clip_image008

14. 다음 화면에서 새로생성된 “Rule”의 이름과 덤프가 저장될 기본 위치를 확인 하세요.

15. “Next” 버튼을 클릭하세요.

clip_image010

16. 마지막으로 “Activate the rule now”를 선택 하셔서 Rule이 바로 모니터링을 시작하도록 하신 후 “Finish” 버튼을 클릭 하세요.

clip_image012

 

17. 여러개의 프로세스에 대한 LeakTrack을 하고 싶으신 경우 각각의 프로세스에 대해서 별도의 Rule을 추가하시거나 아래 그림과 같이 개별 프로세스에 대한 LeakTrace을 Eanble하시고 메모리 상태를 감시하면서 감시하시면서 Hang Dump를 수집하실 수 있습니다.

* LeakTrack이 Enable된 프로세스는 아래 그림과 같이 “LeakTrack Status” column에 “Tracking”이라고 표시가 됩니다.

clip_image014

 

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.

Posted Friday, March 13, 2009 3:47 PM by Yong Hee Park | 1 Comments

Registry를 이용한 BizTalk Server Version 확인 방법

이 포스트는 아래 블로그 포스팅 내용을 한글화 한 것 입니다.

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 값을 확인 하시면 됩니다.

image

 

위의 값고 아래 테이블을 참고하세요.

 

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

Posted Wednesday, February 04, 2009 5:54 PM by Yong Hee Park | 0 Comments

Pickup 폴더내 파일의 복사본을 유지하는 방법

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) 에 복사 하세요.

 

clip_image002

 

2. Message File의 Archive 기능이 필요한 BizTalk Application Project에서 Receive Pipeline 을 추가하시고 (이미 있는 경우는 다음으로 진행하세요)

 

3. 파이프 라인 파일을 여신 후 BizTalk Pipeline Components Toolxbox 에서 오른쪽 마우스 버튼을 클릭하셔서 “아이템 선택”을 클릭하시면 아래와 같은 다이얼로그 박스가 나타납니다.

 

4. 아래 그림과 같이 “BizTalk Pipeline Components” 탭을 선택 하시고 Browser 버튼을 선택하셔서 1번에서 복사한 폴더로 이동 하신 후 컴퍼넌트를 선택하세요.

 

clip_image004

 

5. 컴퍼넌트의 선택이 정상적으로 완료되면 아래와 같이 Toolbox 내에 “Archive Messages”라는 컴퍼넌트가 추가 됩니다.

 

clip_image006

 

6. 추가된 컴퍼넌트를 선택하신 후 Drag 하셔서 “Decode” stage내의 추가 하시기 바랍니다.

 

clip_image008

 

7. 선택된 컴퍼넌트의 설정가능한 속성은 아래와 같습니다. 저장될 폴더 위치와 파일 이름등이 제공되고 있습니다. 기존에 사용 중인 MacroDefinition 파일이 있으시면 File이나 FTP 관련 부분을 추가 하신 후 MacroDefinitionFile Property에 위치를 적어주셔도 됩니다.

 

clip_image010

 

좀더 자세한 기능은 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);
}

Posted Tuesday, February 03, 2009 5:11 PM by Yong Hee Park | 1 Comments

Maximum job history Log의 크기로 SQL Blocking이 발생할 수 있다.

아래의 블로그 글에 약간의 살을 붙여서 글을 올립니다.

 

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”를 선택 하시고 오른쪽 마우스 버튼을 클릭 하신 후 속성창을 실행하세요.

 

clip_image002

 

2. 아래의 그림과 같은 SQL Server Agent Properties 창에서 왼쪽 항목의 마지막에 있는 “History” 를 선태하세요.

3. 아래의 그림에서 오른쪽의 붉은 박스 내용과 비교하셔서 “Limit size of history log” 항목을 선택하시고 “Maximum job history rows per job” 항목의 값이 1000을 넘지 않도록 설정해 주시기 바랍니다.

clip_image004

Posted Tuesday, February 03, 2009 4:48 PM by Yong Hee Park | 1 Comments

IIS 7.0 : 윈도우 인증 방법으로 Negotiate및 NTLM을 지원하도록 설정하는 방법

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

 

image

 

image

Tech에서 설명하고 있는 샘플 커맨드 라인에 오류가 있습니다. 제거또는 추가시 반드시 "/" 다음에 -, +를 붙여주셔야 합니다.

 

image

추가된 윈도우 인증 방식은 아래 화면과 같이 확인 가능합니다.

appcmd list config /section:windowsAuthentication

image

 

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

 

Posted Friday, January 30, 2009 4:35 PM by Yong Hee Park | 1 Comments

BizTalk 서버의 설정과 상태 확인을 위한 도구 (MessageBox Viewer)

이미 BizTalk 서버를 이용해서 개발하시거나 관리하시는 분들은 잘 아시고 계실 것으로 압니다만 MessageBoxViewer는 BizTalk서버의 실행 상태나 설정등을 한눈에 알아 볼 수 있도록 해주는 훌륭한 도구 입니다.

 

메시지박스 뷰어는 http://blogs.technet.com/jpierauc/pages/msgboxviewer.aspx 에서 다운로드 하실 수 있습니다.

 

사용법은 아주 간단합니다. 물론 항상 BizTalk 서버가 실행 중인 시스템에서 실행해 주셔야 합니다.

 

아래 그림과 같이 압축 파일을 푸신 후 GUI 펄더내의 MsgBoxViewer.exe파일을 실행하시면 됩니다. 만일 GUI Tool을 사용할 수 없는 경우 (화면의 크기등에 의해서) Console 폴더 아래의 BtsDBCollect.exe를 실행하셔도 됩니다.

 

clip_image001

 

실행이 되면 나타나는 아래와 같은 화면에서 표시된 "Start to Collect" 버튼을 클릭해 주시고 수집이 완료되면 EXE파일이 있는 폴더에 생성된 HTML 파일을 보내주시면 됩니다. HTML 파일은 UTF-8로 저장이 되어 있습니다. 리포트에서 이상한 메시지가 나타나면 HTML Browser의 Encoding을 변경해 보시기 바랍니다.

 

clip_image003

 

실행이 완료되면 아래 그림과 같이 DialogBox가 표시 됩니다.

image

 

물론 바로 HTML 리포트를 보셔도 그냥 Cancel 하셔도 됩니다.

image

 

대부분의 경우 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분 이하의 시간은 의미가 없거나 서버에 부하를 줄 수 있습니다. 주의 하셔야 합니다.

 

image

 

최근에 업데이트된 MessageBoxViewer의 기능들의 열람은 아래의 그림과 같은 Optional Queries를 참고해 보시면 됩니다.

BizTalk 서버의 성능이 과도한 Request나 메모리 사용이 아닌 DB 서버단에서 발생하는 Locking등과 같은 문제일 경우 아래의 그림에서 처럼 SP_WHO3를 지원해 주기 때문에 어느 정도 (물론 정확한 타이밍에 수집이 되어야겠지요) 확인이 가능합니다. SQL 서버의 성능과 많이 사용 되는 Query등도 확인이 가능 합니다.

 

image

 

SQL 이외에 눈에 띠는 기능으로 서버에 설치된 BizTalk 관련 Hotfix나 CLR Thread Pool, Registry, BizTalk Configuration 등의 설정 성태를 알려주는 부분과 성능 카운터 및 BizTalk 관련 주요 Event를 알려주는 기능을 지원 합니다.

 

image

 

아래 그림을 보시면 BizTalk 성능 카운터를 통해서 MessageAgent의 성능 문제 발생 시점의 관련 내용을 보여주고 있습니다.

붉게 표시된 부분은 Message Delivery와 Publish관련 Throttling이 발생하고 있는 상황으로 BizTalk의 응답이 현재하게 저하된 상태에서 수집된 자료 입니다.

Throttling의 원인은 프로세스 메모리 상태에 의해서 발생하고 있었습니다.

 

image

 

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

Posted Tuesday, December 30, 2008 2:36 PM by Yong Hee Park | 1 Comments

IIS 7.0, DebugDiag, WinDBG & .Net Framework

최근 진행된 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

clip_image001

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

Posted Thursday, December 11, 2008 3:16 PM by Yong Hee Park | 0 Comments

List of URLs related to the BizTalk Performance Issues

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

Posted Friday, December 05, 2008 6:09 PM by Yong Hee Park | 0 Comments

BizTalk의 성능관련 카운터들

BizTalk Server로 서비스를 진행하는 사이트에서 갑작스럽게 서비스의 속도가 떨어지거나 오류 발생이 늘어나는 경우 가장 우선 적으로 성능 모니터 (Performance Monitor)를 통해서 기본적으로 확인할 부분이 있습니다.

 

우선 서버에 전달되고 처리되는 요청의 전반적인 현황을 확인하기 위해서는 아래와 같은 모니터 객체를 성능모니터에 추가하셔서 관측 하시면 됩니다.

아래 카운터를 이용하시면 서버에 전달되고 처리되는 요청의 흐름을 확인 하실 수 있습니다.

 

image

 

서비스에서 Orchestration의 처리량을 확인하기 위해서는 "XLANG/s Operations" 객체에서 "Orchestrations completed/sec" 카운터를 추가하시면 초당 처리되는 Orchestration의 갯수를 확인하실 수 있습니다.

 

초당처리되는 절대량이라기 보다는 전체적인 비율(Ratio)가 맞을거 같습니다. 따라서 증/가감에 따라서 서버의 Orchestration 처리에 문제가 있음을 확인 할 수 있습니다.

 

image

 

판별하기 힘든 이유로 서버의 응답이 느려지는 경우 Throttling 카운터 들을 확인해 보시는 것도 좋겠습니다.

Throttling State 카운터는 "Message delivery", "Message publishing" "Process memory usage throttling" 3가지가 있습니다.

 

image

 

자세한 정보는 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

 

 

Posted Thursday, December 04, 2008 11:07 AM by Yong Hee Park | 1 Comments

More Posts Next page »
Page view tracker