WCF吞吐量低于预期

时间:2012-07-12 16:10:42

标签: wcf iis throughput throttling

我为帖子长度道歉,但有很多事情可能导致我的情况,我试图包括我根据其他帖子所做的所有设置更改。简而言之,我的WCF服务似乎一次被限制为3或4个并发客户端请求。如果我将应用程序池最大工作进程数设置得更高(大约10)或将服务行为ConcurrencyMode设置为Multiple,我的吞吐量会更好(快几倍)。然而,这些似乎是对真正问题的解决方法,带来了他们自己的问题。我错了,或者IIS是否能够在一个工作进程中调出我的WCF服务的许多实例(几十个或更多)以处理负载?我只是知道我在某个地方错过了一个设置,但我找不到它。

编辑:在尝试目前为止的建议时,我意识到我的数学是关闭吞吐量的。使用ForEach循环,我在服务器上获得的估计并发处理速度低于20s(每个任务持续时间*任务数/总运行时间)。对于正在进行的实际工作(睡眠10秒),这似乎仍然很低,但不再低得离谱。

第二次编辑:我将@ Pablo的评论标记为答案,因为他的回答加上他的链接给了我信息以显着提升表现(我认为大约3倍)。但是,我想提出后续问题 - 在WCF / IIS中处理并发请求的合理期望是什么?假设CPU,内存和IO不是瓶颈,处理请求的实际限制/期望(每个CPU)是多少?我正在寻找的是一个经验法则,它告诉我,如果不添加CPU(或工作流程),我可能不会获得更大的提升。再次感谢。

(在Windows 2008 Server上,由IIS托管,1个处理器)
WCF服务配置(缩写):

<?xml version="1.0"?>
<configuration>
  <configSections>
  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
    <services>
      <service name="FMHIRWCFSvc.IRService" behaviorConfiguration="IRServiceBehavior">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="Binding1" contract="FMHIRWCFSvc.IIRService" />
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="Binding1" maxReceivedMessageSize="104857600">
          <readerQuotas maxArrayLength="104857600"/>
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="IRServiceBehavior">
          <serviceMetadata httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceThrottling
              maxConcurrentCalls = "500"
              maxConcurrentSessions = "500"
              maxConcurrentInstances = "500"
            />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <applicationSettings>
    <FMHIRWCFSvc.Properties.Settings>
      <setting name="FMHIRWCFSvc_ir_dev_websvc_IRWebService40" serializeAs="String">
        <value>http://ir-dev-websvc/imageright.webservice/IRWebService40.asmx</value>
      </setting>
    </FMHIRWCFSvc.Properties.Settings>
  </applicationSettings>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="500"/>
    </connectionManagement>
  </system.net>
</configuration>

客户端配置(缩写):

<?xml version="1.0"?>
<configuration>
  <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IIRService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://{myserveraddress}/FMHIRWCFSvc/IRService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IIRService"
        contract="wcf_local.IIRService" name="BasicHttpBinding_IIRService" />
    </client>
  </system.serviceModel>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="500"/>
    </connectionManagement>
  </system.net>
</configuration>

客户端方法调用:

static void WCFTesting()
{
    ConcurrentQueue<Exception> exceptionList = new ConcurrentQueue<Exception>();
    int[] taskList = new int[250];
    Parallel.ForEach(taskList, theTask => 
    {
        try
        {
            // Create the WCF client
            BasicHttpBinding binding = new BasicHttpBinding {
                Security = { Mode = BasicHttpSecurityMode.Transport },
                SendTimeout = TimeSpan.FromSeconds(20)
            };
            EndpointAddress endpointAddress = new EndpointAddress("https://{myserveraddress}/FMHIRWCFSvc/IRService.svc");
            IRServiceClient wcfClient = new IRServiceClient(binding, endpointAddress);

            // Call wcf service method that sleeps 10 seconds and returns
            wcfClient.TestCall();
        }
        catch (Exception exception) {
            // Store off exceptions for later processing
            exceptionList.Enqueue(exception);
        }
    });
}

WCF服务代码:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
...
public string TestCall()
{
    Thread.Sleep(10000);
    return null;
}

感谢您的任何见解或建议!

2 个答案:

答案 0 :(得分:1)

您使用的测试机制可能不完全正确。

使用Parallel.For()并不意味着它将并行创建250名工作人员。在这种情况下,您似乎将基准测试限制为客户端处理器配置的最佳值,而不是实际测试服务器可以处理的内容。

如果你真的想要调用250个并行线程并看看它是如何反应的,你可以手动创建所有线程。如:

        var exceptionList = new ConcurrentQueue<Exception>();
        const int max = 250;
        int numberOfTasks = max;
        var signal = new ManualResetEvent(false);
        for (var i = 0; i < max; i++)
        {
            var thread = new Thread(() =>
            {
                try
                {
                    // Create the WCF client
                    BasicHttpBinding binding = new BasicHttpBinding
                    {
                        Security = { Mode = BasicHttpSecurityMode.Transport },
                        SendTimeout = TimeSpan.FromSeconds(20)
                    };
                    EndpointAddress endpointAddress = new EndpointAddress("https://{myserveraddress}/FMHIRWCFSvc/IRService.svc");
                    IRServiceClient wcfClient = new IRServiceClient(binding, endpointAddress);

                    // Call wcf service method that sleeps 10 seconds and returns
                    wcfClient.TestCall();
                }
                catch (Exception exception)
                {
                    // Store off exceptions for later processing
                    exceptionList.Enqueue(exception);
                }

                if (Interlocked.Decrement(ref numberOfTasks) == 0) signal.Set();
            });
            thread.Start();
        }
        signal.WaitOne();

答案 1 :(得分:0)

Parallel.ForEachTask.Start的代码大致相同。不保证任务同时运行。

最好使用对WCF服务link的异步调用进行测试。