Answered by:
Hitting service throttling on webhttp endpoint but not net.tcp endpoint - self hosted scenario

Question
-
Hi
I have a WCF service that needs to handle bursty traffic (several hundred requests will arrive concurrently every morning when people turn on their machine.
I added service throtting to the service behavior configuration, which instantly resolved the issue for my net.tcp endpoint. However, for my webhttp endpoint, adding the throttling configuration changed nothing whatsoever. So I built my own load simulator and verified this behavior. I found articles suggesting that the threadpool has something to do with it, so when in order to work around the issue I'm now calling ThreadPool.SetMinThreads and set it to the number of concurrent requests I expect in burst mode - that resolved the issue, but still has me wondering why the throttling configuration would work for .net.tcp endpoints but not webhttp endpoints.
Here's the relevant entries from my app.config
<system.serviceModel> <diagnostics performanceCounters="All" /> <bindings> <wsHttpBinding> </wsHttpBinding> <basicHttpBinding> </basicHttpBinding> <netTcpBinding> <binding name="SmartAppServerBinding" closeTimeout="00:01:00" openTimeout="00:01:00" hostNameComparisonMode="WeakWildcard" maxConnections="50000" receiveTimeout="24:00:00" maxBufferSize="20971520" maxBufferPoolSize="20971520" maxReceivedMessageSize="20971520" listenBacklog="50000" transactionFlow="false" portSharingEnabled="false"> <readerQuotas maxDepth="128" maxStringContentLength="1048576" maxArrayLength="3145728" maxBytesPerRead="49152" maxNameTableCharCount="374784" /> <security mode="None"> <transport clientCredentialType="None" protectionLevel="None" /> </security> <!--<reliableSession ordered="False" enabled="True" inactivityTimeout="01:00:00"/>--> </binding> </netTcpBinding> <webHttpBinding> <binding name="SmartAppMobileClientBinding" bypassProxyOnLocal="true" useDefaultWebProxy="false" sendTimeout="00:20:00" openTimeout="00:20:00" receiveTimeout="00:20:00" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" > <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> <!--<security mode="Transport"> <transport clientCredentialType="Certificate" proxyCredentialType="None"></transport> </security>--> </binding> <binding closeTimeout="00:20:00" openTimeout="00:20:00" sendTimeout="00:20:00" receiveTimeout="00:20:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" maxBufferSize="2147483647"> <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> </binding> <binding name="TestWebBinding"> <security mode="Transport"> <transport clientCredentialType="None" /> </security> </binding> </webHttpBinding> </bindings> <client> </client> <behaviors> <serviceBehaviors> <behavior name="IncludeExceptionDetails"> <serviceDebug includeExceptionDetailInFaults="true" /> <dataContractSerializer maxItemsInObjectGraph="2147483647" /> <serviceThrottling maxConcurrentCalls="2147483647" maxConcurrentInstances="2147483647" maxConcurrentSessions="2147483647" /> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="webHttpBehavior"> <webHttp /> </behavior> <behavior name="webHttpWithHelpAndAutoFormatSelection"> <webHttp automaticFormatSelectionEnabled="false" helpEnabled="true" defaultOutgoingResponseFormat="Json" /> </behavior> </endpointBehaviors> </behaviors> <services> <service behaviorConfiguration="IncludeExceptionDetails" name="SmartAppServer.SmartAppServer"> <endpoint address="net.tcp://localhost:8088/SmartAppServer" binding="netTcpBinding" bindingConfiguration="SmartAppServerBinding" contract="ClientInterface.IPhoneClient"> <identity> <servicePrincipalName value="SmartAppServer" /> </identity> </endpoint> <endpoint address="http://localhost:8090" binding="webHttpBinding" bindingConfiguration="SmartAppMobileClientBinding" contract="SmartAppMobileClientInterface.ISmartAppMobile" behaviorConfiguration="webHttpWithHelpAndAutoFormatSelection"> <identity> <servicePrincipalName value="SmartAppServer" /> </identity> </endpoint> </service> </services> </system.serviceModel>
I have no throttling whatsoever on the net.tcp endpoint, and heavy throttling on the webHttp endpoint on port 8090 unless I reconfigure the threadpool to allow the number of concurrent threads I need from the getgo. As it is not recommended to manipulate the threadpool, I'd like to find out if there's another way to "unthrottle" the webhttp endpoint.
My Service is a singleton by the way allowing for multiple concurrency:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
(the same class implements both interfaces due to a legacy architecture).
Wednesday, July 2, 2014 9:54 AM
Answers
-
Hi,
>> I wondering why the throttling configuration would work for .net.tcp endpoints but not webhttp endpoints.
It seems that because we can set the specifies the maximum number of outbound and inbound connections the service creates and accepts respectively for statefull TCP connections like netTcpBinding and but can not do that for the stateless HTTP protocols like basicHttpBinding, wsHttpBinding or webHttpBinding.
For more information, please try to refer to:
#WCF Throttling:
http://www.lybecker.com/blog/2010/10/11/wcf-throttling-%e2%80%93-part-2/ .
Best Regards,
Amy Peng
We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
Click HERE to participate the survey.- Edited by Amy PengMicrosoft employee Friday, July 4, 2014 6:41 AM
- Proposed as answer by dns jinung Friday, July 11, 2014 9:35 AM
- Marked as answer by Amy PengMicrosoft employee Monday, July 14, 2014 1:42 AM
Friday, July 4, 2014 6:34 AM -
Maybe you have to use the ThreadPool.SetMinThreads and set it to the number of concurrent requests as what you do in your first question.
Thanks.
- Proposed as answer by dns jinung Friday, July 11, 2014 9:35 AM
- Marked as answer by Amy PengMicrosoft employee Monday, July 14, 2014 1:42 AM
Friday, July 11, 2014 9:35 AM
All replies
-
You can use single class to setup your wcf service and discard interface. You need to add global.asax file also. After you make the second call, all of them will return "finished".
This configuration does what you want. Create TestService.cs with :
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)] [ServiceContract(SessionMode = SessionMode.NotAllowed)] public class TestService { private static ManualResetEvent done = new ManualResetEvent(false); [OperationContract] [WebGet(UriTemplate = "test?id={id}")] public string Test(int id) { if (id == 1) { done.Reset(); done.WaitOne(); } else { done.Set(); } return "finished"; } }
web.config:
<configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true" /> </system.webServer> <system.serviceModel> <standardEndpoints> <webHttpEndpoint> <!-- Configure the WCF REST service base address via the global.asax.cs file and the default endpoint via the attributes on the <standardEndpoint> element below --> <standardEndpoint name="" helpEnabled="false" > </standardEndpoint> </webHttpEndpoint> </standardEndpoints> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> <serviceMetadata httpGetEnabled="true" /> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel> </configuration>
Global.asax file:
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { RouteTable.Routes.Add(new ServiceRoute("testservice", new WebServiceHostFactory(), typeof(TestService))); } }
Thursday, July 3, 2014 7:22 AM -
You must have missed the "self hosted" bit on the title... this is NOT running on an IIS, it is self hosted, so with the usual
private bool startClientHostAsync() { try { clientHost = new ServiceHost(this); clientHost.UnknownMessageReceived += clientHost_UnknownMessageReceived; clientHost.Opened += clientHost_Opened; clientHost.BeginOpen(eventHostOpened, null); return true; } catch (Exception e) { Log("Unable to initialize service host for clients: " + e.Message, 1); return false; } }
(I'm not showing the other events.. standard boilerplate code to run a WCF service in an application).
As it is not IIS hosted, there's no global.asax.cs, and I cannot use InstanceContextMode.PerCall (the reasons are in post 1), and SessionMode = SessionMode.NotAllowed is a nogo.. my net.tcp is duplex so I need the session.
Your modified configuration above (I understand the comments about mex and debugging stuff.. but it doesn't address the problem at hand) will also be subject to the standard throttling in WCF (and for a useful load test, you'd have to do something like Task.Delay(10000); inside the Test() method and then send a couple 1000 concurrent requests and you should see the outstanding requests pile up.
My question was and is: Why is the webHttp endpoint in the Service SmartAppServer.SmartAppServer subject to throttling whereas the net.tcp endpoint under the same service is not and how do I need to change the configuration (a complete rewrite with separate classes implementing the interfaces, percall, etc. is out of the question.. (refactoring is coming, in fact I'm throwing WCF out, but it's not ready yet and my problem is more immediate).
Thursday, July 3, 2014 8:43 AM -
Hi,
>> I wondering why the throttling configuration would work for .net.tcp endpoints but not webhttp endpoints.
It seems that because we can set the specifies the maximum number of outbound and inbound connections the service creates and accepts respectively for statefull TCP connections like netTcpBinding and but can not do that for the stateless HTTP protocols like basicHttpBinding, wsHttpBinding or webHttpBinding.
For more information, please try to refer to:
#WCF Throttling:
http://www.lybecker.com/blog/2010/10/11/wcf-throttling-%e2%80%93-part-2/ .
Best Regards,
Amy Peng
We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
Click HERE to participate the survey.- Edited by Amy PengMicrosoft employee Friday, July 4, 2014 6:41 AM
- Proposed as answer by dns jinung Friday, July 11, 2014 9:35 AM
- Marked as answer by Amy PengMicrosoft employee Monday, July 14, 2014 1:42 AM
Friday, July 4, 2014 6:34 AM -
So what is the solution for stateless connections? I doubt webhhhtp is inheritently limited to just a few dozend concurrent connections.Friday, July 4, 2014 7:32 AM
-
Maybe you have to use the ThreadPool.SetMinThreads and set it to the number of concurrent requests as what you do in your first question.
Thanks.
- Proposed as answer by dns jinung Friday, July 11, 2014 9:35 AM
- Marked as answer by Amy PengMicrosoft employee Monday, July 14, 2014 1:42 AM
Friday, July 11, 2014 9:35 AM