WCF - Throttling and Pooling

Through the management of a service instance can define what form of creating an instance to serve a given request. This setting we make the level of service through a behavior , imposes no restriction on the amount of instance and / or concurrent executions are carried out, depending on the volume of requests that the service has or even the amount of resources it uses, can significantly degrade performance. 's Throttling allows restricting the amount of sessions, concurrent instances and calls that are made ​​to a service. Besides Throttling , there is another feature that can be used in a service, which is the pooling of objects, very common within the Enterprise Services (COM +) . This article will explain how to proceed to make configuration of Throttling and its implications;supercialmente also talk about the structure of the Pooling and how to implement it. Throttling would be very interesting to get to meet all the incoming requests to a service but unfortunately, due to the limitation of some features, it is not always possible. Each service (as well as any other application) is limited to the availability of the processor, memory, connection to the database, etc. A large number of calls causes a large number of instances a large number of concurrent access (depends on the management mode chosen instance) or be created. Each instance or each thread requires system resources to be able to perform the operation. To solve problems like these we have two alternatives: the first is to have a deleas hardware more powerful and able to meet all requests more if the amount of requests increase, need more hardware ; already the second alternative is to restrict access to such resources, limiting the number of concurrent calls and / or active sessions. If the limit is reached, requests are queued, waiting your turn or if it waits for the processing takes a long time, will fail bytimeout . WCF enables you to control these limits by throttling . Basically the idea Throttling is to limit the number of sessions, and concurrent instances of a service executions. This configuration is performed from a behaviorservice, ie, this setting will reflect on (s) instance (s) of service, regardless of endpoints . We have three properties that can set to specify this behavior:









  • MaxConcurrentInstances: This property specifies the maximum number of concurrent instances allowed for the service. When the instance management mode is set to Single , this information is irrelevant because there is only a single instance serving all requests; already on the way PerCall the number of instances is the same number of concurrent calls.
  • MaxConcurrentCalls: This property specifies the maximum number of concurrent messages that the service can process. The default value is set to 16.
  • MaxConcurrentSessions: This property specifies the maximum number of concurrent sessions that will enable the service. It is important to remember that customers are responsible for initializing or terminating sessions, performing several calls from this period. The problem is that the sessions long as they are long, or better, last, other customers may be blocked. The bindings that are under HTTP and are disabled with the session does not interfere in value because it does not maintain an active connection to the service, and consequently there will be no instance serving him. The default value is set to 10.
Configuring the Throttling directly affects the service regardless of which endpoint the request is coming.Therefore, the configuration can be done via configuration file or imperative form. In the declarative model used the element serviceThrottling , part of a behavior that is directly connected to a service; already in the imperative model, we used the class ServiceThrottlingBehavior ( System.ServiceModel.Description namespace ) that once configured, to add to the collection of behaviors exposed by the class ServiceHost . The code snippet below shows the two ways to configure the Throttling :
using System;
using System.ServiceModel;
using System.ServiceModel.Description;

using (ServiceHost host = new ServiceHost (typeof (ICliente) 
    new Uri [] {new Uri ("net.tcp: // localhost: 8377")}))
{
    // Configuring Endpoints

    ServiceThrottlingBehavior ServiceThrottlingBehavior t = new ();
    t.MaxConcurrentCalls = 40;
    t.MaxConcurrentInstances = 20;
    t.MaxConcurrentSessions = 20;
    host.Description.Behaviors.Add (t);

    host.Open ();

    Console.ReadLine ();
}


Configuring the Throttling should be held before the opening of the service. The equivalent setting to the above, but using the configuration file is shown below:


<? Xml version = "1.0" encoding = "utf-8"?>
<Configuration>
  <System.serviceModel>
    <Services>
      <Service name = "Host.ServicoDeClientes" behaviorConfiguration = "Config">
        <- Endpoints ->
      </ Service>
    </ Services>
    <Behaviors>
      <ServiceBehaviors>
        <Behavior name = "Config">
          <ServiceThrottling
            maxConcurrentCalls = "40"
            maxConcurrentInstances = "20"
            MaxConcurrentSessions = "20" />
        </ Behavior>
      </ ServiceBehaviors>
    </ Behaviors>
  </system.serviceModel>
