对于实验,我在VS2012上使用.NET 4.5创建了一个简单的“Hello World”WCF服务和客户端。服务器托管在控制台应用程序上,并使用net.tcp绑定。我编写了客户端代码,向服务器发送一连串异步请求(总共700个请求)。一切顺利,直到我打开服务的可靠会话功能。打开后,服务突然变得很慢,我的机器上花了差不多一分钟来完成700个请求。我试图微调Concurrency和Throttling参数(见下文),但它没有帮助。
有谁知道为什么会这样?反正有没有避免这个?
如果我关闭Reliable会话功能,或者我使服务调用同步,则不会发生缓慢。所以我认为它可能与WCF在WS-ReliableMessaging模式下处理挂起请求的方式有关。
编辑:当我将netTcpBinding转换为wsHttpBinding时,这也没有发生。这很奇怪,因为在这种情况下,wsHttpBinding比netTcpBinding快得多。
编辑:在服务器端运行Perfmon.exe表明在上述情况下“线程计数”从8逐渐增加到100以上。
编辑:我的PC(本地网络)上的一些测量吞吐量。看到案例1的表现非常缓慢,实际上没用。
以下是我在实验中使用的服务器和客户端的代码和配置。
服务器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using System.ServiceModel.Description;
[ServiceContract]
public interface IHelloService
{
[OperationContract(IsOneWay=false)]
string SayHello(string name);
}
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.PerSession)]
public class HelloService : IHelloService
{
public string SayHello(string name) {
String s = string.Format("Hello {0}", name);
return s;
}
}
namespace WcfServer
{
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("net.tcp://localhost:8080/hello");
using (ServiceHost host = new ServiceHost(typeof(HelloService), baseAddress)){
// Open and listen
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using WcfClient.WcfServer;
namespace WcfClient
{
class Program
{
static async Task PrintNameAsync(HelloServiceClient client, int cnt) {
string s = await client.SayHelloAsync(string.Format("-- {0} --", cnt));
Console.WriteLine(s);
}
static void Main(string[] args)
{
HelloServiceClient client = new HelloServiceClient("HelloService", "net.tcp://10.20.61.13:8080/hello");
List<Task> tasks = new List<Task>();
for(int i=0; i < 700; i++){
Task t = PrintNameAsync(client, i);
tasks.Add(t);
}
Task.WhenAll(tasks).Wait();
client.Close();
}
}
}
服务器的App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="HelloServiceBinding">
<reliableSession ordered="true" enabled="true" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000"
maxConcurrentInstances="1000" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="HelloServiceBehavior" name="HelloService">
<endpoint address="net.tcp://localhost:8080/hello" binding="netTcpBinding"
bindingConfiguration="HelloServiceBinding" name="HelloService" contract="IHelloService" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
客户端的App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="HelloServiceBinding" sendTimeout="00:01:00">
<reliableSession enabled="true" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:8080/hello" binding="netTcpBinding"
bindingConfiguration="HelloServiceBinding" contract="WcfServer.IHelloService"
name="HelloService">
</endpoint>
</client>
</system.serviceModel>
</configuration>
答案 0 :(得分:1)
您正在发送消息Async,但您已在ReliableSessionBindingElement上订购了=“true”。这没有意义。将ordered设置为false,因为它对您的场景更有意义。 ReliableMessaging将导致性能损失,因为它会将每个响应消息添加到SequenceAcknowledgement中。它还会增加CreateSequence / CreateSequenceResponse和CloseSequence / CloseSequenceResponse的开销,然后在会话的开头和结尾添加TerminateSequence / TerminateSequenceResponse消息交换。
答案 1 :(得分:1)
从以下链接找到问题的部分解决方法:
使用变通方法(使用WorkerThreadPoolBehavior),测量的吞吐量如下:
请注意,上述情况1从70毫秒/呼叫显着改善。但是,它仍然落后于案例2.对于案例3,引入WorkerThreadPool行为会导致性能从0.25毫秒/调用降至0.47毫秒/调用。
答案 2 :(得分:1)
看看这个......
“设置MaxTransferWindowSize
Windows Communication Foundation(WCF)中的可靠会话使用传输窗口来保存客户端和服务上的消息。可配置属性 MaxTransferWindowSize 表示传输窗口可以容纳多少条消息。
在发件人上,这表示在等待确认时传输窗口可以容纳多少条消息;在接收器上,它表示缓冲服务的消息数 ......“
来源“MSDN:可靠会话的最佳实践”: http://msdn.microsoft.com/en-us/library/ms733795.aspx