2012-07-12 120 views
3

对于帖子长度,我表示歉意,但有很多事情可能会导致我的情况,并且我试图根据其他帖子包含所做的所有设置更改。简而言之,我的WCF服务似乎一次只限制3个或4个并发客户端请求。如果我将应用程序池Maximum Worker Processes设置得更高(大约10)或将服务行为ConcurrencyMode设置为Multiple,则我可以获得更好的吞吐量(几倍更快)。然而,这些看起来像解决真正的问题,带来他们自己的问题。我误解了,还是应该IIS能够在一个工作进程中调用我的WCF服务的许多实例(数十个或更多)来处理负载?我只知道我错过了某个地方的设置,但我找不到它。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; 
} 

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

回答

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(); 
+0

感谢您的帮助。当我使用手动线程创建代码时,我确实得到了并发的提升(估计低30s而不是20s),但不是我希望的跳跃,就像允许许多IIS工作进程(web garden)一样。我的想法是,如果增加员工流程的数量会大大提高绩效,那么客户并不是瓶颈。如果服务器硬件不征税(CPU使用率低,内存使用率低,I/O活动低),还有什么可能会限制吞吐量?我真的是最大化WCF服务,我的下一步是更多的工作流程? – 2012-07-13 16:34:09

+0

我认为一个问题可能与WCF和IIS如何处理ThreadPool有关。长时间运行的请求(特别是在突发期间)存在固有的问题,因为池中的线程数量非常少。有一个彻底的帖子[这里](http://www.codeproject.com/Articles/234085/Fixing-WCF-to-build-highly-scalable-async-REST-API)分析WCF的线程行为,一些建议,作为以及来自Microsoft的其他建议:http://support.microsoft.com/kb/2538826,http://blogs.microsoft.co.il/blogs/idof/archive/2011/05/05/problems-with-wcf -scaling.aspx – 2012-07-13 20:51:02

+0

感谢您的链接。我没有阅读(并理解)所有的链接,但是我可以通过IOCP线程创建解决方法链接将性能提高一倍。这使我用我的测试方法平均处理了78个并发处理的请求。我现实世界的场景同时在35个左右。我想我已经耗尽了所有实用的编程解决方案,需要更多地关注服务器管理解决方案。 – 2012-07-16 21:03:09

0

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

更好地测试异步调用WCF服务link

+0

感谢您的回答。你是对的,异步会让客户端处理的不仅仅是Parallel.ForEach。在我寻找并行进程的禁食方法中,我编写了一些测试客户端应用程序,发现手动线程创建给了我最大的吞吐量,其次是异步调用,接着是Parallel.Foreach。不过,我认为我目前的瓶颈在服务器上,因为使用Parallel.ForEach添加工作进程显着提高了单个测试客户端应用程序的吞吐量。 – 2012-07-13 16:40:43