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>
您提到您正在使用单个客户端实例,然后使用 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 问题。