【问题标题】:DebugDiag Message Thread Does Not Appear to be Waiting on the Remote Server to RespondDebugDiag 消息线程似乎没有在远程服务器上等待响应
【发布时间】:2015-09-17 15:30:04
【问题描述】:

我们有一个 C# Windows 服务,它运行一个被拆分为多个任务的进程。大多数任务使用 WCF 联系 Web 服务以针对数据库执行工作。该服务的任务在多个线程中运行。

一位客户向我们提出了一个支持案例,称 Windows 服务偶尔无法响应,需要重新启动。我从 Windows 服务获得了内存转储。我运行DebugDiag 2.0 来分析转储文件。

DebugDiag 报告的摘要中有一个有趣的条目:

WindowsService.DMP 中的以下线程正在尝试发出 HttpWebRequest,但它们确实没有似乎正在等待远程服务器响应(例如,不是“在线”)。这些请求中的一个或多个至少使用了其最大可用连接数的一半。

(17 18 27 31 32 33 42) 12.07% 的线程被阻塞(7 个线程)

如果许多线程处于这种状态,这通常表明限制限制(即“maxconnection”设置)已用尽。单击左侧列表中的任何线程以查看其正在等待的 WebRequest 的限制详细信息。

如有必要,您可以通过修改应用程序配置文件中的“maxconnection”参数(请参阅<connectionManagement> Element)或以编程方式修改相应的 ConnectionLimit 属性(请参阅Managing Connections)来增加可用的连接数。

我跳到线程 17 看到了这个:

线程 17 - 系统 ID 4612

入口点 mscorwks!Thread::intermediateThreadProc 创建时间 2015 年 9 月 10 日上午 10:13:14 在用户模式下花费的时间 0 天 00:00:00.000 在内核模式下花费的时间 0 天 00:00:00.000

此线程正在尝试发出 HttpWebRequest,但是它们确实 似乎正在等待远程服务器响应(例如,不 '在线')。这些请求中的一个或多个正在使用至少一半 其最大可用连接数。

警告,至少有一半的可用连接正在使用中

HttpRequest URI:http://WebServer/MyWebSite/SubDir/MyService.svc ServicePoint - ConnectionLimit:48 CurrentConnections:44

HttpWebRequest 对象是一个环回地址,但连接限制仍然适用于该 webrequest 对象,因为 定义连接限制(通过 autoconfig 设置为 true processModel 部分或通过在其中添加 * 条目 连接管理部分

.NET 调用堆栈如下:

Function

[[HelperMethodFrame_1OBJ] (System.Threading.WaitHandle.WaitOneNative)] System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, UInt32, Boolean, Boolean) 
mscorlib_ni!System.Threading.WaitHandle.WaitOne(Int64, Boolean)+2f 
mscorlib_ni!System.Threading.WaitHandle.WaitOne(Int32, Boolean)+25 
System_ni!System.Net.LazyAsyncResult.WaitForCompletion(Boolean)+d3 
System_ni!System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest)+2b7 
System_ni!System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)+7c 
System_ni!System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)+f9 
System_ni!System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)+1d3 
System_ni!System.Net.HttpWebRequest.GetRequestStream()+e 
System_ServiceModel_ni!System.ServiceModel.Channels.HttpOutput+WebRequestHttpOutput.GetOutputStream()+45 
System_ServiceModel_ni!System.ServiceModel.Channels.HttpOutput.Send(System.TimeSpan)+f6 
System_ServiceModel_ni!System.ServiceModel.Channels.HttpChannelFactory+HttpRequestChannel+HttpChannelRequest.SendRequest(System.ServiceModel.Channels.Message, System.TimeSpan)+121 
System_ServiceModel_ni!System.ServiceModel.Channels.RequestChannel.Request(System.ServiceModel.Channels.Message, System.TimeSpan)+cb 
System_ServiceModel_ni!System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message, System.TimeSpan)+17 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannel.Call(System.String, Boolean, System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[], System.TimeSpan)+1a2 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannel.Call(System.String, Boolean, System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[])+33 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)+43 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)+65 
mscorlib_ni!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)+bd
[[TPMethodFrame] (IMyWebService.GetDataSet)]
IMyWebService.GetDataSet(System.Guid, System.String, System.Data.DataSet)
<service code snipped>
mscorlib_ni!System.Threading.ThreadHelper.ThreadStart_Context(System.Object)+66
mscorlib_ni!System.Threading.ExecutionContext.runTryCode(System.Object)+51 
[[HelperMethodFrame_PROTECTOBJ] (System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup)]
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) 
mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+67 
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+45 
mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+44 
[[GCFrame]] 

我看到了它提出的建议,并已开始研究它们。我的问题是:

为什么 DebugDiag 说线程没有似乎在等待服务器响应?

查看.NET Reference Source,请求似乎已经提交成功,服务似乎正在等待响应。

更新

进入正常调用后,我确实看到一个调用堆栈在 ws2_2 等待,如下 Puneet Gupta 所建议:

