我们有一个 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 属性(请参阅管理连接)来增加可用连接的数量。
我跳到线程 17 并看到了这个:
线程 17 - 系统 ID 4612
入口点 mscorwks!Thread::intermediateThreadProc 创建时间 9/10/2015 10:13:14 AM 在用户模式下花费的时间 0 天 00:00:00.000 在内核模式下花费的时间 0 天 00:00:00.000
该线程正在尝试发出 HttpWebRequest,但是它们似乎没有在远程服务器上等待响应(例如,不是“在线”)。这些请求中的一个或多个正在使用其最大可用连接数的至少一半。
警告,至少有一半的可用连接正在使用中
HttpRequest URI:
http://WebServer/MyWebSite/SubDir/MyService.svc
ServicePoint - ConnectionLimit:48 CurrentConnections:44HttpWebRequest 对象是一个环回地址,但连接限制仍然适用于此 webrequest 对象,因为已定义连接限制(通过在 processModel 部分中将 autoconfig 设置为 true 或通过在 connectionManagement 部分中添加 * 条目
.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 消息所示。