Наша архитектура сервера приложений настроена таким образом, чтобы каждый вызов службы проходил через специально созданный маршрутизатор службы WCF - единый сервис, который распределяет входящие запросы на соответствующий сервис с использованием информации, встроенной в заголовок сообщения запросов.
У нас возникают проблемы с производительностью при использовании этого сервисного маршрутизатора WCF (тайм-ауты при нагрузочном тестировании с одновременными пользователями).Мы задаемся вопросом, происходит ли это из-за ошибки в маршрутизаторе, что мы неправильно настроили службы / IIS или ожидаемо - каждый вызов, проходящий через одну службу, звучит как потенциальная проблема.
Без маршрутизации мы можем обработать около 120 одновременных пользователей, прежде чем получим ошибки тайм-аута, и, хотя мы получаем тайм-ауты, IIS продолжает обрабатывать запросы.При использовании маршрутизатора IIS прекращает обработку запросов примерно с 20 одновременными пользователями и никогда не возобновляет обработку каких-либо запросов в течение всего остального нагрузочного тестирования.
Наш главный вопрос заключается в том, следует ли ожидать этого при использовании служебного маршрутизатора илидолжен ли IIS обрабатывать эту нагрузку так, как мы ее настроили?
Служба маршрутизации выглядит следующим образом:
/// <summary>
/// Generic service contract which can accept any WCF message.
/// </summary>
[ServiceContract]
public interface IServiceRouter
{
[OperationContract(Action = "*", ReplyAction = "*", AsyncPattern=false)]
Message ProcessMessage(Message requestMessage);
}
Реализация:
[ServiceBehavior(
InstanceContextMode = InstanceContextMode.PerCall,
ConcurrencyMode = ConcurrencyMode.Multiple,
AddressFilterMode = AddressFilterMode.Any,
ValidateMustUnderstand = false)]
public sealed class ServiceRouter : IServiceRouter
Операция ProcessMessage:
public Message ProcessMessage(Message requestMessage)
{
//Figure out the url of the downstream service
string serviceName = requestMessage.Headers.GetHeader<String>(ServiceNameMessageHeader, String.Empty);
string url = String.Format(_destinationUrlFormat, _destinationAppName, _destinationAppVersion, serviceName);
EndpointAddress endpointAddress = new EndpointAddress(url);
using (ChannelFactory<IServiceRouter> factory = new ChannelFactory<IServiceRouter>(_binding, endpointAddress))
{
factory.Endpoint.Behaviors.Add(new MustUnderstandBehavior(false));
IServiceRouter proxy = factory.CreateChannel();
using (proxy as IDisposable)
{
try
{
IClientChannel clientChannel = proxy as IClientChannel;
// invoke service
Message responseMessage = proxy.ProcessMessage(requestMessage);
return responseMessage;
}
catch (Exception ex)
{
// ...
}
}
}
}