ntdll.dll!_NtWaitForSingleObject@12()
mswsock.dll!_SockWaitForSingleObject@16()
mswsock.dll!_WSPRecv@36()
***ws2_32.dll!_recv@16()***
System.ni.dll!6c084a13()
[Managed to Native Transition]  
System.dll!System.Net.Sockets.Socket.Receive(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode)
System.dll!System.Net.Sockets.Socket.Receive(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags)
System.dll!System.Net.Sockets.NetworkStream.Read(byte[] buffer, int offset, int size)
System.dll!System.Net.PooledStream.Read(byte[] buffer, int offset, int size)
System.dll!System.Net.Connection.SyncRead(System.Net.HttpWebRequest request, bool userRetrievedStream, bool probeRead)
System.dll!System.Net.ConnectStream.ProcessWriteCallDone(System.Net.ConnectionReturnResult returnResult)
System.dll!System.Net.HttpWebRequest.WriteCallDone(System.Net.ConnectStream stream, System.Net.ConnectionReturnResult returnResult)
System.dll!System.Net.ConnectStream.CallDone(System.Net.ConnectionReturnResult returnResult)
System.dll!System.Net.ConnectStream.ResubmitWrite(System.Net.ConnectStream oldStream, bool suppressWrite)
System.dll!System.Net.HttpWebRequest.EndWriteHeaders_Part2()
System.dll!System.Net.HttpWebRequest.EndWriteHeaders(bool async)
System.dll!System.Net.HttpWebRequest.WriteHeadersCallback(System.Net.WebExceptionStatus errorStatus, System.Net.ConnectStream stream, bool async)
System.dll!System.Net.ConnectStream.WriteHeaders(bool async)
System.dll!System.Net.HttpWebRequest.EndSubmitRequest()
System.dll!System.Net.HttpWebRequest.CheckDeferredCallDone(System.Net.ConnectStream stream)
System.dll!System.Net.HttpWebRequest.GetResponse()
System.ServiceModel.dll!System.ServiceModel.Channels.HttpChannelFactory<System.ServiceModel.Channels.IRequestChannel>.HttpRequestChannel.HttpChannelRequest.WaitForReply(System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.RequestChannel.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout)  Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.Call(string action, bool oneway, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation, object[] ins, object[] outs, System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage methodCall, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage message)
mscorlib.dll!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref System.Runtime.Remoting.Proxies.MessageData msgData, int type)

所以通常情况下,它将等待来自 Windows 套接字的响应。在这种情况下,线程可能正在等待连接变为可用于处理请求 - 如其他 DebugDiag 消息所示。

【问题讨论】:

    标签: c# multithreading wcf windows-services debugdiag


    【解决方案1】:

    消息说它似乎没有在线等待的原因是因为线程上的最后一帧是waithandle.waitone。

    对于真正在线等待的线程,我们应该看到 ws2_32(在本机堆栈中),它是 Windows 套接字库或托管堆栈中 system.net.sockets 中的一些函数。

    您是否能够捕获多个转储?如果是,您是否看到线程状态在一个转储与第二个转储中发生了变化?

    【讨论】:

    • 有趣。不,我只有一个转储,但如果它再次发生,我可以在未来使用 > 1。我使用 WinDbg 的最佳猜测是线程似乎已经等待了很长时间——大约 1 到 2 个小时。
    【解决方案2】:

    !dso (!DumpStackObjects) 是否显示当前线程中的任何连接对象?如果是这样,System.Net.Connection 对象中的 m_WaitList 值是多少,m_CurrentRequest 的值是多少? 由于您的调用堆栈没有显示我们正在等待 ws2_32 (WinSock),这表明 HWR 仍在等待获取可用连接或套接字。

    【讨论】:

    • 感谢您的回复。有联系。连接的等待列表有 1 个对当前线程尝试联系的同一 URL 的 HTTP 请求。 (我确实希望多个线程出于不同目的调用同一个端点。)在这个连接上,没有当前请求。 m_CurrentRequest 为空。
    • m_Free/m_Idle Boolean 连接怎么样。由于此连接积压为 1,但没有所有者请求。 m_Free 和 m_Idle 会告诉你连接状态。
    • 在创建 HWR 之前,您是否测试过将 ServicePointManager.DefaultConnecitonLimit 设置为 96?
    • m_Free 和 m_Idle 均为 0。m_ReadDone = 0,m_WriteDone = 1。ConnectionGroup 最多有 48 个连接。该组中当前有 45 个连接。前 7 个连接的等待列表长度均为 1。我查看了其他几个,它们的等待列表长度为 0。我可以尝试更高的连接限制。然而,有些东西看起来很奇怪。我不明白为什么 HttpWebRequests 被分配了已经在等待的连接。为什么不使用空闲连接?
    • 我只知道 support.microsoft.com/en-us/kb/2497453 中记录的 HWR 的一些旧锁定问题,但不确定您的情况是否与此相关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多