非常糟糕的WCF往返时间,线程更多

时间:2016-03-04 09:25:39

标签: c# multithreading wcf

我编写了一个WCF应用程序,其中客户端,服务器在同一台机器上运行。 线程很少(<10),平均往返时间(客户端 - >服务器 - >客户端)为400毫秒。 如果我将线程增加到200,那么平均往返时间会增加到50秒。

我的WCF服务使用basicHttp,Per-call,并发500个连接。 服务托管在控制台中。客户端使用该接口并通过使用ChannelFactory打开Channel来与服务通信。 服务器,客户端之间交换的数据最多为5 MB。

服务器app.config

<system.serviceModel>
<behaviors>
  <serviceBehaviors>
    <behavior name="serviceBehavior1">
      <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:3999/TestWCFService/" httpsGetEnabled="false" httpsGetUrl="https://http://localhost:3999/TestWCFService/"/>
      <serviceDebug includeExceptionDetailInFaults="true" />
      <serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500" maxConcurrentInstances="500" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<bindings>
  <basicHttpBinding>
    <binding name="basicHttp" openTimeout="02:00:00" receiveTimeout="21:00:00" sendTimeout="21:00:00" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
      <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" />
    </binding>
  </basicHttpBinding>
</bindings>
<services>
  <service behaviorConfiguration="serviceBehavior1" name="TestWCF.TestWCFServer">
    <endpoint address="http://localhost:3999/TestWCFService/" binding="basicHttpBinding" bindingConfiguration="basicHttp"
      name="TestWCFServiceEndpoint" contract="TestWCF.ITestWCFInterface">
      <identity>  <dns value="localhost"/>  </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <host>
        <baseAddresses>  <add baseAddress="http://localhost:3999/TestWCFService/"/> </baseAddresses>
    </host>
  </service>
</services>

服务器代码(参数Geometry,EntityDataFilter在一个单独的DLL中定义,在客户端,服务器中作为引用添加)

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
internal class TestWCFServer : ITestServiceInterface
{
  public IList<EntityData> fetchEntityData(Geometry boundary, EntityDataFilter filter, string clientID)
  {
    // Fetch the EntityData from database inmemory cache with the given inputs.
    // I have a timer inside the whole method. This whole method is taking ~4 milli seconds.
  }
}

// Main class that starts the server
public static class TestWCFMain
{
  static void Main()
  {
    using (ServiceHost host = new ServiceHost(typeof(VSCacheService)))
    {
        host.Open();
        Log.Info("Server is UP !!!");
        Log.Info("<Press enter to shutdown server>");               

        Console.ReadLine();
    }
  }
}

客户端应用配置

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="basicHttp" openTimeout="02:00:00" receiveTimeout="21:00:00" sendTimeout="21:00:00"
           maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
       <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" />
    </binding>
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="http://localhost:3999/TestWCFService/" binding="basicHttpBinding"
      bindingConfiguration="basicHttp" contract="TestWCF.ITestWCFInterface" name="TestWCFServiceEndpoint" kind="" endpointConfiguration="" />
</client>

客户端代码(参数Geometry,EntityDataFilter在一个单独的DLL中定义,在客户端,服务器中作为引用添加)

void fetchEntityDataFromServer(Geometry boundary, EntityDataFilter filter, string clientID)
{
    var channelFactor = new ChannelFactory<ITestWCFInterface>("TestWCFServiceEndpoint");
    channelFactor.Open();

    var proxy = channelFactor.CreateChannel();

    IList<EntityData> res = proxy.fetchEntityData(Geometry boundary, EntityDataFilter filter, string clientID);
}

我被困在这里。任何前进的指示都将是一个很大的帮助。 提前谢谢..

2 个答案:

答案 0 :(得分:1)

我使用我的WCF服务用200个线程执行一些测试。 客户端和服务放在同一个操作系统上。

客户端: 200个线程,20 x调用服务方法

<强>服务

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

  <wsHttpBinding>
    <binding name="WSHttpBinding" sendTimeout="00:00:30" transactionFlow="false" maxReceivedMessageSize="2147483647">
      <security mode="None">
        <message clientCredentialType="None" establishSecurityContext="false" negotiateServiceCredential="false" />
        <transport clientCredentialType="None" />
      </security>
    </binding>
  </wsHttpBinding>
不同服务方法变体的

结果

  1. <强> Thread.sleep代码(10)

    • 平均客户响应时间:~11ms
  2. 1MB 随机字符串的响应

    • 平均响应时间:~1.5min
    • CPU使用率:~90-93%
  3. 1MB const字符串的响应

    • 平均响应时间:~450ms
    • CPU使用率:~75-80%
  4. 5MB 随机字符串的响应

    • 平均响应时间:~6min
    • CPU使用率:~95-99%
  5. 5MB const字符串的响应

    • 平均响应时间:~1,7min
    • CPU使用率:~75-80%
  6. <强>猜疑: 每次通话= 5MB响应?如果是,则听起来像序列化/传输的大量数据。在我看来,这只是硬件限制。

    <强>建议:

    1. 不要打开工厂。 channelFactory.Open()
    2. 检查频道工厂缓存选项或自行缓存。
    3. 尝试使用wsHttpBinding
    4. 从理论上讲更慢security mode="None"
    5. 如果客户端和服务器在同一操作系统上运行,请尝试NetNamedPipeBinding

答案 1 :(得分:0)

您应该尝试增加WCF设置的客户端代码的并发连接数。我认为线程正在等待,直到建立连接,从而提高平均吞吐量。

请参阅此帖子以及示例:Multiple concurrent WCF calls from single client to Service

相关问题