Балансировка нагрузки в WCF (throttling)

Платформа Windows Communication Foundation используется практически в каждом проекте, требующим использования сетевых сервисов. Фактически, если в проекте стает необходимость исопльзовать сервисы, мы несомненно используем WCF непосредственно или опосредовано (например, используя ADO.NET Data Services). Обычно сервисы работают что называется "из коробки" и многие не заботятся о дополнительном конфигурировании сервиса. Однако, при построении сервисов, которые должны работать под нагрузкой приходится задумываться о более сложных параметрах.

Здесь я бы хотел в компактном виде привести основные сведения, которые нужно знать при настройке сервиса, работающего под нагрузкой.

ConcurrencyMode

Параметр, который определяет режим работы сервиса – сколько реальных потоков будут обрабатывать сообщения и выполнять действия. Этот параметр может принимать значения:

  • Single – сообщения обрабатываются последовательно в единственном потоке (значение по умолчанию).
  • Reentrant – аналогично Single с некоторыми ньюансами (см. MSDN).
  • Multiple – сообщения обрабатываются параллельно в нескольких потоках.

Также с этим параметром тесно связан параметр MaxConcurrentCalls, который ограничивает максимальное количество потоков обработки конкурирующих вызовов. Обычно параметр ConcurrencyMode задается при определении сервиса.

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }
}

InstanceContextMode

Очень важный параметр, который определяет каким способом создается объект на стороне сервиса для обслуживания запроса. Параметр может принимать следующие значения:

  • PerCall – создавать новый экземпляр сервиса на каждый вызов (значение по умолчанию).
  • PerSession – создавать новый экземпляр сервиса на каждую сессию.
  • Single – создавать единственный экземпляр сервиса, который будет обслуживать все запросы.

Понятно, что более эффективно использовать режим Single. При этом будет создан единственный объект сервиса и не нужно заботиться об использовании памяти и других ресурсов. Однако, в случаях, когда сервис содержит состояние, использовать режим Single невозможно. В этом случае можно ограничить количество одновременно существующих экземпляров сервиса параметром MaxConcurrentInstances. Также можно ограничить количество одновременно работающих сессий, это делается при помощи параметра MaxConcurrentSessions.

Обычно параметр InstanceContextMode задается при определении сервиса.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }
}

Кроме того, на параметры устойчивости приложения на внешние атаки могут влиять параметры, задающие квоты на различные параметры. Например, к таким квотам относятся настройки sendTimeout, receiveTimeout, maxReceivedMessageSize и т.д. Более подробно о них можно прочитать в MSDN.