Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve high-performance REST API on Azure with .NET?

We have a .NET Web Role hosted on Windows Azure that only serves a REST API with only a hand few web methods.

API is used rather aggressively by other cloud hosted apps (not browsers). Each method is stateless which enable direct scaling out, and typically interacts with the Blob or Table Storage.

Then contrary to most classical API, the amount of data uploaded to the API is typically much larger than the data downloaded from the API. Then, the size the average message is typically quite big as well (i.e. above 100kB).

So far, we are using WCF on top of ASP.NET Forms with POX messages (Plain Old Xml). The front-end performance are not very good, culprits are:

  • XML is verbose ==> bandwidth limitation.
  • ASP.NET + WCF + WcfRestContrib slow to parse/serialize messages ==> CPU limitation.

I am wondering what is the best strategy to achieve the highest possible front-end performance to reduce the number of VMs needed to support the workload.

Possible strategies that I am considering:

  • Discard XML in favor of ProtoBuf.
  • Add upstream GZip compression (classical HTTP compression only applies downstream).
  • Discard WCF entirely in favor of raw HttpHandlers.

Does anyone has benchmarked the various alternatives to achieve the most of each Azure VM for such usage?

Ps: Implicitly referring the Lokad Forecasting API but tried to phrase the question in a more general way.

like image 575
Joannes Vermorel Avatar asked Sep 27 '11 15:09

Joannes Vermorel


2 Answers

Is your XML being serialized via reflection (ie. using attributes and so forth)? If so, then protobuf-net stands to be much, much faster.

In fact, though, even if your XML serialization is customized using explicit getter and setter Func<>s, you can still see some significant gain with protobuf-net. In our case, depending on the size and content of the objects being serialized, we saw 5-15% speed increases in serialization times.

Using protobuf-net will also provide a bump to available bandwidth, though that will depend on your content to a large extent.

Our system sounds pretty different from yours, but FWIW we find that WCF itself has an almost imperceptibly low overhead compared to the rest of the flow. A profiler like dotTrace might help identify just where you can save once you've switched to protobufs.

like image 106
ladenedge Avatar answered Sep 23 '22 17:09

ladenedge


Is the size of the messages your service is receiving so big because there is a large amount of data in the message or because they contain files?

If it is the first case, then ProtoBuf does indeed seem like a very good option.

If the message size is big because it embeds files, then one strategy I have been using with success is creating two different architectures for your service methods: one for methods that upload and download files and another one for methods that only send and receive messages.

The file related methods will simply transmit the files inside the body of the HTTP requests, in binary form without any transformation or encoding. The rest of the parameters will be send using the request URL.

For file uploads, in WCF REST services, in the service method you will have to declare the parameter representing the file of being of type Stream. For example:

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "uploadProjectDocument?projectId={projectId}")]
void UploadProjectDocument(Guid projectId, Stream document);

When encountering Stream parameters, WCF will simply take their content directly from the body of the request without doing any processing on it. You can only have one parameter of type Stream on a service method (which makes sense because each HTTP request has only one body).

The downside to the above approach is that besides the parameter representing the file, all the other ones need to be of basic types (like strings, number, GUIDs). You cannot pass any complex object. If you need to do that you will have to create a separate method for it, so you might end up having two methods (which will translate in two calls at runtime) where at the moment you have only one. However, uploading files directly in the body of the request should be much more efficient than serializing them, so even with the extra call things should be improved.

For downloading files from the service you will need to declare the WCF methods as returning Stream and simply write the file in returned object. As with the Stream paramters, WCF will output the content of the Stream directly into the body of the result without any transformations on it.

like image 39
Florin Dumitrescu Avatar answered Sep 23 '22 17:09

Florin Dumitrescu