2012-10-23 30 views
3

对于实验,我在VS2012上创建了一个简单的“Hello World”WCF服务和使用.NET 4.5的客户端。服务器托管在控制台应用程序上,并使用net.tcp绑定。我编写了客户端代码向服务器发送突发异步请求(总共700个请求)。一切都很好,直到我打开服务的可靠会话功能。打开之后,服务突然跑得很慢,我的机器上花了差不多一分钟的时间完成700次请求。我试着微调Concurrency和Throttling参数(见下文),但它没有帮助。当可靠的会话开启并且突发异步请求时,WCF速度很慢

有谁知道为什么会发生这种情况?无论如何要避免这种情况?

如果我关闭Reliable会话功能,或者如果我使服务调用同步,则缓慢度不会发生。所以我认为它可能与WCF在WS-ReliableMessaging模式下处理未决请求的方式有关。

编辑:也没有发生,当我channetTcpBinding wsHttpBinding。这很奇怪,因为在这种情况下,wsHttpBinding比netTcpBinding快得多。

编辑:在服务器端运行Perfmon.exe显示在上述情况下,“线程计数”从8逐渐增加到100以上。

编辑:我的电脑(本地网络)上的一些测量吞吐量。看到案例1的表现非常缓慢,实际上没用。

  1. Async + NetTcpBinding /可靠的吞吐量 - >大约。 14呼叫/秒(70毫秒/呼叫)
  2. 异步+ WsHttp /可靠的吞吐量 - > 7957呼叫/秒(0.12毫秒/呼叫)
  3. 同步+ NetTcpBinding的/可靠吞吐率 - > 3986呼叫/秒(0.25毫秒/呼叫)

以下是我在实验中使用的服务器和客户端的代码和配置。

服务器:

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> 

回答

1

实测值从下面的链接针对该问题的部分解决办法:

随着解决方法(使用WorkerThreadPoolBehavior),所测量的吞吐量如下:

  1. Async + NetTcpBinding/Reliable t hroughput - > 474呼叫/秒(2.1毫秒/调用)......改善,但不能令人满意
  2. 异步+ WsHttp /可靠的吞吐量 - > 7856呼叫/秒(0.13毫秒/电话)......没有变化
  3. 同步+ NetTcpBinding/Reliable Throughput - > 2110 call/s 0.47 ms/call)...降级

请注意,上述情况1从70 ms/call显着提高。但是,它仍然滞后于情况2.而对于情况3,引入WorkerThreadPool行为会导致性能从0.25毫秒/调用降至0.47毫秒/调用。

1

你发送消息异步,但你已经下令= “真” 的ReliableSessionBindingElement。这没有意义。设置为false,因为它对您的场景更有意义。 ReliableMessaging会导致性能下降,因为它会为每个响应消息添加一个SequenceAcknowledgement。它还增加了CreateSequence/CreateSequenceResponse和CloseSequence/CloseSequenceResponse的开销,然后在会话开始和结束时TerminateSequence/TerminateSequenceResponse消息交换。

+0

感谢您的建议。然而,改变下令False没有帮助,完成700个请求仍需要将近1分钟(当Reliable为OFF或使用同步调用时,完成时间不到1秒) – nikoniko

+0

+1。reliableSession是并发的死敌。我打开它,并发请求被禁用(不管是否是顺序是真是假) - 这是什么导致大的减速。事实上,我已经看到订单=“真”时消息的乱序处理。 – morpheus

1

看这...

设置MaxTransferWindowSize

在Windows通讯基础(WCF)

可靠的会话使用转会窗口持有客户端和服务上的消息。该配置属性MaxTransferWindowSize表示传输窗口可以容纳多少条消息

在发件人上,这表示在等待确认时传输窗口可以容纳多少条消息;在接收器上表示多少消息服务缓冲......”

来源‘MSDN:为可靠的会话的最佳实践’: http://msdn.microsoft.com/en-us/library/ms733795.aspx