Wednesday, May 23, 2012

Dynamic WCF Throttling Behavior


WCF provides some advanced configuration opportunities to allow for performance tuning of services.  The throttling behavior allows you to configure the throughput of the service so it can be scaled to the resident processor.  The configurable attributes are:

maxConcurrentCalls: The total number of calls that can currently be in progress across all service instances. The default is 16.  Sometimes it is better to wait a couple of ticks than to allow another large process to start.

maxConcurrentInstances:  The number of InstanceContext objects that execute at one time across a ServiceHost. The default is Int32.MaxValue.

maxConcurrentSessions:  A positive integer that limits the number of sessions a ServiceHost object can accept. The default is 10.

From what I have read, the default configuration is not really wired up for a high demand environment.  It seems that the best way to target these settings is to target them at the server hardware on which you have deployed the services.  Most of the experts on the subject seem to agree that you should base these settings on the number of processors on the target machine.  The recommended settings for .NET 4.0 WCF services are maxConcurrentSessions = 100 * ProcessorCount, maxConcurrentCalls=16* ProcessorCount, maxConcurrentinstances=116 * ProcessorCount.  This is obviously problematic for a commercial software vendor since we have no knowledge of our customer machines.  Since these are so varied and fact dependent upon production environment, I thought a more dynamic approach would be a useful exercise.

I have created a class that will take the service interface name and return to you a behavior class.  The idea here is that it will dynamically find the number of processors on the machine, use your default settings for multipliers and then look in the config file for a service specific modifier for the multiplier override in case you want to configure a specific service to act independently.

First, create a static class to dynamically build a throttling behavior:

public static class ThrottleBuilder
{
   public static ServiceThrottlingBehavior BuildThrottler(String serviceName)
   {
      // check config for service specific multipliers
      Int32 maxConcurrentCalls = 
            Convert.ToInt32(ConfigurationManager.AppSettings[serviceName + "maxCallsMultiplier"] ?? "16");
      Int32 maxConcurrentSessions = 
            Convert.ToInt32(ConfigurationManager.AppSettings[serviceName + "maxSessionssMultiplier"] ?? "100");
      Int32 maxConcurrentInstances = 
            Convert.ToInt32(ConfigurationManager.AppSettings[serviceName + "maxInstancessMultiplier"] ?? "116");
 
       // build new throlttling behavior
       ServiceThrottlingBehavior throttle = new ServiceThrottlingBehavior();
       throttle.MaxConcurrentCalls = (maxConcurrentCalls * Environment.ProcessorCount);
       throttle.MaxConcurrentSessions = (maxConcurrentSessions * Environment.ProcessorCount);
       throttle.MaxConcurrentInstances = (maxConcurrentInstances * Environment.ProcessorCount); 
 
       return throttle;
 
   }
}
>
Then, leverage it as you attach the service to the host.
// crete service host
ServiceHost host = new ServiceHost(typeof(TestService));
 
// if host has behaviors, remove them.
if (host.Description.Behaviors.Count != 0)
{
    host.Description.Behaviors.Clear();
}
// add dynamically created throttle behavior
host.Description.Behaviors.Add(ThrottleBuilder.BuildThrottler("TestService"));
            
//open host
host.Open();

With this class and creation approach, you will be able to dynamically configure your throttle behavior at runtime based on the current environment.  This also gives you the benefit of additional configuration opportunities to troubleshoot or tweak the behavior for a specific customer installation.  Hopefully, you will find this useful and set yourself up to scale to any customer server configuration.

4 comments: