Executions environments - Lambda functions behind the scenes

The expression serverless is slightly misleading, because Lambda actually runs on servers, they are just not visible for the accounts. In this short post, I'll cover how Lambda functions are run, and what AWS does to improve the efficiency of Lambda invocations.

Lambda is one of the most important element of AWS’s serverless stack.

The main advantages of being serverless is that there’s no need to provision and manage servers, accounts pay for the service after invocations and Lambda functions scale automatically.

But what goes on behind the scenes? How does Lambda work?

1. The secrets behind serverless revealed

First, Lambda functions have to run on something, which means that there must be a physical machine on which the code runs.

Being serverless doesn’t mean that there are no servers. There are, but we, the account owners, can’t see them, and as such, don’t manage them.

All of the server provisioning, management, scaling and high availability are the responsibility of AWS.

In real life, Lambda runs on AWS-managed (micro) virtual machines dedicated to the given account. This mainly means EC2 instances, but since last year AWS started to use Firecracker, a proprietary virtualization technology to create logical blocks, one for each account, in which Lambda functions run.

As it was said above, these micro-virtual machines are dedicated to an account, and multiple microVMs (for multiple accounts) can run on a high capacity EC2 instance. There are no miracles, all roads lead to EC2.

2. Lambda execution environments

Let’s take a closer look at how Lambda functions are invoked.

The service responsible for running Lambda (also called the data plane) allocates an execution environment for each Lambda function, where no two functions share the same execution environment. This can be imagined as an isolated container, in which the functions run, and they can’t reach into the other function’s container.

These environments are isolated from each other using various Linux container technologies, which are way beyond the scope of this post.

So far we have EC2 instances, each of which hosting multiple logical units called micro-virtual machines (one per account), and each microVM can have multiple execution environments, one for each Lambda function.

3. Execution environments are reusable

Let’s follow the lifecycle of a Lambda function.

When the function gets executed for the first time, the function code will get loaded from an S3 bucket, which can be customer defined or Lambda-managed.

Once the code is there, a new execution environment gets created for the function (also called a cold start). The execution environment contains the runtime information (e.g. NodeJS) and any layers created for the function as well.

The function runs in this container, and then it gets destroyed after it did what it was supposed to (return something, throw an error or simply just perform some logic).

But the good thing about execution environments is that they are reused for multiple invocations of the same functions, which is called warm execution. This comes from the need that most of the time a Lambda function will get executed more than once, with the invocations often following each other at a high frequency. So the next invocation of the same function uses the execution environment, which is already set up for that function. Lambda keeps caches and computes some common results between function invocations, and this way it can improve efficiency and save us time, therefore money.

Executions environments can live from a few minutes up to hours before they get destroyed.

What happens when multiple invocations of the same function occur at the same time? It’s one of the great features of Lambda that it supports a large number of concurrent invocations.

In this case, a new execution environment is generated for each concurrent invocation, so execution environments are only shared for serial invocations.

Of course, the execution environment doesn’t live forever, and eventually it will be used for another function invocation. To prevent functions interfering with each other, Lambda clears the memory before an execution environment is allocated to a function. The memory - for obvious reasons - will not be cleared when the execution environment is used for serial invocations of the same function.

The execution environment also includes a specific folder in case Lambda functions need to download something. Files written to this folder will be kept until the execution environment gets destroyed, which will result in improving efficiency.

4. Summary

Lambda being serverless doesn’t mean that there are no servers. Lambda functions run on EC2 instances, but they are managed by AWS.

Each function has an execution environment generated for them, and these environments can serve multiple invocations of the same function. Different functions have different execution environments, and so do concurrent invocations of the same function.

Thanks for reading, and see you next time.