AWS Partner Network (APN) Blog
Achieving Multi-Region Reliability with AWS Step Functions and Fauna
By Shadid Haque, Developer Advocate – Fauna
By Justin Callison, General Manager, Workflow – AWS
Fauna |
Multi-region architectures improve latency for applications with global user bases and optimize recovery time objectives (RTO) across the broadest set of potential failure events. However, creating and maintaining these architectures can add significant cost and complexity.
In this post, you will learn how to build and deploy a multi-region serverless application while minimizing cost and complexity using AWS Step Functions and Fauna, an AWS Partner and distributed document-relational database delivered as a cloud API.
You use Amazon API Gateway to invoke synchronous Express Workflows that send and retrieve messages in multiple languages using Amazon Translate.
Prerequisites
To follow along with this guide, you must have access to a Fauna account and an Amazon Web Services (AWS) account. You can register for a free Fauna account and benefit from Fauna’s free tier while you learn and build. You do not need to provide payment information until you upgrade your plan.
You can sign up for an AWS account by following these instructions. Although you must provide a payment method to create an AWS account, AWS also offers a free tier.
Additionally, you must have a currently supported Node.js version installed in your development environment to complete this walkthrough.
Multi-Region Benefits
If your users are geographically distributed, multi-region architectures can provide a better user experience through faster response times. Always on, multi-region active-active architectures can also reduce application downtime in the face of regional outages.
Traditionally, active-active architectures have been costly. With traditional instance- or container-based computing, running the same application in multiple regions means multiplying your resources and spending.
However, with serverless architectures you pay only for value. One million invocations split across two or more regions are cost equivalent to one million invocations in a single region.
Strongly Consistent Multi-Region Data with Fauna
Fauna is distributed by default within a geographic region or across the globe. Fauna’s document-relational model combines the flexibility and familiarity of JSON documents with the relationships and querying power of a traditional database.
Fauna gives you the strong consistency and ACID (atomicity, consistency, isolation, durability) transactions of a relational database with the performance you expect from a document database, simplifying building performant multi-region applications.
Creating a Multi-Region Database with Fauna
To create a new database in the Classic Region Group, provide a name for your database (1) and then choose the Classic Region Group (2). Next, click Create to create your database (3). In milliseconds, Fauna creates a globally distributed, strongly consistent database for you.
Figure 1 – Create Fauna database.
Accessing Your Database with Keys
In your new database, navigate to the Security tab and choose New key to create an admin key. You use this key to provision your collections, functions, and indexes using Fauna Schema Migrate, Fauna’s infrastructure as code (IaC) tool.
On the New key screen, confirm your database (1) is already selected and choose Admin from the Role selector (2). Optionally, you can give your key a name (3) to remember what it’s used for. Finally, choose Save (4) to create your first key.
Figure 2 – Create new Fauna key for Admin role.
Fauna creates your key and displays the key’s secret. Copy this secret to use to provision your database resources later.
Be sure to store this key securely. Admin keys have full permissions over your database, including the ability to create and delete resources like collections, indexes, and other keys.
For your AWS application, you need two server keys—one for each AWS region. Server keys allow full access to all documents, functions, and indexes in a database, but do not allow you to create and destroy collections, functions, indexes, or keys.
Fauna offers a number of tools for securing your production applications. For more information, see this post on the Fauna blog: Choosing an authentication strategy with Fauna.
Choose New key again, but this time select Server as the Role (1). Name the key based on the AWS region you’ll deploy to. For this tutorial, you deploy to eu-central-1 and us-west-2, so name your first server key Europe (Frankfurt) to match. Copy and store the server key securely.
Figure 3 – Create new Fauna key for Server role.
Repeat the previous process to create and securely store a key named US West (Oregon).
You should now have one admin key and two server keys.
Figure 4 – Key list with one admin key and two server keys.
Provisioning Resources in Fauna
Clone the repository for this post to your dev environment and change into the source directory:
git clone https://github.com/fauna-labs/multi-region-step-functions
cd multi-region-step-functions
Install the required dependencies:
npm install
Set the FAUNA_ADMIN_KEY
environment variable to the value of the admin key you previously created:
export FAUNA_ADMIN_KEY={{Admin Key}}
Fauna Schema Migrate provisions infrastructure using a two-step process. First, run the following command to generate the planned migration:
npx fauna-schema-migrate generate
Figure 5 – Fauna schema generation.
This creates an entry in the fauna/migrations directory and shows all resources that will be created or modified. For this tutorial, you create the following resources:
- Messages collection: A collection, similar to a table in a relational database, that holds all original messages.
- Translation collection: A collection that holds all translated messages.
- CreateMessage function: A user-defined function (UDF), similar to a stored procedure in a relational database, that creates a new message and translation for each message that is sent.
- GetNewMessages function: A UDF that retrieves a list of all messages in a given chat since the provided lastSeenAt timestamp.
- StoreTranslation function: A UDF that stores a new translation of a message in a given language.
- MessagesByChat index: An index that allows you to retrieve all messages for a given chat.
- TranslationsByMessageAndLanguage index: An index that allows you to find a translation for a particular message in a given language if one exists.
Once you review the migration and understand its changes, run the following command to create the required resources in your database:
npx fauna-schema-migrate apply
Figure 6 – Fauna schema application.
That’s it! You now have a multi-region database ready to send and receive messages and their translations.
Process Orchestration with AWS Step Functions
AWS Step Functions allows you to combine multiple service integrations and steps into complete microservices. In this application, you create two basic Express Workflows, one for sending messages and one for retrieving new messages.
Sending a Message
The SendMessage workflow has a single state, an AWS Lambda function that writes the provided input to your database in Fauna by calling the CreateMessage UDF.
Figure 7 – Step Functions workflow definition with a single state that writes a message to Fauna.
Although you can invoke the Lambda function directly from Amazon API Gateway, by embedding it in an Express Workflow you allow yourself to expand the definition of the SendMessage process in the future by modifying the workflow itself.
Retrieving New Messages
The GetNewMessages workflow starts by retrieving a list of all messages for a given chat later than the provided lastSeenAt timestamp. Next, a map state iterates over each message, checking whether it was returned in the requested language. If so, no further action is taken and the message is added to the list of return values.
If the message is not yet available in the requested language, the workflow invokes an Amazon Translate request. When the translated message is received, another Lambda function stores the new translation in Fauna by calling the StoreTranslation UDF, and the translated message is added to the list of messages to be returned.
Figure 8 – Step Functions workflow definition.
Deploying the AWS CloudFormation Stack
Run the following command in the same directory where you deployed your Fauna infrastructure:
sam build && sam deploy --guided --region eu-central-1
Figure 9 – SAM deployment for first region.
Be sure to confirm the AWS region is eu-central-1 and the FaunaDomain is db.fauna.com. Paste the EU Central (Frankfurt) server key you previously created when prompted for the FaunaServerKey.
Note that the value for the parameter FaunaServerKey will not be displayed.
When the AWS CloudFormation stack finishes deploying it will output a base URL as your WebEndpoint. Copy this value to use in testing.
Deploy your application to a second region by running the following command in the same directory:
sam build && sam deploy --guided --region us-west-2
Confirm that this time the AWS region is us-west-2 and paste the US West (Oregon) server key you previously created when prompted for the FaunaServerKey.
Note that you must use the --guided
option again, as you provide a different key for each region.
Figure 10 – SAM deployment for second region.
Again, copy the value of the WebEndpoint output to use in the next section.
Testing Your Application
Now that your application is deployed to eu-central-1 and us-west-2, it’s time to test it.
Run the following command, replacing {{WebEndpoint}}
with the value of the CloudFormation Output from your first stack in EU Central (Frankfurt):
Next, run the following command, replacing {{WebEndpoint}}
with the value of the CloudFormation Output from your second stack in US West (Oregon):
Navigate to the Fauna dashboard and choose Collections > Translations. Note that you have two documents—one for each of the original messages. This makes sense because the messages have been sent but not yet requested in any other languages than the original.
Imagine you were a French-speaking user of the application and wanted a list of all messages in French. Your application would run the following command, replacing {{WebEndpoint}}
with the value of the CloudFormation output from either stack:
curl {{WebEndpoint}}/chats/1234567890/messages/fr
Figure 11 – Response with automated translation of multi-region messages.
Success! The first “Hello, world!” is translated into French, and the second message is returned in the original French. Confirm this by returning to the Translations collection in the Fauna dashboard. You now see three documents—the two original messages and a translation of the first message from English to French.
Figure 12 – Resulting French documents including translations.
Cleanup
To remove the AWS resources you created when following this tutorial, run the following commands. If you deployed your stacks to different regions, you’ll need to modify the --region
argument appropriately. Be sure to answer “y” when prompted to confirm you want to remove the stack and the objects in your Amazon Simple Storage Service (Amazon S3) bucket.
sam delete --region eu-central-1
sam delete --region us-west-2
After removing your CloudFormation stacks, navigate to the Fauna dashboard and choose DB Overview and then Settings. Choose Delete and then Yes, Delete Database to delete your database and all associated resources.
Conclusion
In this post, you learned how to build and deploy a multi-region serverless application with AWS Step Functions and Fauna. You learned the benefits of running your application in multiple AWS regions and how Fauna simplifies storing and retrieving data across regions.
To learn more about AWS Step Functions, see the Serverless Workflows Collection. To learn more about building with Fauna on AWS, see Building a serverless REST API with AWS SAM and Fauna and Deploying a REST API with AWS App Runner and Fauna.
Fauna – AWS Partner Spotlight
Fauna is an AWS Partner and flexible, developer-friendly, transactional database delivered to you as a secure, web-native API so you never again have to worry about database provisioning, maintenance, scaling, sharding, replication, or correctness.