WCF 客户端性能问题

本文关键字:问题 性能 客户端 WCF | 更新日期: 2023-09-27 18:30:49

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

目前,我正在使用单个客户端和TPL在多个线程上发送请求。我还将 system.net 最大连接数设置更改为 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>

WCF 客户端性能问题

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

接下来,不应单独使用 TPL 来获取并发性。进行 WCF 调用时,一切都与网络 I/O 和等待来自服务器的响应有关。确保在客户端中执行的操作是使用异步 WCF 协定。然后,您可以将这些工作流与 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。

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

如果是 GC 问题,则需要对服务和客户端代码进行审查。在服务上,确保对象实例范围尽可能有限。这有助于确保实例大部分是在 Gen0 中垃圾回收的,这最常发生。还应检查客户端代码,但它在服务代码中尤其重要。

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