WCF是缓慢的,当可靠的会话是和突发异步请求 [英] WCF is slow when reliable session is ON and with burst async request

查看:400
本文介绍了WCF是缓慢的,当可靠的会话是和突发异步请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关的实验,我创建了一个简单的Hello WorldWCF在VS2012使用.NET 4.5的服务端​​和客户端。服务器托管在一个控制台应用程序并使用net.tcp绑定。我写的客户端code到发出一阵异步请求(共700请求)给服务器。一切都很好,直到我打开了服务的可靠的会话功能。后为ON,服务突然跑得很慢,花了将近一分钟,我的机器上,完成700请求。我试图微调的并发和节流的参数(见下文),但它并没有帮助。

有谁知道为什么出现这种情况?反正是有避免这种情况?

如果我关掉了可靠的会话功能,或者,如果我做了服务电话同步的缓慢并没有发生。因此,我认为这可能与WCF处理的WS-ReliableMessaging的模式挂起的请求的方式。

编辑:另外我chaned NetTcpBinding的到的wsHttpBinding这并没有发生。这是很奇怪的,因为在这种情况下的wsHttpBinding比NetTcpBinding的速度要快得多。

编辑:在服务器端运行的Perfmon.exe表明,线程计数逐渐从8在上述情况下增加至超过100

编辑:我的电脑(局域网)上的一些测量吞吐量。见这种情况下,1的表现非常低迷,实际上毫无用处。

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

以下是在codeS和配置为予实验中使用的服务器和客户端。

服务器:

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用System.Threading.Tasks;

使用System.ServiceModel;
使用System.ServiceModel.Description;

[的ServiceContract]
公共接口IHelloService
{
    [OperationContract的(IsOneWay = FALSE)]
    字符串的SayHello(字符串名称);
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,InstanceContextMode = InstanceContextMode.PerSession)
公共类HelloService的:IHelloService
{
    公共字符串的SayHello(字符串名称){
        字符串s =的String.Format(你好{0},名称);
        返回S;
    }
}

