Serverless Microservices with AWS Lambda. How to Build a Robust and Cost Effective Back End product.

You probably heard a lot of hype about the serverless technology like AWS Lambda and microservices. After reading this blog post, you’ll know about pros and cons of using serverless microservices. You’ll also know how to implement an infinitely scalable back end using microservices on AWS Lambda.

Why bother with serverless microservices

Before we dive into reasons behind using serverless microservices, we need to understand the difference between microservices and a monolith.

What is a Monolith

Monolith

A monolith is a single back end application. All code is usually located inside a single repository. The entire back end application usually runs on a single server. Even though it’s quicker to build a monolith back end in a short term with frameworks like Ruby on Rails, Django or similar, it has some disadvantages in the long run. As you probably guessed, it’s harder to have multiple developers work in the same code repository as it grows bigger. The biggest disadvantage is resiliency, if there is an issue in a part of the app, the whole back end is down and your app or a website is unusable.

What are Microservices

Microservices

The microservices architecture solves these problems. The entire back end consists of multiple small services communicating with each other over HTTP or through a messaging system like RabbitMQ, AWS SQS or similar. Microservices take some time to set up. Once the core architecture is set up, you get the advantages like easy work parallelization and increased resiliency. Each developer can work on its own microservice without causing code conflicts with another developer. Each developer can develop a domain expertise allowing to develop features quicker and have a greater sense of ownership. In addition to the increased speed of development, if one microservice is down, the whole system is unaffected. Most of your app or a website functions as normal even though a small part has a problem. This way, there is no interruption of service and your business is better overall because of that.

What is serverless

Serverless is a concept that is developed recently. A traditional back end system is deployed and ran on a server or a group of servers. The advantage of a traditional server approach is that you have control over your own servers and the infrastructure behind it. One of the main disadvantages is an increased cost. Not only you have to hire DevOps or infrastructure engineers to build and maintain the infrastructure, you also pay for idle servers. Serverless technology solves these problems. With serverless pattern, you use a service that runs your code and maintains the infrastructure behind it. You only pay for the time it takes to process each request. AWS has a service for it called AWS Lambda, Microsoft offers similar Azure Functions, Google Cloud has Cloud Functions.

How to implement serverless microservices on AWS Lambda

As you can see, serverless microservices offer increased resiliency, faster speed of development at a lower infrastructure cost. Let’s figure out how to implement it on AWS Lambda.

Create a lambda role in IAM

In order to run your lambda on AWS, you’ll need to create a role in IAM and assign permissions to it. Go to IAM, select Roles, click “Create new role”. Attach a policy based on what resources your lambda needs to access. AWSLambdaBasicExecutionRole should work for a very basic case.

Write your lambda

Go to AWS console and choose the Lambda service, click “create function”. You can either choose from existing templates or chose to “Author from scratch”. Choose API Gateway as a trigger and click the “Next” button. As you can see on the next screen, a typical lambda consists of one function named handler. Here is an example:

exports.handler = (event, context, callback) => {
  callback(null, 'Hello from Lambda');
};

Implement your business logic inside the handler function. Once the work is done, call the callback function. Pass null as a first parameter to your callback to indicate success. The second argument is the data returned by the function. If you would like to return a failure, return an error object as a first parameter instead. Here is an example of a lambda function indicating a failure.

exports.handler = (event, context, callback) => {
  callback(new Error("Execution Failed");
};

It’s important to note that you have to call the callback function to tell the system that your lambda is done. If you don’t do so, the function keeps running unless it times out. Catch your errors and call your callback explicitly to handle errors.

After you finished implementing your business logic, choose a Role that you created in IAM previously and hit “Next”.

API Gateway

AWS API Gateway is another service from AWS that helps us to receive an HTTP request. It also helps us to connect the request with our lambda for later processing. If you didn’t read the post on developing mobile apps faster with AWS API Gateway, I highly recommend it. You’ll know how to simplify even more of your infrastructure to move even faster.

Go to the AWS API Gateway service. If you chose an existing API when you created your lambda, your lambda will be connected to the existing API. If you didn’t have any API before, a new API will be created. From here, you can customize your request, response, headers, etc. You can also create new endpoints and connect them with new lambdas. Every time a request comes in, your lambda will be invoked automatically.

Lambda Environments

If you have multiple environments, you will need to create multiple versions of your lambda corresponding to each environment. node-lambda npm package handles it out of the box if you specify the –environment parameter. node-lambda also helps you automate the deployment of your lambdas. This way you can develop and test your lambda locally. You can use your version control system. It also allows you to deploy your lambdas to AWS with a single command and your changes will be available in seconds.

Now that you have several versions of your lambda, let’s say hello-world-development and hello-world-staging, you can connect it to the same API using stage variables. Go to your API on AWS API Gateway, click on Stages. For each one of your stages, select your stage, go to the “Stage Variables” tab and create a stage variable named “environment”. For the development stage, set the environment stage variable value to “development”, set it to “staging” for the staging stage. Repeat the same for all your stages.

The last step is configuring the lambda name based on the value of the stage variable named “environment”. Go to your AWS API Gateway, create a new resource and a method, choose the Lambda integration type. In the “Lambda Function” field, specify the name of your function followed by -${stageVariables.environment}. For example, if the name of your lambda is hello-world, enter hello-world-${stageVariables.environment}.

Connecting Lambda with API Gateway

Next, you’ll be prompted by an alert explaining how to grant a permission to execute your lambda with all possible values of your stage variables. Copy the command from this alert, replace ${stageVariables.environment} with your environment name. Run this command from the terminal to grant permissions. Repeat for each environment name.

Grant permissions for each lambda environment

Warm up times

Another thing to take into consideration is warm up times. Since a lambda is ephemeral it’s not running all the time like traditional servers. The very first request usually takes several seconds to warm up any lambda. Subsequent requests are processed quickly. If you develop a real-time API with AWS Lambda, consider setting up Cloud Watch triggers to keep real-time lambdas always warm.

Final words

Serverless microservices is a cost effective way to develop a resilient back end faster. It takes a little work up front to set it up. Once it’s set up, you start developing your lambdas which are isolated and “infinitely” scalable. This way you can spend more time developing your business logic instead of supporting the infrastructure behind it.

The main takeaway is that you have to think about your application requirements today and tomorrow. I’ve seen so many companies implementing a monolith infrastructure in a hurry, getting stuck with it later, scratching it and starting over again. In order to set yourself up for success, your system needs to be extensible so you can change the pieces of it without affecting the whole system. Microservices is one way of doing it. Think about how you can make your system modular on your project.

Thanks to otubo, timparkinson, and kwanie for providing awesome images.