</ Configuration>


Pooling 

already know that the runtime WCF creates instances of the class that represents the service to meet a particular request. The creation of instances will depend on the chosen mode of management, which was constantly discussed in this article . To recall, the way PerSession creates an instance for each client; already so PerCallcreates an instance per call and finally the mode Single creates a single instance. Creating and destroying instances all the time can be extremely costly, because sometimes there are difficult tasks that are performed at the time of startup. For a considerable gain in performance, we resort to a technique called pooling . This technique consists of, instead of destroying the object completely and remove it from memory put it in a repository for reuse it. This technique will also influence the management mode instances. When a request arrives for a service that is exposed via mode PerCall , WCF checks if there are "pre-made" objects in the pool to service the request. If yes, it will use that instance to serve the request. When the request to terminate, the object is returned to the pool and can be reused for future requests. When we use the mode PerSession , the semantics are the same, but the object will only be returned to the pool when the client logs. Already mode Single does not apply to pooling . For security and also consistency, returning an object to the pool , the data that are used by the same (internal fields) must be restarted. By default, WCF does not natively support the technique of pooling .With all the extensibility ( behavior ) that WCF has, it's easy to attach an extension to it to support the Pooling .Just as the customer owns the proxy , the service has the dispatcher *. For each endpoint have a dispatcher endpoint related, and is responsible for converting incoming messages to the service (more specifically for theendpoint ) in calls to the operations that the service provides and thereafter return a message containing the answer. * The client can also create a dispatcher, but it happens when we are using a duplex contract and is beyond the scope of this article. 's endpoint exposes a property called DispatchRuntime , type DispatchRuntime , which represents the dispatcher . This class, in turn, provides a property called InstanceProvider , which is where we can engage the object instance that will make the extraction and the return of classes (instances) of the service pool . This property gets an object that implements the interface IInstanceProvider (System.ServiceModel.Dispatcher namespace ) and we use when we define our own mechanism for creating instances. A IInstanceProvider Interface provides three members, which must necessarily be implemented in the class that manages the pool . Below is a table with the explanation for these three members, but it is important to say that the frequency for the call of the methods below is subject to management mode used by service instances (property InstanceContextMode attribute ServiceBehaviorAttribute ):














MethodDescription
GetInstanceWhen the message arrives to the dispatcher he will invoke this method to create a new instance of the class and then process it.
GetInstanceThe same purpose method GetInstance except that it is invoked when there is a class Message related to the current request.
ReleaseInstanceWhen the lifetime of an instance reaches the end, the dispatcher calls this method, passing the instance of the current object to decide what we will do with it. As we are creating a pool , we store it for later use.


The implementation of the pool consists of two steps: the first is the creation of the class that manages the pooland one class for acoplarmos the runtime WCF. As we already know, the class that will manage the pool must implement the interface IInstanceProvider ; to facilitate the work, we will create it in a generic way. Internally it will maintain a static member called _pool type Stack (LIFO collection of type ( Last-In First-Out )), which will store the instances to be reused. As is to be expected, the method GetInstance will check whether there is any item available within this collection, and if so, it will be used; otherwise a new instance is created (you do not need to add it to the collection before using it, because who will do this will be the method ReleaseInstance ).Implementation of the pool for purposes of example is not very complex. We use the methods Pop and Push theStack to remove or add an item, using each at the right time ( GetInstance and ReleaseInstance ). Moreover, the class is typified with TService , forcing it to be a class, and also has a default constructor. In addition to the methods provided by interface IInstanceProvider a named method was created CreateNewInstance , which returns a new instance of the class representing the service, if necessary. The code below shows the class in its entirety:




using System;
using System.Diagnostics;
using System.Collections;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

