WCF超时exception详细调查

我们有一个应用程序,它具有在IIS7上运行的WCF服务(* .svc)以及查询服务的各种客户端。 服务器正在运行Win 2008 Server。 客户端正在运行Windows 2008 Server或Windows 2003服务器。 我得到了下面的例外,我已经看到事实上可能与大量潜在的WCF问题有关。

System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9320000. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. ---> System.TimeoutException: The HTTP request to 'http://www.domain.com/WebServices/myservice.svc/gzip' has exceeded the allotted timeout of 00:01:00. The time allotted to this operation may have been a portion of a longer timeout. 

我把超时时间增加到了30分钟,错误仍然发生。 这告诉我其他的事情正在发挥,因为数据量不能花30分钟上传或下载。

错误来了。 目前,这是更频繁的。 如果我有3个客户端同时运行或100个,似乎并不重要,它仍然偶尔发生。 大多数时候,没有超时,但我仍然每小时几个。 错误来自任何被调用的方法。 其中一种方法没有参数并返回一些数据。 另一个需要大量的数据作为参数,但asynchronous执行。 错误总是来自客户端,并且从不在堆栈跟踪中引用服务器上的任何代码。 它始终以:

  at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 

在服务器上:我试过(现在有)以下绑定设置:

 maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" 

这似乎没有影响。

我试过(现在有)下面的限制设置:

 <serviceThrottling maxConcurrentCalls="1500" maxConcurrentInstances="1500" maxConcurrentSessions="1500"/> 

这似乎没有影响。

我目前有WCF服务的以下设置。

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] 

我用ConcurrencyMode.Multiple运行了一段时间,错误仍然发生。

我已经尝试重新启动IIS,重新启动我的底层SQL Server,重新启动计算机。 所有这些似乎都没有影响。

我试过禁用Windows防火墙。 这似乎没有影响。

在客户端上,我有这些设置:

 maxReceivedMessageSize="2147483647" <system.net> <connectionManagement> <add address="*" maxconnection="16"/> </connectionManagement> </system.net> 

我的客户closures它的连接:

 var client = new MyClient(); try { return client.GetConfigurationOptions(); } finally { client.Close(); } 

我已经改变了registry设置,以允许更多的传出连接:

 MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32. 

我现在刚刚尝试过SvcTraceViewer.exe。 我设法在客户端捕捉到一个例外。 我看到它的持续时间是1分钟。 看着服务器端跟踪,我可以看到服务器不知道这个exception。 我能看到的最长时间是10秒。

我已经使用服务器上的exec sp_who来查看活动数据库连接。 我只有几个(2-3)。 我使用TCPview从一个客户端查看了TCP连接。 它通常是2-3左右,我已经看到了5或6。

简单地说,我很难过。 我已经尝试了所有我能find的东西,而且必须错过WCF专家才能看到的东西。 这是我的直觉,在服务器实际接收到消息之前和/或在服务器级别排队消息,并且从不让他们处理消息之前,某些东西阻塞了我的客户端在低层(TCP)。

如果你有任何性能指标我应该看看,请告诉我。 (请指出哪些值是不好的,因为其中一些计数器很难降级)。 另外,如何loggingWCF消息大小? 最后,有没有什么工具可以让我testing我的客户端和服务器之间可以build立多less个连接(独立于我的应用程序)

谢谢你的时间!

额外增加的信息6月20日:

我的WCF应用程序做了类似于以下内容。

 while (true) { Step1GetConfigurationSettingsFromServerViaWCF(); // can change between calls Step2GetWorkUnitFromServerViaWCF(); DoWorkLocally(); // takes 5-15minutes. Step3SendBackResultsToServerViaWCF(); } 

使用WireShark,我确实看到,当发生错误时,我有五个TCP重新传输,其后是TCP重置。 我的猜测是RST来自WCF的连接。 我得到的例外报告是从Step3超时。

我通过查看tcpstream“tcp.stream eq 192”发现了这一点。 然后我把我的filter扩展到“tcp.stream eq 192和http和http.request.method eq POST”,并在此stream中看到了6个POST。 这似乎很奇怪,所以我检查了另一个stream,如tcp.stream公式100.我有三个POST,这似乎有点正常,因为我正在做三个电话。 但是,在每次WCF调用之后,我都会closures连接,所以我希望每个stream都有一个调用(但对TCP我不太了解)。

调查了一下,我把这个http数据包加载到磁盘上,看看这六个电话在哪里。

 1) Step3 2) Step1 3) Step2 4) Step3 - corrupted 5) Step1 6) Step2 

我的猜测是两个并发客户端使用相同的连接,这就是为什么我看到重复。 不过,我还有一些我无法理解的问题:

a)为什么数据包被损坏? 随机networking侥幸 – 也许? 使用这个示例代码gzip的负载: http : //msdn.microsoft.com/en-us/library/ms751458.aspx – 同时使用时,可以在一段时间的代码车? 我应该testing没有gzip库。

b)为什么我会看到步骤1和步骤2运行后损坏的操作超时? 在我看来,似乎这些行动不应该发生。 也许我不是在看正确的stream,因为我对TCP的理解是有缺陷的。 我有其他的stream同时发生。 我应该调查其他stream – 快速浏览stream190-194显示Step3 POST具有适当的有效载荷数据(未损坏)。 推我再看看gzip库。

如果你使用.Net客户端,那么你可能没有设置

 //This says how many outgoing connection you can make to a single endpoint. Default Value is 2 System.Net.ServicePointManager.DefaultConnectionLimit = 200; 

这里是WCF服务节stream的原始问题和答案

更新

这个configuration进入.net客户端应用程序可能会启动或每当开始您的testing之前。