命名空间WcfServer
{
    类节目
    {
        静态无效的主要(字串[] args)
        {
            乌里baseAddress =新的URI(的net.tcp://本地主机:8080 /你好);
            使用(ServiceHost的主机=新的ServiceHost(typeof运算(HelloService中),baseAddress)){
                //打开并监听
                host.Open();
                Console.WriteLine(该服务已经准备好,在{0},baseAddress);
                Console.WriteLine(preSS<进入>停止服务);
                到Console.ReadLine();
                //关闭的ServiceHost。
                host.Close();
            }
        }
    }
}
 

客户端:

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用System.Threading.Tasks;

使用System.ServiceModel;
使用WcfClient.WcfServer;

命名空间WcfClient
{
    类节目
    {
        静态异步任务PrintNameAsync(HelloServiceClient客户端,INT CNT){
            字符串s =等待client.SayHelloAsync(的String.Format( -  {0}  - ,CNT));
            Console.WriteLine(多个);
        }

        静态无效的主要(字串[] args)
        {
            HelloServiceClient客户端=新HelloServiceClient(HelloService中,的net.tcp://10.20.61.13:8080 /你好);
            名单<任务>任务=新的名单,其中,任务>();
            的for(int i = 0; I< 700;我++){
                任务T = PrintNameAsync(客户端,我);
                tasks.Add(T);
            }
            Task.WhenAll(任务).Wait();
            client.Close();
        }
    }
}
 

服务器的App.config中:

 < XML版本=1.0编码=UTF-8&GT?;
<结构>
    <启动>
        < supportedRuntime版本=4.0版的SKU =NETFramework,版本= V4.5/>
    < /启动>
    < system.serviceModel>
        <绑定>
            < NetTcpBinding的>
                <绑定名称=HelloServiceBinding>
                    <有序的ReliableSession =真正的启用=真/>
                    <安全模式=无/>
                < /装订>
            < / NetTcpBinding的>
        < /绑定>
        <行为>
            < serviceBehaviors>
                <行为NAME =HelloServiceBehavior>
                    < serviceMetadata policyVersion =Policy15/>
                    < serviceDebug includeExceptionDetailInFaults =真/>
                    < serviceThrottling maxConcurrentCalls =1000maxConcurrentSessions =1000
                        maxConcurrentInstances =1000/>
                < /行为>
            < / serviceBehaviors>
        < /行为>
        <服务>
            <服务behaviorConfiguration =HelloServiceBehaviorNAME =HelloService的>
                <端点地址=的net.tcp://本地主机:8080 /你好绑定=NetTcpBinding的
                    bindingConfiguration =HelloServiceBindingNAME =HelloService的合同=IHelloService/>
                <端点地址=MEX绑定=mexTcpBinding合同=IMetadataExchange接口/>
            < /服务>
        < /服务>
    < /system.serviceModel>
< /结构>
 

客户端的App.config中:

 < XML版本=1.0编码=UTF-8&GT?;
<结构>
    <启动>
        < supportedRuntime版本=4.0版的SKU =NETFramework,版本= V4.5/>
    < /启动>
    < system.serviceModel>
        <绑定>
            < NetTcpBinding的>
                <绑定名称=HelloServiceBinding的SendTimeout =00:01:00>
                    <启用的ReliableSession =真/>
                    <安全模式=无/>
                < /装订>
            < / NetTcpBinding的>
        < /绑定>
        <客户端>
            <端点地址=的net.tcp://本地主机:8080 /你好绑定=NetTcpBinding的
                bindingConfiguration =HelloServiceBinding合同=WcfServer.IHelloService
                NAME =HelloService的>
            < /端点>
        < /客户>
    < /system.serviceModel>
< /结构>
 

解决方案

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

  • <一个href="http://blogs.msdn.com/b/endpoint/archive/2011/05/04/wcf-scales-up-slowly-with-bursts-of-work.aspx" rel="nofollow">http://blogs.msdn.com/b/endpoint/archive/2011/05/04/wcf-scales-up-slowly-with-bursts-of-work.aspx
  • http://support.microsoft.com/kb/2538826

通过解决方法(使用WorkerThreadPoolBehavior),测得的吞吐量如下:

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

请注意,以上的情况下1显著从70毫秒/呼叫改善。但是,它仍然从案例2.而对于案例3落后,引进WorkerThreadPool行为会导致性能下降,从0.25毫秒/呼叫0.47毫秒/呼叫。

For experiments, I created a simple "Hello World" WCF service and client using .NET 4.5 on VS2012. The server is hosted on a console application and use net.tcp binding. I wrote the client code to send a burst of async requests (a total of 700 requests) to the server. Everything went fine until I turned ON the Reliable session feature of the service. After it is ON, the service suddenly ran very slow and it took almost a minute on my machine to complete the 700 requests. I tried to fine tune the Concurrency and Throttling parameters (see below) but it didn't help.

Does anyone know why this happen ? Is there anyway to avoid this ?

The slowness didn't happen if I turned OFF the Reliable session feature, or if I made the service call synchronous. So I think it may relate to the way WCF handles pending requests in WS-ReliableMessaging mode.

EDIT: Also this didn't happen when I chaned netTcpBinding to wsHttpBinding. This is very weird because in this case wsHttpBinding is much faster than netTcpBinding.

EDIT: Running Perfmon.exe on the server side shows that the "Thread Count" gradually increase from 8 to beyond 100 in the above case.

EDIT: Some measured throughput on my PC (local network). See that the performance of case 1 is very sluggish and practically useless.

  1. Async + NetTcpBinding/Reliable throughput -> approx. 14 call/s (70 ms/call)
  2. Async + WsHttp/Reliable throughput -> 7957 call/s (0.12 ms/call)
  3. Sync + NetTcpBinding/Reliable throughtput -> 3986 call/s (0.25 ms/call)

Below are the codes and configuration for the server and client I used in the experiments.

Server:

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();
            }
        }
    }
}

Client:

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();
        }
    }
}

Server's 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>

Client's 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>

解决方案

Found a partial workaround for the problem from the below links:

With the workaround (using the WorkerThreadPoolBehavior), the measured throughputs are as follows:

  1. Async + NetTcpBinding/Reliable throughput -> 474 call/s (2.1 ms/call) ... improved but not satisfactorily
  2. Async + WsHttp/Reliable throughput -> 7856 call/s (0.13 ms/call) ... no change
  3. Sync + NetTcpBinding/Reliable throughtput -> 2110 call/s 0.47 ms/call) ... degraded

Note that the case 1 above is improved significantly from 70 ms/call. However, it still lags from case 2. And for case 3, introducing WorkerThreadPool behavior cause performance degradation from 0.25 ms/call to 0.47 ms/call.

这篇关于WCF是缓慢的,当可靠的会话是和突发异步请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