我有一个相当简单的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分钟。)
在客户端代码中设置断点,我看到完整的返回消息是“服务器上有太多待处理的安全对话。请稍后重试。”
在服务器代码中设置断点,我发现我的代码甚至没有被调用。所以它在调用和实际启动代码之间失败了。
我的在线搜索并不是很有希望,主要导致相同的suggestion of writing a custom binding以覆盖maxPendingSessions属性,并且以“Someone告诉我有[未命名]配置文件设置”开头的线程然后导致链接断开,声称微软承认这是一个错误。
关于maxPendingSessions属性的链接确实提到了128个连接的限制,超时为2分钟,我当然可以看到我的测试方法将中断某些连接。这是否是一种公认的不良测试方法的预期结果?或者可以在配置中做些什么来改善这个?
答案 0 :(得分:4)
听起来你在服务器上有很多开放的连接 - 因为客户端没有使用'using'进行连接。
答案 1 :(得分:1)
我首先建议在服务器类机器上的完整IIS上测试它。我不相信IIS Express在客户端操作系统上进行性能测试 如果仍然不好,那么请查看限制来限制maxConcurrentCalls。 http://msdn.microsoft.com/en-us/library/vstudio/ms735114(v=vs.90).aspx
答案 2 :(得分:0)
与目标服务器的连接太多。有一些方法可以以适当的方式关闭连接。已经提到的是,围绕WCF代理应该始终有一个using
语句。
除此之外,还有(是?)一个错误,要求您在打开代理时提出请求。在创建代理时,它为代理提供了大约两分钟向服务器发出请求的机会。如果是,则使计时器无效,允许清理代理。如果没有请求,代理仍会在实际关闭连接之前等待超时。可能不是这次的情况,但为了完整性而增加了。
解决此问题的一种方法是使用(ASP.NET)缓存。 System.Web.Caching.Cache
是一个很好的候选人。它允许您缓存给定(最终滑动)时段的结果。这样每次只需要一个请求,例如2分钟。这使得网站/ webservice具有很高的可扩展性。例如,如果每分钟有1000个请求,则只有一个连接用于同一服务调用。
另一种方法是,如果请求很昂贵而且不值得等待,请事先提出请求并缓存响应(ala cron,任务调度程序或简单的另一个线程)。这将允许页面快速检索。
除此之外,应正确配置服务器。不需要从一个客户端打开128个并发连接。尝试将此限制为,例如每个客户端8个连接。这允许同时处理多个客户端。也尝试设置一个体面的超时。等待5分钟让客户端关闭其连接,并不能真正提高吞吐量。
另请考虑asynchronous handling of messages。它使用服务必须等待I / O来处理其他连接的时间。我无法看到WCF服务的作用,因此这可能不相关。
答案 3 :(得分:0)
对于推荐使用声明的人:您不应使用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;
}
如果您不想缓存显式异常,或者只是一个vanilla catch。有时您会想要捕获明确的异常,因为如果通信对象没有出现故障,您可以重试您的操作,从而最大限度地利用资源。
对于您在服务器上挂起的会话的问题,一旦正确关闭客户端,这将变得不常见,但是如果您的服务器端代码具有长时间运行的操作并且客户端正在排队,您仍可能看到它。在这种情况下,要增加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