GraphQL and GRPC Speed Test using C# and Ruby

GraphQL and GRPC Speed Test using C# and Ruby

I recently implemented a GraphQL + GRPC server, with a bridge between the two. This way, clients can connect via GRPC or via GraphQL but have complete feature parity. In this post, I’ll analyze the performance (speed) of each.

The Setup

For this test, I created a complicated GRPC function that needed to load an item from the database, update it, and then return a huge amount of nested objects with lots of potential for N+1s or other inefficient queries. Expressed in terms of GraphQL, the request looked like this:

mutation {
  Resume(token:$token){
    ID
    token
    account {
      ID
      players {
        ID
        type
        parentID
        items {
          ID
        }
      }
    }
  }
}

It’s a basic “resume” request for an OAuth2 access token. In the response, the account includes several players, and the players each have many items. I then re-implemented the same method in pure Ruby/GraphQL (for comparison). Therefore, I had three ways of making the request:

In pure GRPC, the same request looks like this:

ResumeReq req = new ResumeReq() {
  Token = token,
  Selections = {
    new GraphSelection() { Name = "ID" },
    new GraphSelection() { Name = "token" },
    new GraphSelection() { Name = "user", Selections = {
      new GraphSelection() { Name = "account", Selections = {
        new GraphSelection() { Name = "ID" },
        new GraphSelection() { Name = "players", Selections = {
          new GraphSelection() { Name = "ID" },
          new GraphSelection() { Name = "type" },
          new GraphSelection() { Name = "parentID" },
          new GraphSelection() { Name = "items", Selections = {
            new GraphSelection() { Name = "ID" }
          }}
        }}
      }}
    }},
  }
};
client.Resume(req);

All requests were made to my servers running on Amazon Elastic Beanstalk, with thousands of trials for testing. It’s worth noting that the GRPC server is built in C# with .NET 4.6.

The Results

  • Pure GraphQL/Ruby: 166msaverage.
  • Ruby->GRPC Gateway: 128msaverage (23% reduction).
  • Pure GRPC: 63msaverage (62% reduction).

Analysis

There are a lot of variables at play here. Much of the benefits seen in the pure GRPC implementation are certainly due to HTTP/2 vs. HTTP/1.1. With much lower overhead per request, it’s no surprise that requests take 1/3 the time.

Still, there was a meaningful reduction with the Ruby->GRPC gateway. Since the client still connects with HTTP/1.1 in this case, it cannot be explained by protocol. Furthermore, the server has to go through the additional hop of translating the JSON into a GRPC call and forwarding it to the GRPC service behind the Ruby server. One would expect that this would increase overhead, not decrease it (as compared to pure GraphQL/Ruby).

One explanation would be differences in implementation efficiency between the pure GraphQL and pure GRPC servers. However, this doesn’t hold much water: the database queries are nearly identical in both cases. The rest of the logic is rather straightforward serialization and deserialization. If anything, the overhead of going through a JSON<->GRPC conversion should increase the time for the gateway.

I cannot conclude that Ruby is necessarily a “slow language”, as many have done. Still, whatever the reason, C# serving GRPC calls through a gateway was still faster than the Ruby gateway itself doing the work.

Build Guides

Looking for even more detail?

Drop your email in the form below and you'll receive links to the individual build-guides and projects on this site, as well as updates with the newest projects.

... but this site has no paywalls. If you do choose to sign up for this mailing list I promise I'll keep the content worth your time.

Written by
(zane) / Technically Wizardry
Join the discussion

Menu