在现代软件开发中,数据服务的性能对于用户体验至关重要。本文将探讨如何通过改变数据传输格式来优化.NET客户端与OData服务之间的数据交互性能。
有一个名为NWGW的组件,它在本地部署,而.NET客户端则托管在Azure上。通过Service Bus relay从Azure消费此数据。在从本地传输数据到Azure的过程中,面临了性能问题,无论是对于单个用户处理大量数据,还是对于并发用户处理相对较小的数据量。
为了提高性能,进行了一项概念验证(POC),通过将OData服务的响应格式从XML更改为JSON来改善性能。
创建了一个没有底层数据源连接的简单WCF数据服务。在服务初始化时,生成一系列文本消息并将其作为OData公开。
[Serializable]
public class Message
{
public int ID { get; set; }
public string MessageText { get; set; }
}
public class MessageService
{
List _messages = new List();
public MessageService()
{
for (int i = 0; i < 100; i++)
{
Message msg = new Message
{
ID = i,
MessageText = string.Format("My Message No. {0}", i)
};
_messages.Add(msg);
}
}
public IQueryable Messages
{
get
{
return _messages.AsQueryable();
}
}
}
配置服务以允许客户端通过Service Bus endpoint消费服务。
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WcfDataService1 : DataService<MessageService>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Messages", EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
创建一个控制台客户端应用程序来消费服务。
class Program
{
static void Main(string[] args)
{
List<Thread> lst = new List<Thread>();
for (int i = 0; i < 100; i++)
{
Thread person = new Thread(new ThreadStart(MyClass.JsonInvokation));
person.Name = string.Format("person{0}", i);
lst.Add(person);
Console.WriteLine("before start of {0}", person.Name);
person.Start();
}
Console.ReadKey();
foreach (var item in lst)
{
item.Abort();
}
}
}
进行了两种不同的场景测试:
定期测量XML格式和JSON格式的数据传输时间。首次调用时,需要额外的时间来连接到SB endpoint,因为需要进行密钥认证。
在XML格式下消费。
在JSON格式下消费:
XML消息大小约为51 KB。现在,将以JSON格式消费相同的数据列表(数组大小100)。
从上述测试场景中,很明显JSON响应时间比XML响应时间快得多,原因是消息大小。在这次测试中,当以XML格式获取100条记录的列表时,消息大小为51.2 KB,而JSON消息大小为4.4 KB。
在这次并发用户负载测试中,没有进行任何服务节流或最大并发连接配置。
在上述屏幕截图中,会发现一些超时错误,这些错误是在XML响应中发生的,原因是通过中继的高响应时间。但是,当以JSON响应执行相同的测试时,发现响应时间相当稳定且比XML响应快得多,没有得到任何超时。
如果使用的是WCF Data Service 5.3及以上版本,并且使用的是VS2012更新3,则从客户端消费JSON结构时,需要使用以下代码实例化代理/上下文:
<ServiceInstance>.Format.UseJson()
这里不需要单独加载Edmx结构,也不需要编写任何自定义代码。当添加服务引用时,.NET CodeGen将生成该代码。
public static IEdmModel LoadEdmx(string srvName)
{
string executionPath = Directory.GetCurrentDirectory();
DirectoryInfo di = new DirectoryInfo(executionPath).Parent;
var parent1 = di.Parent;
var srv = parent1.GetDirectories("Service References\\" + srvName)[0].GetFiles("service.edmx")[0].FullName;
XmlDocument doc = new XmlDocument();
doc.Load(srv);
var xmlreader = XmlReader.Create(new StringReader(doc.DocumentElement.OuterXml));
IEdmModel edmModel = EdmxReader.Parse(xmlreader);
return edmModel;
}