WCF - 进行多次调用时随机客户端超时

时间:2013-06-07 19:16:09

标签: .net wcf http fiddler

我有一个WPF客户端通过WCF中托管的IIS 7服务请求数据。 service方法使用SQL 2012调用存储过程(EF)来检索某些数据。

要加载大量数据,因此客户端会多次调用服务方法,以“分解”数据加载并避免大量有效负载和超时。

我们使用从System.ServiceModel.ClientBase<T>.

延伸的生成的服务代理

我们还使用带二进制编码的自定义http绑定(来自here) - 此处显示的实际实现:

<customBinding>
   <binding name="CustomBinding_IPointDataAccess" closeTimeout="00:01:00"
      openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
      <binaryMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16" maxSessionSize="2048">
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384" />
      </binaryMessageEncoding>
      <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
         maxReceivedMessageSize="2147483647" allowCookies="false" authenticationScheme="Anonymous" bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard" keepAliveEnabled="true" maxBufferSize="2147483647" proxyAuthenticationScheme="Anonymous" realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false" useDefaultWebProxy="true" />
   </binding>

此外,在IIS中打开了动态压缩。我可以在Fiddler中查看请求,并且消息正文的大小很好(~50KB),并且 99%的请求在一两秒内返回。完善!

然而,几乎每次迭代都会有一个电话需要几分钟才能完成,我不知道为什么......客户端上的sendTimeOut是1分钟而且自然就是一个电话会失败。我把它延长到10分钟,电话似乎在2分多钟内完成 - 虽然有时需要更长时间。这个问题看起来非常随机 - 可能是第一次通话,可能是第30次通话。但它非常可重复。

我在WCF服务方法中对存储过程调用进行了一些日志记录,并在一秒钟内执行并获取数据。所以,我不认为这是一个数据库问题。

使用Fiddler,有问题的调用会生成类似于以下内容的输出:

ACTUAL PERFORMANCE
--------------
ClientConnected:     14:02:42.959
ClientBeginRequest:  14:03:01.224
GotRequestHeaders:   14:03:01.224
ClientDoneRequest:   14:03:01.574
Determine Gateway:   0ms
DNS Lookup:      0ms
TCP/IP Connect:  46ms
HTTPS Handshake:     0ms
ServerConnected:     14:05:16.021
FiddlerBeginRequest: 14:05:16.021
ServerGotRequest:    14:05:16.021
ServerBeginResponse: 14:03:04.784
GotResponseHeaders:  14:05:16.561
ServerDoneResponse:  14:05:16.611
ClientBeginResponse: 14:05:16.611
ClientDoneResponse:  14:05:16.611

请注意ServerBeginResponseGotResponseHeaders之间的重要时间。这看起来与here所见的问题非常相似。

我启用了WCF服务跟踪,并且快速浏览一下,没有任何错误或警告,但除了基础知识之外,我无法理解我所看到的内容。

我如何确定问题的所在和所在?是序列化吗?这是网络问题吗?服务器是否可以跟不上发送这么多请求的客户端?

我尝试通过添加相应的serviceBehaviors来调整配置文件中的WCF限制,但这没有什么区别。

我应该提一下,我是通过VPN连接进行此操作,但其他方面,如文件传输,远程桌面连接工作正常。看起来很可靠。

如有必要,我可以提供更多详细信息。

编辑(6.10.2013):不确定这是否相关或只是侥幸,但有几次,我注意到在有问题的电话中,体型明显小于其他。每次都不是这种情况,但它可能提供一些线索。这是来自Fiddler的屏幕截图,向您展示每次调用时Body尺寸的一致性。所选条目(#21)的尺寸远小于其他条目,但需要2分钟才能完成。

enter image description here

奇怪的是,这次我收到了一个例外。每次都不会发生异常。

System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

2 个答案:

答案 0 :(得分:3)

正如我在评论中所建议的那样,请尝试将transfermode设置为流式传输以排除这是与内存压力相关的问题的可能性(因为流模式应该导致wcf使用更少的内存)。

当我看到这个问题时,怀疑这可能是问题,因为在快速连续进行多次服务呼叫时,似乎只会发生这种情况。根据我的经验,这通常是两个问题之一:代理没有从客户端正确关闭,或者服务器由于内存压力而运行GC。

当缓冲传输模式时,WCF会将消息响应的整个数据集加载到内存中,然后再将其发送回客户端。流式传输只是将数据发回而不进行缓冲。对于大型数据集来说,它往往要快得多,对于小型数据集来说要慢得多,并且总是利用更少的内存(在服务器和客户端上)。

答案 1 :(得分:2)

要了解导致超时的原因,您应该跟踪WCF中发生的情况。将以下内容添加到配置文件将在客户端和服务器上生成跟踪文件:

<system.diagnostics>
   <sources>
       <source name="UserTraceSource" switchValue="Warning, ActivityTracing" >
          <listeners>
              <add name="xml"
                 type="System.Diagnostics.XmlWriterTraceListener"
                 initializeData="C:\logs\UserTraces.svclog" />
          </listeners>
       </source>
   </sources>
   <trace autoflush="true" /> 
</system.diagnostics>

通常情况下,该文件会准确地告诉您发生了什么以及失败了什么。确保您拥有C:\ logs目录,并且用户对目录具有写入权限。

Configure wcf tracing