94

我们有一个应用程序,它具有在 IIS7 上运行的 WCF 服务 (*.svc) 以及查询该服务的各种客户端。服务器正在运行 Win 2008 Server。客户端运行 Windows 2008 Server 或 Windows 2003 Server。我收到以下异常,我已经看到它实际上可能与大量潜在的 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 个客户端似乎并不重要,它仍然会偶尔发生。大多数时候,没有超时,但我仍然每小时有几个。错误来自任何被调用的方法。其中一种方法没有参数并返回一些数据。另一个接收大量数据作为参数,但异步执行。错误始终源自客户端,并且从不引用堆栈跟踪中服务器上的任何代码。它总是以:

 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>

我的客户关闭了它的连接:

var client = new MyClient();

try
{
    return client.GetConfigurationOptions();
}
finally
{
    client.Close();
}

我已更改注册表设置以允许更多传出连接:

MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32.

我现在刚刚尝试了 SvcTraceViewer.exe。我设法在客户端捕获了一个异常。我看到它的持续时间是 1 分钟。查看服务器端跟踪,我可以看到服务器没有意识到这个异常。我能看到的最长持续时间是 10 秒。

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

简单地说,我被难住了。我已经尝试了我能找到的所有东西,并且一定缺少 WCF 专家能够看到的非常简单的东西。我的直觉是,在服务器实际接收到消息之前,某些东西在低级别 (TCP) 上阻塞了我的客户端,和/或某些东西正在服务器级别对消息进行排队,并且从不让它们处理。

如果您有任何我应该查看的性能计数器,请告诉我。(请指出哪些值是错误的,因为其中一些计数器很难破译)。另外,我如何记录 WCF 消息大小?最后,是否有任何工具可以让我测试我可以在客户端和服务器之间建立多少连接(独立于我的应用程序)

谢谢你的时间!

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

我的 WCF 应用程序执行类似于以下的操作。

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

使用 WireShark,我确实看到当错误发生时,我有五次 TCP 重传,然后是 TCP 重置。我的猜测是 RST 来自 WCF 终止连接。我得到的异常报告来自 Step3 超时。

我通过查看 tcp 流“tcp.stream eq 192”发现了这一点。然后,我将过滤器扩展到“tcp.stream eq 192 和 http 和 http.request.method eq POST”,并在此流中看到 6 个 POST。这看起来很奇怪,所以我检查了另一个流,例如 tcp.stream eq 100。我有三个 POST,这似乎更正常一些,因为我正在进行三个调用。但是,在每次 WCF 调用后我都会关闭我的连接,所以我希望每个流调用一次(但我对 TCP 不太了解)。

进一步调查后,我将 http 数据包负载转储到磁盘,以查看这六个在哪里调用。

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

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

a) 为什么数据包损坏?随机网络侥幸——也许吧?使用此示例代码对负载进行 gzip 压缩:http: //msdn.microsoft.com/en-us/library/ms751458.aspx - 当同时使用时,代码会偶尔出现错误吗?我应该在没有 gzip 库的情况下进行测试。

b) 为什么在损坏的操作超时后我会看到第 1 步和第 2 步正在运行?在我看来,这些操作似乎不应该发生。也许我没有看到正确的流,因为我对 TCP 的理解是有缺陷的。我有其他同时发生的流。我应该调查其他流 - 快速浏览流 190-194 表明 Step3 POST 具有正确的有效负载数据(未损坏)。促使我再次查看 gzip 库。

4

11 回答 11

52

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

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

这是原始问答WCF Service Throttling

更新

.Net 客户端应用程序中的此配置可能在启动时或任何时候但在开始测试之前。

此外,您可以将它放在 app.config 文件中,如下所示

<system.net>
    <connectionManagement>
      <add maxconnection = "200" address ="*" />
    </connectionManagement>
  </system.net>
于 2010-04-16T11:24:41.530 回答
3

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

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

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

在客户端上运行 Wireshark。在开始捕获时的选项中,将捕获过滤器设置为tcp http and host service.example.com - 这将减少不相关的流量。

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

当您收到错误时,您可以通过 Wireshark 日志查找呼叫的开始。右键单击客户端调用的第一个数据包(应该类似于 GET /service.svc 或 POST /service.svc),然后选择 Follow TCP Stream。

Wireshark 将对整个 HTTP 对话进行解码,因此您可以确保 WCF 实际上正在发回响应。

于 2009-06-17T17:05:47.587 回答
2

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

为了避免这个超时错误,我们需要 在 WCF 客户端代码中为 Proxy配置 OperationTimeout属性。与我在本文前面讨论的其他配置(例如发送超时、接收超时等)不同,此配置是新的。要设置此操作超时属性配置,我们必须在调用操作协定方法之前将代理转换为 WCF 客户端应用程序中的 IContextChannel。

于 2009-06-11T15:22:05.627 回答
2

我有一个非常相似的问题。在过去,这与序列化问题有关。如果您仍然遇到此问题,您能否验证您是否可以正确序列化您返回的对象。具体来说,如果您使用具有关系的 Linq-To-Sql 对象,如果您将子对象上的反向引用放置到父对象并将该反向引用标记为 DataMember,则会出现已知的序列化问题。

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

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

如果你已经解决了这个问题,我很想听听如何,因为我也被它困住了。我已经验证我的问题不是序列化,所以我很茫然。

更新:我不确定它是否会对您有所帮助,但服务跟踪查看器工具在与您的经历非常相似的 5 天后刚刚解决了我的问题。通过设置跟踪然后查看原始 XML,我发现了导致我的序列化问题的异常。它与 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 中打开以检查结果。

于 2009-08-20T14:55:30.347 回答
2

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

于 2011-04-04T22:54:13.473 回答
0

看起来这个异常消息很笼统,可以由于多种原因而被接收。我们在 Windows 8.1 机器上部署客户端时遇到了这个问题。我们的 WCF 客户端在 Windows 服务内运行并不断轮询 WCF 服务。Windows 服务在非管理员用户下运行。通过在 WCF 配置中将 clientCredentialType 设置为“Windows”以允许身份验证通过,已解决该问题,如下所示:

      <security mode="None">
        <transport clientCredentialType="Windows" proxyCredentialType="None"
          realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
于 2014-06-13T15:57:24.450 回答
0

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

于 2009-06-15T12:27:48.987 回答
0

我不是 WCF 专家,但我想知道您是否没有在 IIS 上遇到 DDOS 保护。我从经验中知道,如果您在某个时候从单个客户端到服务器运行一堆同时连接,则服务器会停止响应调用,因为它怀疑 DDOS 攻击。它还将保持连接打开,直到它们超时,以减慢客户端的攻击速度。

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

此 MSDN 帖子中有更多信息:

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

查看 MaxConcurrentSession 属性。

于 2009-06-16T07:10:39.460 回答
0

您检查过 WCF 跟踪吗?WCF 倾向于吞下异常并且只返回最后一个异常,这是您得到的超时,因为端点没有返回任何有意义的东西。

于 2009-06-16T08:31:50.153 回答
0

如果您将一个对象传递回客户端,该对象包含默认情况下未设置的枚举类型属性并且该枚举没有映射到 0 的值,您也会收到此错误。即enum MyEnum{ a=1, b=2};

于 2011-02-25T22:54:57.620 回答
0

刚刚解决了问题,发现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>,属性“mode”值为“None”。如果您的值是“传输”,则会发生错误。

于 2011-11-18T07:31:40.190 回答