此外,你可以在app.config文件中有如下所示

 <system.net> <connectionManagement> <add maxconnection = "200" address ="*" /> </connectionManagement> </system.net> 

如果您还没有尝试过,请将您的服务器端WCF操作封装在try / finally块中,并添加日志logging以确保它们实际上正在返回。

如果这些显示操作正在完成,那么我的下一步就是降低级别,并查看实际的传输层。

Wireshark或其他类似的数据包捕获工具在这一点上可能相当有帮助。 我假设这是通过标准80端口上的HTTP运行。

在客户端运行Wireshark。 在开始捕获的选项中,将捕获filter设置为tcp http and host service.example.com – 这将减less不相关的stream量。

如果可以,请修改您的客户端以通知您确切的开始呼叫时间以及发生超时的时间。 或者只是密切监视。

当出现错误时,您可以通过Wireshark日志来查找通话的开始。 右键单击第一个包含客户端调用的数据包(应该是GET /service.svc或POST /service.svc),然后selectFollow TCP Stream。

Wireshark将解码整个HTTP会话,所以你可以确保WCF实际上发送回应。

来自: http : //www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

为了避免这个超时错误,我们需要在WCF客户端代码中configuration Proxy 的OperationTimeout属性。 这种configuration是不同于其他configuration,如发送超时,接收超时等,我在文章的早些时候讨论。 为了设置这个操作超时属性configuration,我们必须在调用操作契约方法之前将我们的代理强制转换为WCF客户端应用程序中的IContextChannel。

我有一个非常类似的问题。 过去,这与序列化问题有关。 如果你仍然有这个问题,你可以validation你可以正确地序列化你正在返回的对象。 特别是,如果使用的是具有关系的Linq-To-Sql对象,那么如果将子对象的反向引用放在父对象上,并将该后向引用标记为DataMember,则存在已知的序列化问题。

您可以通过编写一个控制台应用程序来validation序列化,该应用程序使用服务器端的DataContractSerializer以及客户端使用的任何序列化方法对您的对象进行序列化和反序列化。 例如,在我们当前的应用程序中,我们同时拥有WPF和Compact Framework客户端。 我编写了一个控制台应用程序来validation我可以使用DataContractSerializer进行序列化,并使用XmlDesserializer进行反序列化。 你可以试试。

此外,如果您要返回具有子集合的Linq-To-Sql对象,则可以尝试确保已经在服务器端急切地加载它们。 有时,由于延迟加载,返回的对象不会被填充,并且可能会导致您看到多次将请求发送到服务方法的行为。

如果你已经解决了这个问题,我很乐意听到这个问题,因为我也被困住了。 我已经证实,我的问题不是系列化,所以我不知所措。

更新:我不确定它是否会帮助你,但服务跟踪查看器工具刚刚解决了我的问题5天后,非常类似的经验,你的。 通过设置跟踪,然后查看原始XML,我发现导致序列化问题的exception。 这与Linq-to-SQL对象有关,偶尔有更多的子对象可能被成功序列化。 将以下内容添加到您的web.config文件应该启用跟踪:

 <sharedListeners> <add name="sharedListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\Temp\servicetrace.svclog" /> </sharedListeners> <sources> <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing" > <listeners> <add name="sharedListener" /> </listeners> </source> <source name="System.ServiceModel.MessageLogging" switchValue="Verbose"> <listeners> <add name="sharedListener" /> </listeners> </source> </sources> 

可以使用服务跟踪查看器工具打开生成的文件,也可以在IE中查看结果。

您是否在请求之间closures到WCF服务的连接? 如果你不这样做,你会看到确切的超时(最终)。

我刚刚解决了这个问题。我发现App.config文件中的节点错误。

 <client> <endpoint name="WCF_QtrwiseSalesService" binding="wsHttpBinding" bindingConfiguration="ws" address="http://cntgbs1131:9005/MyService/TGE.ISupplierClientManager" contract="*"> </endpoint> </client> <bindings> <wsHttpBinding> <binding name="ws" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text"> <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/> <**security mode="None">** <transport clientCredentialType="None"></transport> </security> </binding> </wsHttpBinding> </bindings> 

在节点<security>确认您的configuration,属性“mode”值为“None”。 如果您的值是“传输”,则会发生错误。

你有没有尝试使用clientVia来查看发送的消息,使用SOAP工具包或类似的东西? 这可能有助于查看错误是来自客户端还是来自其他地方。

你检查过WCF的痕迹吗? WCF倾向于吞下exception,并且只返回最后一个exception,这是您所得到的超时,因为结束点没有返回任何有意义的结果。

如果你将一个对象传回给包含一个enumtypes属性的客户端,而这个属性默认没有设置,并且enum没有映射为0的值,你也会收到这个错误。例如enum MyEnum{ a=1, b=2};

看起来像这个exception信息是相当通用的,可以由于各种原因接收。 我们在Windows 8.1机器上部署客户端时遇到了这个问题。 我们的WCF客户端在Windows服务中运行,并不断轮询WCF服务。 Windows服务在非pipe理员用户下运行。 通过在WCFconfiguration中将clientCredentialType设置为“Windows”来解决该问题,以允许身份validation通过,如下所示:

  <security mode="None"> <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security> 

我不是WCF专家,但是我想知道你是不是在IIS上运行DDOS防护。 我从经验中得知,如果您在某个时间点从一个客户端向服务器运行一堆同时连接,则服务器会因为怀疑DDOS攻击而停止响应这些呼叫。 它也将保持连接,直到它们暂停,以便在攻击中减慢客户的速度。

然而,来自不同机器/ IP的多重连接应该不成问题。

有更多的信息在这个MSDN文章:

http://msdn.microsoft.com/en-us/library/bb463275.aspx

查看MaxConcurrentSession sproperty。