How to Set Up a Scalable and Highly-Available GraphQL API in Minutes
A modern GraphQL API layer for cloud native applications needs to possess two characteristics: horizontal scalability and high availability.
Horizontal scalability adds more machines to your API infrastructure, whereas vertical scalability adds more CPUs, RAM, and other resources to an existing machine that runs the API layer. While vertical scalability works to a certain extent, the horizontally scalable API layer can scale beyond the capacity of a single machine.
When it comes to high availability, the GraphQL API layer needs to function continuously without failing (even in the event of outages that are not under our control). But this system characteristic is best measured with the nines of availability.
This post shows you how to set up a GraphQL API layer (with an underlying database) across multiple availability zones of a public cloud region in minutes. More specifically, the solution that spans multiple availability zones can withstand zone-level outages and scale horizontally across multiple geographical locations. AWS, Hasura Cloud, and YugabyteDB Managed are used as reference platforms for demo purposes.
Deploying YugabyteDB across multiple availability zones
Let’s begin with the database layer. We picked YugabyteDB, an open source, distributed SQL database that is an ideal backbone for scalable and resilient APIs. YugabyteDB is also a PostgreSQL-compliant database. This means we don’t need to learn another SQL dialect or rewrite existing applications from scratch.
How much time does it take to deploy a resilient, multi-zone YugabyteDB cluster? It depends. But if you are as lazy as I am—or prefer using cloud native services—then YugabyteDB Managed is the simplest way to accomplish this task:
- For starters, create or sign in to your YugabyteDB Managed account: https://cloud.yugabyte.com/.
- Next, provision a multi-node YugabyteDB cluster that spans several availability zones:
- Use a custom cluster name such as multi-zone-cluster, place the cluster in an AWS region closest to you (N.Virginia – us-east-1 for me), and make sure the Fault Tolerance parameter is set to Availability Zone Level.
- Download credentials for future reference and then click Create Cluster.
Achieving high availability
But how do we achieve high availability with YugabyteDB? A YugabyteDB cluster has three nodes, deployed in one of three availability zones. The replication factor is also set to three. This means each node (and each region effectively) will keep a copy of a given data record. In my case, there is a node in us-east-1b, us-east-1c, and us-east-1a availability zones:
YugabyteDB is built on the Raft consensus protocol. Therefore, with the current three-node configuration, we can lose up to one node (or one availability zone as long as there is one node in each region) and remain operational. Why wouldn’t YugabyteDB keep serving requests with one node left? In terms of the CAP theorem, YugabyteDB is a consistent and partition-tolerant (CP) database.
The following formula defines a dependency between the fault-tolerance of k nodes and replication factor (RF):
RF = (2k + 1)
In our case, k is equal to one (the cluster can lose up to one node) and, as a result, RF calculates three copies of data.
But how do we achieve horizontal scalability with YugabyteDB if the database needs to process 100x more queries or keep much more data? Just go to the Settings screen of the cluster and add more nodes to the infrastructure.
Creating a scalable and resilient Hasura GraphQL API layer
Hasura is an advanced GraphQL server that gives us instant, real-time GraphQL APIs over PostgreSQL-compliant databases such as YugabyteDB.
Hasura comes with a fully-managed cloud version. Create a Hasura project that provides horizontal scalability and high availability out of the box:
- Sign in to your Hasura Cloud account: https://cloud.hasura.io/
- Create a Standard Tier project:
- Select an AWS region similar to the one chosen for the YugabyteDB deployment – US East (N. Virginia) in my case.
- Finally, click the Create Project button to proceed with the deployment.
As we see, Hasura doesn’t have any settings related to scalability and zone-level availability. But how can we be sure that our API layer will remain operational during potential zone outages or scale horizontally once necessary? In fact, as long as we selected the Standard Tier, these two characteristics are provided out of the box. This is what Hasura says in the documentation:
- Horizontal scalability – Hasura Cloud lets you scale your applications automatically without having to think about the number of instances, cores, memory, and thresholds. You can keep increasing your number of concurrent users and the number of API calls and Hasura Cloud will figure out the optimizations automagically.
- High availability – Multiple instances of Hasura can be run with the open source graphql-engine. In Hasura Cloud, the process of automatically scaling and the infrastructure required to run this is taken care of without any requirement of manual intervention.
Connecting Hasura GraphQL API layer to YugabyteDB
Up to now, we’ve already deployed a Hasura GraphQL layer and YugabyteDB cluster that can scale horizontally and withstand zone level outages. What’s left is the interconnection of these two components to get a final solution for our applications.
Adding Hasura to the YugabateDB white list
The YugabyteDB cluster instance requires us to specify the IP addresses of applications accessing the database. This is not an exception for our Hasura instance.
Add Hasura Cloud IP to the Allow IP List on YugabyteDB Managed’s end:
- Copy the Hasura Cloud IP from your Hasura’s project screen.
- Finally, navigate to YugabyteDB Cloud and add the IP to the IP Allow List.
After granting Hasura access to the YugabyteDB instance, we need to establish a connection between the two services. Specifically, it involves two steps:
- Open Yugabyte Cloud and copy a connection URL:
- Click the Connect button and select the Connect to your Application option.
- Check the Optimize for Hasura property.
- Copy your unique connection URL for YSQL (Yugabyte SQL).
- Make sure to replace DB USER and DB PASSWORD with the credentials that you downloaded during the YugabyteDB cluster deployment step.
- Navigate to Hasura Cloud and establish a connection with YugabyteDB:
- Click the Launch Console button and go to the Data & Schema Management screen.
- Provide YugabyteDB connection parameters and establish a connection.
- Finally, click the Connect Database button to establish the connection.
We’ve just set up a GraphQL API layer that can withstand zone-level outages and scale horizontally. Now, let’s do a sanity test of the APIs by playing with sample data and requests.
Creating a sample database
Follow the steps below to create the Users and Messages tables in YugabyteDB:
- Launch the Cloud Shell on the YugabyteDB Cloud end:
- Create Users and Messages table:
- Finally, initialize the Users table with two records:
Querying data with GraphQL API layer
After loading the sample database to YugabyteDB, we can benefit from the GraphQL API layer provided by Hasura.
Exposing tables to GraphQL API layer
Even though Hasura automatically detects structural changes on the database side, we still need to specify explicitly what tables can be queried with GraphQL APIs.
- Open the Data & Schema Management tab of the Hasura Console.
- Click the Track All button to expose both tables via the GraphQL APIs:
- Finally, click the Track buttons for the messages->users foreign key relationships:
Next, let’s read records of the Users table with GraphQL:
- Open the Api Explorer tab of the Hasura Console:
- Get all the Users:
- Lastly, confirm the output is as follows:
Finally, let’s make sure that our GraphQL APIs can handle writes without issues:
- Add a Message to the database with the following GraphQL mutation:
- Read the Message back from YugabyteDB:
- Finally, confirm the output is as follows:
As we’ve seen in this article, the right combination of modern cloud native services makes it easy to set up a horizontally scalable and highly available GraphQL API layer. Within a matter of minutes, we’ve got the API layer that can handle an increase in requests, expand its capacity from 10GB to 100GB and even bigger volumes, and—most importantly—keep serving application requests, even in the event of a zone-level outage.
Finally, if your GraphQL API layer needs to work across several cloud regions and tolerate region-level outages, then you still can use Hasura and YugabyteDB. Presently, this capability is available for self-managed installation options (see YugabyteDB multi-region deployments). However, I believe this should make its way to the fully-managed versions of the technologies in the near future.
YugabyteDB Managed is a frictionless multi-cloud database-as-a-service built for developers. Now you can focus on building great apps and stop making costly trade offs with your database. Sign up for free today!