与 Remoting 相比,为什么 WCF 性能如此之慢?

发布于 2024-10-07 00:07:10 字数 5817 浏览 0 评论 0原文

我正在尝试评估在新系统中使用哪种通信技术,目前看来远程处理是我们唯一的选择,因为 WCF 的性能很糟糕。

我对使用 nettcp 调用 IIS7 中托管的 WCF 服务与调用控制台应用程序中托管的远程接口进行了基准测试。 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();

IIS 主机的 web.config 文件如下所示:

<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
活动边界。开始时间 2010 年 3 月 12 日 15:35:58.861
通过频道收到一条消息。信息 3/12/2010 15:35:58.861
至:执行“Ria.Spike.News.INewsService.GetNews”传输 3/12/2010 15:35:58.864
活动边界。暂停 2010 年 3 月 12 日 15:35:58.864
来自:执行“Ria.Spike.News.INewsService.GetNews”传输 3/12/2010 15:35:58.864
活动边界。简历 3/12/2010 15:35:58.864
通过信息频道发送消息 3/12/2010 15:35:58.866
活动边界。 Stop 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();

以及托管在 IIS 中的此远程处理通道的 TCP 端点:

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);      
    }
}

I'm trying to evaluate which communication technology to use in a new system, right now it looks like Remoting is our only option as WCF's performance is terrible.

I have benchmarked calling a WCF service hosted in IIS7 using nettcp, compared to calling a remoting interface hosted in a console app. The WCF service takes ~4.5 seconds to perform 1000 requests, synchronusoly on an endpoint (which simply returns back a new instantce of an object). The remoting client takes < 0.5 second to perform the same task.

Here is the WCF client code:

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();
    }
}

And a simple console app to invoke the client code:

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();

The web.config file for the IIS host looks like this:

<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>

And the service class hosted in 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"}
            };
    }
}

I have traced the WCF activity and have seen the process take approximately 5 millisconds to complete (I couldn't upload animage, here's one acivity trace from the log)

From: Processing message 5. Transfer 3/12/2010 15:35:58.861
Activity boundary. Start 3/12/2010 15:35:58.861
Received a message over a channel. Information 3/12/2010 15:35:58.861
To: Execute 'Ria.Spike.News.INewsService.GetNews' Transfer 3/12/2010 15:35:58.864
Activity boundary. Suspend 3/12/2010 15:35:58.864
From: Execute 'Ria.Spike.News.INewsService.GetNews' Transfer 3/12/2010 15:35:58.864
Activity boundary. Resume 3/12/2010 15:35:58.864
Sent a message over a channel Information 3/12/2010 15:35:58.866
Activity boundary. Stop 3/12/2010 15:35:58.866

Is this as good as it gets :s

Here's the remoting code used in this example.

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();

And a the TCP endpoint for this remoting channel hosting in 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);      
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

财迷小姐 2024-10-14 00:07:10

这仅测试顺序、同步、调用。 IIS 托管的 WCF 服务提供了更多基础设施来处理更高的负载,并且在高负载测试(具有大量并发连接的测试)中可能会优于远程处理。

远程处理端点也可以托管在 IIS 中,以获得相同的优势。 WCF 也可以托管在控制台中。您实际上是在将苹果与橙子进行比较。

This tests sequential, synchronous, calls only. An IIS hosted WCF service provides more infrastructure to handle a higher load and will likely out-perform remoting for a high-load test (one with a lot of concurrent connections).

A remoting endpoint can also be hosted in IIS though to get the same advantages. WCF can also be hosted in a console. You're really comparing apples to oranges here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文