Cloud Architecture

Designing a 3-tier Architecture Using Serverless Services

February 27, 2023

I recently published a whitepaper and GitHub repository detailing a 3-tier AWS cloud architecture using only serverless services. In a series of blog post I will go over each tier to describe the reasoning and decisions behind the design.

In today's post we will look at a top-level design of the proposed stack. For those of you wanting to dive into the details straight away, a detailed diagram of the architecture can be found on GitHub here.

The design in a nutshell

Below is a simplified version of what we are building. It's a common 3 tier design that consists of a web layer, application layer and database layer.

The architecture consists of a web tier, application tier and database tier. 

Web tier

The 3-tier design helps us separate application logic and increase security. The web tier is where end-users (in the case of the provided Shopify example these are merchants and customers) interact with our application. In this design we are using AWS App Runner to host the main application. App Runner is a PaaS (Platform as a Service) solution. It's fully managed by AWS. It takes a code container and then deploys it automatically, taking care of availability, scaling, and security.

Application tier

The application tier hosts our API backend layer that takes instructions from App Runner and relays them to the database that runs in the database tier. It uses Amazon API Gateway with a private endpoint to receive the instructions which are then “proxied” to a Lambda function. The Lambda function queries the database and sends the response back to API Gateway, which in turn passes the response back to App Runner.

Database tier

The database tier is where merchant, customer and session data will be stored. The architecture is using both an SQL and NoSQL solution.

SQL

Many Shopify apps will benefit from a relational database and in general, MySQL and PostgreSQL are good choices. Aurora supports those databases and also comes in a serverless version. Therefor we will be using an Aurora Serverless V2 cluster, which is a quickly scalable Multi-AZ solution. We’ll be putting an RDS Proxy in front of our cluster to prevent overloading it with Lambda connections (more on that later).

NoSQL

At the time of writing, Shopify apps need some form of session storage and Shopify itself is recommending Redis. While it would be an option to provision an Elasticache Redis service, currently that doesn't come serverless. For this use case however, DynamoDB provides a perfect alternative. (I rewrote Shopify’s Redis module to work with DynamoDB. Let me know if you’re interested in using it)

Technically, DynamoDB does not run in a subnet because it’s a public service. However, we can use it privately by deploying a VPC Gateway Endpoint and adding a route to our private route table.

An RDS proxy service is used to manage the database connections. Since Lambda can reach high concurrency, it is possible hundreds of database connections are needed. Because this can overflow the database, a proxy is introduced to manage that traffic.

CI/CD using GitHub Workflows and ECR

Finally, as you can see in the diagram, GitHub is used to push code containers to ECR. This is done using GitHub Actions. Both App Runner and Lambda are then configured to update whenever there is a new version available. This fulfills our continuous integration and continuous delivery needs.

Continued reading

If you would like to learn more about this stack, please have a look at the whitepaper and GitHub repository.

About the author
Support

I'm an AWS certified cloud architect from New York, who loves writing about DevSecOps, Infrastructure as Code and Serverless. Having run a tech company myself for years, I love helping other start-up scale using the latest cloud services.

Join my mailing list

Stay up to date with everything Skripted.

Sign up for periodic updates on #IaC techniques, interesting AWS services and serverless.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.