Evaluating Performance of REST vs. gRPC
By: Ruwan Fernando
Tags: Grpc, Benchmark, Aspnetcore, Rest Api, Dotnet Core

I’ve been waiting for a break to investigate the performance benefits of gRPC over REST for quite a while now. I currently have a few micro-services which are talking to each other in JSON over REST, and feel like they’re reaching the VPS hardware throughput limits, and I’d soon need to upgrade my tier to better balance the performance.

This seemed like the ideal time for some experimentation. I needed to evaluate just how much of a performance benefit I could gain with gRPC (if any) and more importantly, how much of an effort I’d have to put in to fully migrate my existing talkative micro-services to gRPC.

What is gRPC?

For those who’ve not heard of it before, gRPC is a language agnostic framework introduced by Google for remote procedure calls, that gives serious thought for performance and scale. It’s been around for quite a while now, but most people (maybe just I) have put it on the back-burner due to the initial time that needs to be spent on getting the IDL right, and the extra stub code that needs to be maintained. While REST on the other hand, is a breeze to implement using ASP.NET Core WebAPIs.

Similar to how JSON is widespread for REST communication, gRPC relies heavily on Protocol Buffers, a language neutral storage format for serialized structured data. This is what pulls gRPC apart from the rest (pun intended). The Protocol Buffers can be used in all major language flavors thanks to the protoc compiler which generates the necessary native class definitions from the proto file definition. In addition to this gRPC also uses HTTP/2 for communication, which brings added goodies like HTTP header data compression and multiplexed requests over TCP connections.

Benchmark Constraints

There were a few constraints that I wanted implemented when bench-marking the REST vs. gRPC calls.

Test pure communication throughput, and not involve any business logic in the process. I felt that would take away the focus from the main point.

Not to have any Database connectivity and instead mock the data with Static fields. Thus eliminating caching issues and random execution time skews.

Disable logging so it will not have any impact on the test runs. If not, it could’ve led to highly misleading readings.

Project Structure

ModelLibrary contains the REST & GRPC related models. Also to make the test cases more generalized, I’ve chosen a data set which includes string, int, double & date time. The NASA meteorite landings data set of 1000 data points found at https://data.nasa.gov/resource/y77d-th95.json.

Sample Data Point of NASA’s meteorite landings

The following Messages and Service definitions were also created for the gRPC Service using Protocol Buffer definitions.

Protocol Buffer Definition for Messages

I’m also testing the gRPC’s streaming performance here with the “GetLargePayload” service.

Protocol Buffer Definition for Services

RestAPI contains the WebAPI which exposes the following three methods targeting three specific scenarios, receiving a small payload, receiving a large payload & sending a large payload

ASP.NET MVC Core WebAPI routes

Also as mentioned above under constraints, get rid of extra console logging from the WebAPI so it won’t affect the benchmark measures.

Decrease Logging verbosity for ASP.NET MVC Core WebAPI

GrpcAPI contains the Service Implementation and some bootstrap code to startup the gRPC Server. It was interesting for me to also test how gRPC streaming compares to REST, so I’ve also implemented an extra method “GetLargePayload” which iterates and streams one data point at a time

GrpcAPI Service Implementation

RESTvsGRPC contains the Benchmark harness which calls all these methods in two batches of 100 & 200 iterations each to reduce measurement inaccuracies of small execution times. So the below benchmark execution times are actually multiplied by 100 & 200 times the real value.

RESTvsGRPC Benchmark Harness

Benchmark Results

As expected gRPC came out on top, except when streaming data. Streaming was slightly worse than calling REST. gRPC also showed even better performance when Sending data than Receiving. I assume this is due to the HTTP/2 header compression, but I’ve yet to verify that claim by analyzing the HTTP post data.