10

我有一个WPF客户通过WCF托管在IIS 7. 服务方法调用存储过程 ( SQL 2012)EF用于检索一些数据。

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

我们使用生成的服务代理从System.ServiceModel.ClientBase<T>.

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

<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

ServerBeginResponse注意和之间的重要时间GotResponseHeaders这似乎与这里看到的问题惊人地相似。

我启用了 WCF 服务跟踪,并且快速浏览了一下,没有错误或警告,但我无法真正理解超出基础的内容。

我怎样才能确定问题出在什么地方?是序列化吗?是网络问题吗?服务器能跟不上客户端发送这么多请求的速度吗?

我已经尝试通过添加适当的 来调整配置文件中的 WCF Throttling serviceBehaviors,但这并没有什么不同。

我应该提一下,我是通过 VPN 连接执行此操作的,但文件传输、远程桌面连接等其他事情也可以正常工作。看起来还挺靠谱的。

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

编辑(6.10.2013):不确定这是否相关或只是侥幸,但有几次,我注意到在有问题的调用中,身体尺寸明显小于其他尺寸。并非每次都是如此,但它可能会提供一些线索。这是 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)
4

2 回答 2

5

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

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

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

于 2013-06-10T19:09:43.203 回答
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 目录并且用户对该目录具有写入权限。

配置 wcf 跟踪

于 2013-06-10T15:26:05.700 回答