【问题标题】:WCF - Random client timeout when making multiple callsWCF - 进行多次调用时随机客户端超时
【发布时间】:2013-06-07 19:16:08
【问题描述】:

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

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

我们使用从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): 不确定这是相关还是只是侥幸,但有几次,我注意到在有问题的调用中,Body size 明显小于其他。并非每次都是如此,但它可能会提供一些线索。这是 Fiddler 的屏幕截图,向您展示了 Body 大小与每次调用的一致性。所选条目 (#21) 的大小比其他条目小得多,但需要 2 多分钟才能完成。

奇怪的是,这次我收到了异常。异常并非每次都发生。

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)

【问题讨论】:

  • 您是否在绑定中使用了可靠会话?
  • 不,我没有打开可靠会话。
  • 几个问题;这些请求是并行的还是顺序的?您是否尝试在 IIS 中为此 WCF 服务调整高级 AppPool 设置中的最大工作进程? (这将把它变成一个网络花园)。我发现当我的服务主机在同时请求中可以处理的内容超载时会发生通信错误。
  • (1) 这些请求是连续的。一个调用将在调用下一个调用之前完成。 (2) 我没有尝试在 Advanced AppPool 设置中调整 Maximum Worker Processes。如果调用是连续的,这仍然适用吗?目前,这设置为 1。
  • 我建议您尝试将 transfermode 设置为 streamed 以排除这是与内存压力有关的问题的可能性(因为流模式应该导致 wcf 使用较少的内存)

标签: .net wcf http fiddler


【解决方案1】:

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

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

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

【讨论】:

  • 再次感谢您的帮助!
【解决方案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

【讨论】:

  • 感谢您的回复。我启用了 WCF 跟踪,但没有看到任何失败或警告。
猜你喜欢
  • 1970-01-01
  • 2011-04-13
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 2012-11-24
  • 2011-03-22
  • 2011-07-07
  • 2012-03-25
相关资源
最近更新 更多