如何提高WCF数据服务的性能

如何提高WCF数据服务的性能,wcf,wcf-ria-services,wcf-data-services,astoria,Wcf,Wcf Ria Services,Wcf Data Services,Astoria,我是WCF数据服务的新手,所以我一直在玩。在一些初始测试之后,我对测试数据服务的性能感到失望 我意识到,由于WCF DS是基于HTTP的,因此协议中存在固有的开销,但我的测试仍然比我预期的慢很多: 环境: 一体机:四核64位笔记本电脑,4GB RAM运行W7。像样的机器 小型SQL数据库(SQLExpress 2008 R2),包含16个表。。。被测试的表有243行 在IIS中以所有默认值托管我的测试服务 代码: 我已经为这个数据库创建了一个实体框架模型(DataContext)(VS20

我是WCF数据服务的新手,所以我一直在玩。在一些初始测试之后,我对测试数据服务的性能感到失望

我意识到,由于WCF DS是基于HTTP的,因此协议中存在固有的开销,但我的测试仍然比我预期的慢很多:

环境:

  • 一体机:四核64位笔记本电脑,4GB RAM运行W7。像样的机器
  • 小型SQL数据库(SQLExpress 2008 R2),包含16个表。。。被测试的表有243行
  • 在IIS中以所有默认值托管我的测试服务
代码:

  • 我已经为这个数据库创建了一个实体框架模型(DataContext)(VS2010的stock codegen)
  • 我已经基于这个模型创建了一个数据服务
  • 我已经创建了一个客户机,该客户机具有此服务的直接服务引用(ObjectContext)(VS2010的stock codegen)
  • 在客户端中,我还可以直接调用EF模型,还可以使用本机SQL(ADO.NET SqlConnection)
测试计划:

  • 每个迭代都连接到数据库(有一个重用连接的选项),查询目标表中的所有行(“事件”),然后对它们进行计数(从而强制执行任何延迟的回迁)
  • 为本机SQL(SqlConnection/SqlCommand)、实体框架(DataContext)和WCF数据服务(ObjectContext)分别运行25次迭代
结果:

  • 本机SQL的25次迭代:436ms
  • 实体框架25次迭代:656ms
  • WCF数据服务的25次迭代:12110ms
哎哟。这比EF慢20倍左右

由于WCF数据服务是HTTP,因此没有机会重用HTTP连接,因此每次迭代都会强制客户机重新连接到web服务器。但肯定还有更多的事情要做

EF本身速度相当快,相同的EF代码/模型被重用用于服务和直接到EF的客户端测试。在数据服务中,Xml序列化和反序列化会有一些开销,但是有那么多!?!我过去在Xml序列化方面有很好的表现

我将使用JSON和协议缓冲区编码运行一些测试,看看是否可以获得更好的性能,但我很好奇社区是否有加快这一速度的建议


我对IIS不是很在行,所以也许可以设置一些IIS调整(缓存、连接池等)来改善这一点?

为了消除大部分连接开销,您可以尝试将所有操作批处理到WCF DS,看看这是否会产生显著的差异

NorthwindEntities context = new NorthwindEntities(svcUri);
var batchRequests = 
     new DataServiceRequest[]{someCustomerQuery, someProductsQuery};

var batchResponse = context.ExecuteBatch(batchRequests);

有关更多信息,请参见。

如何通过WCF的25次迭代

var WCFobj = new ...Service();
foreach(var calling in CallList)
   WCFobj.Call(...)
如果您这样调用,则意味着您调用WCF 25次,这会消耗太多资源

对我来说,我过去常常将所有内容构建成一个
DataTable
,并将用户表名添加到我正在调用的存储过程中<代码>数据行是参数。调用时,只需使用

var table = new DataTable("PROC_CALLING")...
...
StringBuilder sb = new StringBuilder();
var xml = System.Xml.XmlWriter.Create(sb);
table.WriteXml(xml);
var bytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
[optional]use GZip to bytes
WCFobj.Call(bytes);
问题是,您可以一次通过所有25个调用,这可以显著节省性能。如果返回对象是相同的结构,只需以字节形式将其作为
DataTable
传递,然后将其转换回
DataTable

我曾经用GZip为导入/导出数据模块实现这种方法。传递大量字节会使WCF不高兴。这取决于你想吃什么;计算资源或网络资源。

尝试在配置的绑定部分将安全设置为“无”。这应该会有很大的改进。

需要尝试的事情:

1) 结果编码:尽可能使用WCF通道的二进制编码,请参阅--交替使用压缩:

2) 更改服务实例行为,请参阅--try InstanceContextMode=InstanceContextMode.Single,ConcurrencyMode=ConcurrencyMode.Multiple-如果您可以验证您的服务是以线程安全的方式构建的


关于您的基准测试,我认为您应该模拟更真实的负载(包括并发用户)并忽略异常值,对IIS的第一个请求将非常慢(它必须加载所有DLL)

考虑将其部署为windows服务吗?IIS可能有ASAPI过滤器、重写规则等。即使这些都没有处于活动状态,IIS管道也很长,有些东西可能会稍微减慢您的速度


服务应该为您提供一个很好的基线,说明在没有IIS减速的情况下,请求运行、打包等所需的时间。

下面的链接提供了一些视频,其中包含一些有趣的WCF基准以及WCF数据服务和实体框架之间的比较


WCF数据服务用于为不同的客户机提供OpenData协议;因此,您不必为每个更改请求编写/重构多个web服务方法。如果整个系统是基于microsoft技术堆栈的,我从不建议使用它。它适用于远程客户端。

我只需启用压缩功能,就可以将WCF数据服务API的性能提高41%。这真的很容易做到。按照此链接说明在IIs服务器上执行的操作:

换完零钱后别忘了换衣服

在客户端:

// This is your context basically, you should have this code throughout your app.
var context = new YourEntities("YourServiceURL");
context.SendingRequest2 += SendingRequest2;

// Add the following method somewhere in a static utility library
public static void SendingRequest2(object sender, SendingRequest2EventArgs e)
{
    var request = ((HttpWebRequestMessage)e.RequestMessage).HttpWebRequest;
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}

有趣的。。。一些观点,一些投票,还有一些喜欢的补充,但没有答案。我在这个问题上悬赏是为了给这个问题注入更多的活力。希望有人能给出答案。除非我计划将数据公开给其他应用程序,否则我不会使用WCF数据服务。如果所有的东西都在同一个盒子上运行,为什么不直接使用EF呢?它不是在同一个盒子上运行的。但是数据源都在一个(非常大且国际化的)公司网络上。我试图在一堆不同的数据源(SQL、XML、平面文件等)前面放置一个服务层,将实际存储语义与发现和查询数据的能力隔离开来。您如何测试这一点