7

我有一个相当简单的 WCF Web 服务,使用 .Net 3.5 托管在 IIS Express(最终成为完整的 IIS)中。服务方法相当无趣。

[ServiceContract]
public class MySvc
{
    [OperationContract]
    public Stuff MyMethod(string input)
    {
        Stuff result = DoSomething();
        return result;
    }
}

服务配置也相当通用:

<system.serviceModel>
    <services>
        <service behaviorConfiguration="MySvcBehavior" name="MySvc">
            <endpoint address="" binding="wsHttpBinding" contract="MySvc">
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MySvcBehavior">
                <serviceMetadata httpGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

该服务由 ASPX 应用程序中的代码隐藏使用。有一个服务参考,导致一些同样无趣的代码。

MySvcClient svc = new MySvcClient();
Stuff result = svc.MyMethod("foo");

只要一次一个请求,一切正常,客户端代码得到预期的结果。耶。

当我进行一些非常原始的压力测试时,问题就来了。我在浏览器中加载客户端 ASPX 页面,然后按住 F5 键。观察 IIS Express 窗口,起初结果返回状态 200,但几分钟后我开始看到状态 500。此时,服务只会响应状态 500,直到我重新启动 IIS Express。(基于等待大约 10 分钟。)

在客户端代码中设置断点,我看到完整的返回消息是“服务器上有太多待处理的安全对话。请稍后重试。”

在服务器代码中设置断点,我发现我的代码甚至没有被调用。所以它在调用和我的代码的实际开始之间的某个地方失败了。

我的在线搜索并不是很有希望,主要导致编写自定义绑定以覆盖 maxPendingSessions 属性和一个以“有人告诉我有一个 [未命名] 配置文件设置”开头的线程的相同建议,然后导致声称微软承认这是一个错误的链接断开。

关于 maxPendingSessions 属性的链接确实提到了 128 个连接的限制,超时时间为两分钟,我当然可以看到我的测试方法将在哪里中断一些连接。这是公认的糟糕测试方法的预期结果吗?或者可以在配置中做些什么来改善这一点?

4

4 回答 4

4

听起来您在服务器上有无数个打开的连接 - 由于客户端没有使用“使用”进行连接。

于 2013-03-20T16:58:58.617 回答
1

我首先建议在服务器类机器上的完整 IIS 上进行测试。我不会信任客户端操作系统上的 IIS Express 来进行性能测试。
如果仍然很糟糕,请查看限制以限制 maxConcurrentCalls。http://msdn.microsoft.com/en-us/library/vstudio/ms735114(v=vs.90).aspx

于 2013-03-21T09:38:37.710 回答
1

对于那些推荐 using 语句的人:您不应该使用 using 语句来关闭客户端。

请参阅http://msdn.microsoft.com/en-us/library/aa355056.aspx

而不是关闭客户端,您应该使用以下代码段:

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

如果您不想缓存显式异常,或者只是一个普通的捕获。有时您希望捕获显式异常,因为如果通信对象没有出现故障,您可以重试您的操作,这将提供资源的最佳使用。

对于您在服务器上挂起对话的问题,一旦您正确关闭客户端,这将变得不那么常见,但是如果您的服务器端代码有长时间运行的操作并且客户端正在排队,您可能仍然会看到它。在这种情况下,要增加 MaxPendingChannels 的值,您要么必须在客户端和接收方配置文件中使用自定义绑定,要么在启动服务之前以编程方式修改接收方的绑定。如果您使用的是 .NET 3.5,则 MaxPendingChannels 的默认值实际上是 4。对于 .NET 3.0,该值据称为 128。在我看来,两者都很低。

请参阅http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/745b95d2-1480-4618-89f5-1339d6ee228d

于 2013-04-09T16:06:14.150 回答
0

与目标服务器的连接太多。有一些方法可以以正确的方式关闭连接。已经提到的是,应该始终using围绕 WCF 代理声明。

除此之外,还有(是?)一个错误,要求您在打开代理时提出请求。创建代理时,它给代理大约两分钟的机会向服务器发出请求。如果是这样,它将使计时器无效,从而允许清理代理。如果没有发出请求,代理在实际关闭连接之前仍会等待超时。这次可能不是这种情况,但为了完整性而添加。

解决此问题的一种方法是使用 (ASP.NET) 缓存。System.Web.Caching.Cache是一个很好的候选人。它允许您缓存给定(最终滑动)期间的结果。这样,每 2 分钟只发出一个请求。这使得网站/网络服务非常可扩展。例如,如果每分钟有 1000 个请求,则同一服务调用只使用一个连接。

另一种方法是,如果请求很昂贵且不值得等待,则提前发出请求并缓存响应(ala cron、任务调度程序或只是另一个线程)。这将允许页面快速检索。

除此之外,应该正确配置服务器。无需从一个客户端打开 128 个并发连接。尝试将其限制为,例如每个客户端 8 个连接。这允许同时处理多个客户端。也尝试设置一个体面的超时。等待 5 分钟让客户端关闭其连接,并不会真正增加吞吐量。

还要考虑消息的异步处理。它使用服务必须等待 I/O 来处理其他连接的时间。我看不到 WCF 服务的作用,所以这可能不相关。

于 2013-03-21T08:18:34.417 回答