public class PoolInstanceProvider <TService>: 
    IInstanceProvider where TService: class, ICleanup, new ()
{
    private static object _lock = new object ();
    private static Stack _pool;

    static PoolInstanceProvider ()
    {
        _pool = new Stack ();
    }

    public object GetInstance (InstanceContext InstanceContext, Message message)
    {
        object obj = null;

        lock (_lock)
        {
            if (_pool.Count> 0)
            {
                _pool.Pop obj = ();
                Debug.WriteLine ("From Pool");
            }
            else
            {
                CreateNewInstance obj = ();
                Debug.WriteLine ("New Object");
            }
        }

        return obj;
    }

    public object GetInstance (InstanceContext InstanceContext)
    {
        throw new NotImplementedException ();
    }

    public void ReleaseInstance (InstanceContext InstanceContext, object instance)
    {
        lock (_lock)
        {
            ((ICleanup) instance) .Cleanup ();

            _pool.Push (instance);
        }
    }

    private static object CreateNewInstance ()
    {
        return new TService ();
    }
}


As we can see, the class PoolInstanceProvider makes use of a generic type called TService where TService must be typed with a class that represents the service. There are some conditions that the type that is specified in the parameter TService should satisfy: class (must be a class), ICleanup (must implement this interface ) and new(must have a constructor with no parameters). The ICleanup interface provides one method called Cleanup , which aims to restore the data (internal members) used by an instance before returning it to the pool . 's important to remember that the above class is just one example, for a world real, may need to be improved. With it created, remains to define the entry point for acoplarmos this class within the WCF. Just as the Throttling the Poolingshould also reflect to the service as a whole, regardless of which endpoint the request come and due to this, we create a behavior service, which leads us to implement the Interface IServiceBehavior in a class, more Specifically the method ApplyDispatchBehavior . This method provides the possibility to insert objects in implementing the WCF extensibility, allowing you to modify or inspect the host that is being built for the execution of the object that represents the service. instance of the host is provided as a parameter to this method and through it we have a collection of dispatchers related to it (remembering that there is a dispatcher for each endpoint ). Initially we will walk through the collection of dispatchers provided by the host and, from there, the collection of endpoints . Eachendpoint provides a property called DispatchRuntime that, as we saw above, is where the WCF transforms messages into objects. From this property we can bind the instance pool we created earlier through the propertyInstanceProvider . It is important to say that, as the same pool must meet all requests, you must set the same instance for all endpoints exposed by the host . The code below shows how to perform this configuration:






using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;

internal class PoolServiceBehavior <TService>: 
    IServiceBehavior where TService: class, ICleanup, new ()
{
    public void AddBindingParameters (ServiceDescription ServiceDescription, 
        ServiceHostBase ServiceHostBase, Collection <ServiceEndpoint> endpoints, 
        BindingParameterCollection bindingParameters) {}

    public void ApplyDispatchBehavior (ServiceDescription ServiceDescription, 
        ServiceHostBase ServiceHostBase)
    {
        PoolInstanceProvider <TService> pool = new PoolInstanceProvider <TService> ();

        foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
        {
            foreach (EndpointDispatcher ed in ((ChannelDispatcher) cdb) .Endpoints)
            {
                ed.DispatchRuntime.InstanceProvider = pool;
            }
        }
    }

    public void Validate (ServiceDescription ServiceDescription, 
        ServiceHostBase ServiceHostBase) {}
}


Finally, with all this infrastructure ready, we add the class instance PoolServiceBehavior the collection of behaviorsof the host service. Because it is a generic class, when creating your instance you must specify the same type of class that is being exposed by the service. The code below illustrates how to proceed to install the same on thehost :


using System;
using System.ServiceModel;
using System.ServiceModel.Description;

using (ServiceHost host = new ServiceHost (typeof (ServicoDeClientes) 
    new Uri [] {new Uri ("net.tcp: // localhost: 8377")}))
{
    host.Description.Behaviors.Add (new PoolServiceBehavior <ServicoDeClientes> ());

    // Endpoints

    host.Open ();
    Console.ReadLine ();
}


Note: As we already know, there are other ways to add a behavior , eg via the configuration file, or even via attribute, but this is beyond the scope of this article. Conclusion: This article explained how to proceed and what forms we have to tell the runtime WCF when and how to create the object instance that represents the service as well as the impact that these techniques cause. The settings we saw this article ( Throttling and Pooling ) considerably improves the performance of a service, but if used improperly, can harm rather than improve.

Comments

Popular posts from this blog

WCF - Transfer and Data Encoding

WCF - Managing Instances