当可靠会话开启且具有突发异步请求时,WCF速度很慢

时间:2012-10-23 10:45:23

标签: .net wcf nettcpbinding ws-reliablemessaging

对于实验,我在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的表现非常缓慢,实际上没用。

  1. Async + NetTcpBinding /可靠的吞吐量 - >约。 14个呼叫/秒(70毫秒/呼叫)
  2. Async + WsHttp /可靠的吞吐量 - > 7957呼叫/秒(0.12毫秒/呼叫)
  3. Sync + NetTcpBinding / Reliable throughtput - > 3986呼叫/秒(0.25毫秒/呼叫)
  4. 以下是我在实验中使用的服务器和客户端的代码和配置。

    服务器

    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>
    

3 个答案:

答案 0 :(得分:1)

您正在发送消息Async,但您已在ReliableSessionBindingElement上订购了=“true”。这没有意义。将ordered设置为false,因为它对您的场景更有意义。 ReliableMessaging将导致性能损失,因为它会将每个响应消息添加到SequenceAcknowledgement中。它还会增加CreateSequence / CreateSequenceResponse和CloseSequence / CloseSequenceResponse的开销,然后在会话的开头和结尾添加TerminateSequence / TerminateSequenceResponse消息交换。

答案 1 :(得分:1)

从以下链接找到问题的部分解决方法:

使用变通方法(使用WorkerThreadPoolBehavior),测量的吞吐量如下:

  1. Async + NetTcpBinding /可靠的吞吐量 - &gt; 474呼叫/秒(2.1毫秒/呼叫)......改进但不令人满意
  2. Async + WsHttp /可靠的吞吐量 - &gt; 7856呼叫/秒(0.13毫秒/呼叫)......无变化
  3. Sync + NetTcpBinding / Reliable throughtput - &gt; 2110呼叫/秒0.47毫秒/呼叫)...降级
  4. 请注意,上述情况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