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.

This is part of a series of posts about building a C# networking and data library for developing online games in Unity.

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: 166ms average.
  • Ruby->GRPC Gateway: 128ms average (23% reduction).
  • Pure GRPC: 63ms average (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.

Add Comment

By zane

Recent Posts

Recent Comments

Archives

Categories

Meta

Recent Posts

Categories

Tags

zane

Get in touch

Quickly communicate covalent niche markets for maintainable sources. Collaboratively harness resource sucking experiences whereas cost effective meta-services.