.net - 当可靠 session 打开并且突发异步请求时,WCF 很慢

标签 .net wcf nettcpbinding ws-reliablemessaging

对于实验,我在 VS2012 上使用 .NET 4.5 创建了一个简单的“Hello World”WCF 服务和客户端。服务器托管在控制台应用程序上并使用 net.tcp 绑定(bind)。我编写了客户端代码来向服务器发送大量异步请求(总共 700 个请求)。一切都很顺利,直到我打开服务的可靠 session 功能。开启后,服务突然跑得很慢,在我的机器上花了将近一分钟才完成 700 个请求。我尝试微调 Concurrency 和 Throttling 参数(见下文),但没有帮助。

有谁知道为什么会这样?有没有办法避免这种情况?

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

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

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

编辑:我的电脑(本地网络)上的一些测量吞吐量。看到案例 1 的性能非常缓慢并且几乎没有用处。

  • 异步 + NetTcpBinding/可靠吞吐量 -> 大约。 14 次调用/秒(70 毫秒/次调用)
  • 异步 + WsHttp/可靠吞吐量 -> 7957 call/s (0.12 ms/call)
  • 同步 + NetTcpBinding/可靠吞吐量 -> 3986 call/s (0.25 ms/call)

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

    服务器:
    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>
    

    最佳答案

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

  • 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),测得的吞吐量如下:
  • Async + NetTcpBinding/Reliable 吞吐量 -> 474 call/s (2.1 ms/call) ... 改进但不令人满意
  • 异步 + WsHttp/可靠吞吐量 -> 7856 call/s (0.13 ms/call) ... 没有变化
  • 同步 + NetTcpBinding/可靠吞吐量 -> 2110 call/s 0.47 ms/call) ... 降级

  • 请注意,上述案例 1 比 70 毫秒/调用显着提高。但是,它仍然落后于案例 2。对于案例 3,引入 WorkerThreadPool 行为会导致性能从 0.25 毫秒/调用下降到 0.47 毫秒/调用。

    关于.net - 当可靠 session 打开并且突发异步请求时,WCF 很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13028717/

    相关文章:

    .net - 3D 世界中最通用的轴方向是什么?

    wcf - 已超出传入消息的最大消息大小配额(明显修复无济于事)

    c# - 使用非单向方法的 WCF 中的竞争条件

    c# - "using"关键字是否意味着对象已被处置并被 GC 处理?

    c# - 自删除 C# 应用程序

    c# - 是否可以从 UWP 应用程序格式化/创建分区?

    silverlight - Silverlight 4 中对 EF 实体的输入验证

    c# - 我们是否需要处理资源以及为什么我们需要在 WCF 中

    c# - Microsoft.Http.dll 和相关引用

    WCF 服务调用使用 basicHttpBinding 但因 netTcpBinding 失败