WCF客户端性能问题

时间:2012-04-11 14:32:57

标签: c# wcf

我有一个应该能够向我的wcf服务发送数百个并发请求的应用程序。该服务正在公开http联合绑定。

目前我正在使用单个客户端和TPL在多个线程上发送请求。我还将system.net max connections设置更改为1000,以便windows不会将wcf限制为最多2个并发请求。

我可以看到初始请求需要更多时间,因为他们正在获取身份验证令牌等,然后请求时间通常开始显着减少,但后来我间歇性地看到一些峰值,这与服务器日志无关有

我想知道这是否是接近高通量高可扩展客户端的最佳方式。

我尝试在多个线程之间使用共享客户端代理,并在多个线程之间共享ChannelFactory。所有线程都使用TPL完成。

显示绑定

<basicHttpBinding>
        <binding name="Binding1" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00" closeTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
            <message clientCredentialType="UserName" algorithmSuite="Default"/>
          </security>
        </binding>
      </basicHttpBinding>

2 个答案:

答案 0 :(得分:2)

您提到您正在使用单个客户端实例,然后使用TPL扇出工作。 WCF客户端实例在技术上不是线程安全的。创建客户端的成本非常低廉,只要在完成后Close(),就不应该害怕创建新实例。

接下来,您不应该单独使用TPL来获得并发性。当您进行WCF调用时,它都是关于网络I / O并等待来自服务器的响应。您需要确保在客户端使用async WCF contracts。然后,您可以将这些与TPL的Task.Factory.FromAsync结合起来,将您在呼叫返回后可能需要执行的任何其他工作流链接在一起。例如:

[ServiceContract]
public interface IMyService
{
    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginDoSomething();
    SomeResultType EndDoSomething(IAsyncResult result);
}

// Somewhere in the client app you store your channel factory (these are "expensive", these you cache)
ChannelFactory<IMyService> channelFactory = new ChannelFactory<IMyService>();

public void MyClientMethod()
{
   // Create a client channel
   IMyService myServiceChannel = channelFactory.CreateChannel();

   // Use TPL's FromAsync to invoke the async WCF call and wrap that up with the familiar Task API
   Task<SomeResultType>.Factory.FromAsync(myServiceChannel.BeginDoSomething
                                          myServiceChannel.EndDoSomething,
                                          null)
                               .ContinueWith(antecdent =>
                               {
                                    try
                                    {
                                        // NOTE: exception will be thrown here if operation failed
                                        SomeResultType result = antecedent.Result;

                                        // ... continue processing the result ...
                                    }
                                    finally
                                    {
                                        // NOTE: depending on your configuration you might want to watch for errors and .Abort() here too
                                        ((IClientChannel)myServiceChannel).Close();
                                    }
                               });      
}

您的所有可扩展性都来自于在该客户端调用上使用异步I / O.

答案 1 :(得分:1)

WCF服务和使用WCF客户端(直接使用ClientBase或ChannelFactory)的一些生产性能问题是由于.NET垃圾收集器由于草率的对象处理而被迫执行大量工作。我将使用性能监视器在运行时检查.NET垃圾收集器的行为,看看是否会导致峰值。

如果是GC问题,那么您需要检查您的服务和客户端代码。在服务上,确保对象实例范围尽可能受限。这有助于确保实例主要是在Gen0中进行垃圾收集,这种情况最常发生。还应审查客户端代码,但这在服务代码中尤为重要。

此外,在服务中,特别是在客户端上,确保实现IDisposable的对象实例正确地包装在using语句除了WCF客户端实例之外。要处理WCF客户端的正确处置,请查看此brief blog post以获得良好的模式。如果您使用依赖注入容器,这可能会变得棘手。您可以搜索“WCF不使用”以获取有关原因的更多详细信息。 BasicHttpBinding和WsHttpBinding的一些配置可以处理草率处理,但任何使用会话的绑定都会容易出现GC问题。