My first simple High Available/Scalable Architecture on AWS
I’ve been playing with AWS for a year now. When I heard Scalable, High Availability architecture back in college days, I wondered what do these mean? I knew we had to run a lot of servers in data centres, but has this got something to do with configuring the application what we are building? I thought this was all about tweaking MySQL, PostgreSQL configs or configuring number of workers in NGINX or something to do with our application design. This is the era of cloud, times have gone where you would procure hardwares and set up your own data centres (Well, you could still do it now with Open Stack if you think AWS, Azure or any other Cloud providers can’t handle you 🤪). Now you can literally set up a Virtual Private Cloud(AWS) sitting wherever you are right now just with a web browser. That’s what even I’ve been trying for the past 1 year and here is what I have.
DISCLAIMER & PREFACE:
- Architectures are opinionated and always subjective.
- Having some idea with AWS services could make you finish this post swiftly. For those who don’t I’ve linked the AWS Lingos to their docs.
- AWS has a lot of services, most of these can be implemented with their own service like EC2. So my policy is to use AWS services only if i feel its necessary. The prime reason for my policy is, if say there comes a day AWS can’t handle my application load/scale (Unlikely to happen), I could still replicate my architecture on bare metal machines easily.
- I have not discussed anything about containerising or container orchestration(eg: Docker, Docker swarm, Kubernetes). For starters lot of things can be achieved with AWS AMIs. Maybe in my next posts I will talk on them.
- Again my opinions are subjective, bear with me 👨🏻💻.
1. API Gateway
API gateway is the entry point of the public traffic. This will/must be the only way your services should be consumed by the outer world. I’d like to quote the definition of API Gateway defined in one of the blog post by NGINX here.
An API Gateway is a server that is the single entry point into the system. It is similar to the Facade pattern from object‑oriented design. The API Gateway encapsulates the internal system architecture and provides an API that is tailored to each client. It might have other responsibilities such as authentication, monitoring, load balancing, caching, request shaping and management, and static response handling.
So we are going to have an API gateway in all the Availability Zones of the region which you are planning to use. There will be a ELB in front of this which will be distributing the load.
To implement this concept.
- Create a t2.small EC2 instance with just NGINX installed( You can create an AMI for this and keep before hand for the Launch configuration). We will be configuring NGINX as a reverse proxy to route all requests from the outside world to their respective micro services.
- Create a Launch configuration for this and attach it to an Auto Scaling group. Based on your anticipated load you can set the min and max instances values in the Auto Scaling group.
- Create a Target group for the Application Load Balancer which you will be creating in the next step and link the created Target group to the Auto Scaling group created in the previous step.
- Create a internet-facing Application Load Balancer and link it to the Target group which you created in previous step.
And now you have a load balanced API Gateway which can scale based on load.
Your API Gateway will proxy all the requests to your micro services. The interesting thing here is they will be proxying to the internal load balancers of your micro services. Here is a sample snippet of how your NGINX config could look.
Other details in the config are irrelevant here, what’s important here is how you proxy the requests to the respective internal load balancers of your micro services.
This proxy routing can be done with the help of AWS ELB listener rules. Why did I implement it with NGINX ? Disclaimer & Preface Point 5.
2. Your Micro services
Splitting your monolithic codebase in to micro services has advantages and limitations. It’s discourse is beyond the scope of this post. Either ways you are gonna have at least one micro service. So you can apply the next describe steps to it.
Following The twelve-factor app methodology keep each of your micro service stateless. If there are any shared data move it to MongoDB, Redis or some other data store. Eg: if you are having a socket.io micro service, use socket.io-redis adapter to sync the socket room ids between other identical instances.
We are going to do pretty much same to our micro service what we did with our API gateway. I’m gonna list the steps what you have to do for a single micro service, you can repeat the same for all your micro services.
- Package your micro service in an AMI.
- Create a Launch configuration for this and attach it to an Auto Scaling group. Based on your anticipated load you can set the min and max instances values in the Auto Scaling group.
- Create a Target group for the Application Load Balancer which you will be creating next step and link the created Target group to the Auto Scaling group created in the previous step.
- Create an internal Application Load Balancer and link it to the Target group which you created in previous step.
- The DNS Name of the internal Application Load Balancer could look something like this internal-myproduct-production-orders-ms-elb-123456.ap-south-1.elb.amazonaws.com. Add this to your API Gateway’s NGINX configuration.
Here we go. Now we have all our micro services load balanced. They will scale based on loads. Since we have replicated in multiple Availability zones. We have some high availability with respect to the region which we are using.
So when there is a traffic spike in the API Gateway, multiple API Gateways will get spawned, at the same time our API Gateways will pass the load to their respective micro services. Now the traffic shifts to our micro services and they too react to it by spawning more instances of themselves.
And we have a very simple High Available, Scalable Architecture. Thanks to AWS.
3. Databases
When I’m on AWS, I prefer RDS, Aurora, DynamoDB and their other cloud databases than hosting databases myself. AWS takes the best care of our databases. While creating their managed DB instances we have to specify the Multi AZ availability, backups, encryptions and other configs and we are good to go. Later we have to make our micro services point to the endpoints of this managed database instances.
4. Horizontal and Vertical Scaling
In this design horizontal scaling can be achieved be changing the max and min instances count in the Auto Scaling group configuration and Vertical Scaling can be achieved by changing the instance type in the Launch configuration.