Почему производительность WCF такая низкая по сравнению с удаленным доступом? - PullRequest
4 голосов
/ 07 декабря 2010

Я пытаюсь оценить, какую коммуникационную технологию использовать в новой системе, сейчас похоже, что удаленное взаимодействие - наш единственный вариант, так как производительность WCF ужасна.

Я протестировал вызов службы WCF, размещенной в IIS7, с использованием nettcp, по сравнению с вызовом интерфейса удаленного взаимодействия, размещенного в консольном приложении. Службе WCF требуется ~ 4,5 секунды для выполнения 1000 запросов, синхронно с конечной точкой (которая просто возвращает новое мгновение объекта). Клиенту удаленного взаимодействия требуется менее 0,5 секунды для выполнения той же задачи.

Вот код клиента WCF:

public class TcpNewsService : INewsService
{
    private INewsService _service = null;

    Lazy<ChannelFactory<INewsService>> _newsFactory = new Lazy<ChannelFactory<INewsService>>(() =>
    {
        var tcpBinding = new NetTcpBinding
            {
                //MaxBufferPoolSize = int.MaxValue,
                //MaxBufferSize = int.MaxValue,
                //MaxConnections = int.MaxValue,
                //MaxReceivedMessageSize = int.MaxValue,
                PortSharingEnabled=false,
                TransactionFlow = false,
                ListenBacklog = int.MaxValue,
                Security = new NetTcpSecurity 
                { 
                    Mode = SecurityMode.None, 
                    Transport = new TcpTransportSecurity
                    {
                         ProtectionLevel = System.Net.Security.ProtectionLevel.None,
                         ClientCredentialType = TcpClientCredentialType.None
                    },
                    Message = new MessageSecurityOverTcp 
                    { 
                        ClientCredentialType = MessageCredentialType.None } 
                    },
                ReliableSession = new OptionalReliableSession { Enabled = false }
            };
        EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8089/NewsService.svc");
        return new ChannelFactory<INewsService>(tcpBinding, endpointAddress);
    });

    public TcpNewsService()
    {
        _service = _newsFactory.Value.CreateChannel();
        ((ICommunicationObject)_service).Open();

    }

    public List<NewsItem> GetNews()
    {
        return _service.GetNews();
    }
}

И простое консольное приложение для вызова кода клиента:

var client = new TcpNewsService();

Console.WriteLine("Getting all news");

var sw = new System.Diagnostics.Stopwatch();
sw.Start();

for (int i = 0; i < 1000; i++)
{
    var news = client.GetNews();
}
sw.Stop();

Console.WriteLine("Finished in " + sw.Elapsed.TotalSeconds);
Console.ReadLine();

Файл web.config для хоста IIS выглядит следующим образом:

<system.serviceModel>
<services>
  <service behaviorConfiguration="NewsServiceBehavior" name="RiaSpike.News.Service.NewsService">
    <endpoint address=""
          binding="netTcpBinding"
          bindingConfiguration="tcpBinding"
          contract="RiaSpike.News.Types.INewsService">
    </endpoint>
    <endpoint address="http://localhost:8094/NewsService.svc"
          binding="basicHttpBinding"
          bindingConfiguration="httpBinding"
          contract="RiaSpike.News.Types.INewsService">
    </endpoint>
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="NewsServiceBehavior">
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<bindings>
  <basicHttpBinding>
    <binding name="httpBinding">
      <security mode="None">
        <transport clientCredentialType="None" />
      </security>
    </binding>
  </basicHttpBinding>
  <netTcpBinding>
    <binding name="tcpBinding" portSharingEnabled="false">
      <security mode="None">
        <transport clientCredentialType="None" />
        <message clientCredentialType="None" />
      </security>
      <reliableSession enabled="false"  />
    </binding>
  </netTcpBinding>
</bindings>

И класс обслуживания, размещенный в IIS:

[ServiceBehavior(
    ConcurrencyMode = ConcurrencyMode.Multiple,
    InstanceContextMode = InstanceContextMode.Single,
    AddressFilterMode = AddressFilterMode.Any
)]

public class NewsService : MarshalByRefObject, INewsService
{

    public List<NewsItem> GetNews()
    {
        return new List<NewsItem> 
            { 
                new NewsItem { Descripion = "The Description", Id = 1, Title = "The Title"}
            };
    }
}

Я проследил активность WCF и увидел, что процесс занимает около 5 миллисекунд (я не смог загрузить анимацию, вот один след активности из журнала)

От: Обработка сообщения 5. Передача 3/12/2010 15: 35: 58.861
Граница деятельности. Старт 3/12/2010 15: 35: 58,861
Получил сообщение по каналу. Информация 3/12/2010 15: 35: 58,861
Кому: Выполнить перевод 'Ria.Spike.News.INewsService.GetNews' 3/12/2010 15: 35: 58.864
Граница деятельности. Приостановить 3/12/2010 15: 35: 58.864
От: Выполните перевод Ria.Spike.News.INewsService.GetNews 3/12/2010 15: 35: 58.864
Граница деятельности. Резюме 12.03.2010 15: 35: 58.864
Отправлено сообщение по каналу. Информация 3/12/2010 15: 35: 58.866
Граница деятельности. Стоп 3/12/2010 15: 35: 58,866

Это так хорошо, как это получается: s

Вот код удаленного взаимодействия, используемый в этом примере.

var  iserver = (INewsService)Activator.GetObject(typeof(INewsService), "tcp://127.0.0.1:9000/news");
var sw = new System.Diagnostics.Stopwatch();
sw.Start();

for (int i = 0; i < 1000; i++)
{
    var news = iserver.GetNews();
}

sw.Stop();

Console.WriteLine("Finished in " + sw.Elapsed.TotalSeconds);
Console.ReadLine();

И конечная точка TCP для хостинга этого удаленного канала в IIS:

public class Global : System.Web.HttpApplication
{
    private TcpServerChannel _quote; 

    protected void Application_Start(object sender, EventArgs e)
    {
        _quote = new TcpServerChannel(9000);
        if (ChannelServices.RegisteredChannels.Length ==0)
        {
            ChannelServices.RegisterChannel(_quote, false);    
        }


        RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(NewsService),
        "news",
        WellKnownObjectMode.SingleCall);

        _quote.StartListening(null);      
    }
}

1 Ответ

9 голосов
/ 07 декабря 2010

Тестирует последовательные, синхронные, только вызовы. Служба WCF, размещенная в IIS, предоставляет больше инфраструктуры для обработки более высокой нагрузки и, вероятно, превзойдет удаленное взаимодействие для теста с высокой нагрузкой (один с большим количеством одновременных подключений).

Конечная точка удаленного взаимодействия также может быть размещена в IIS, хотя для получения тех же преимуществ. WCF также может быть размещен в консоли. Вы действительно сравниваете яблоки с апельсинами здесь.

...