How to: optimize Lambda memory size during CI/CD pipeline
Tags: aws, lambda, performance, serverless
Published: 2020-03-22 12:17:23

---
title: How to: optimize Lambda memory size during CI/CD pipeline
published: true
date: 2020-03-22 01:22:34 UTC
tags: AWS,Lambda,Performance,Serverless
canonical_url: https://theburningmonk.com/2020/03/how-to-optimize-lambda-memory-size-during-ci-cd-pipeline/
---

Lambda invocations are charged in 100ms blocks of execution time. But the cost per 100ms of execution time depends on how much memory you allocate to the function. The higher the memory, the more CPU cycles and network bandwidth, but the higher the cost as well.

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bc3f03d0d.png)<figcaption id="caption-attachment-9914">https://aws.amazon.com/lambda/pricing</figcaption>

One of the simplest and most efficient cost optimization for Lambda is to right-size the memory allocation for your functions. It used to be a dark art that requires plenty of trial-and-error, until the [aws-lambda power-tuning](https://github.com/alexcasalboni/aws-lambda-power-tuning) app from [Alex Casalboni](https://twitter.com/alex_casalboni). Which uses Step Functions to execute your function against different memory sizes to help you find the best configuration for speed, cost or a balance of the two.

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bc6d4ad0e.png)

However, managing the deployment of the `aws-lambda-power-tuning` app (which is available via the [Serverless Application Repository](https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:451282441545:applications~aws-lambda-power-tuning)) is an extra overhead that most of us rather do without. Not to mention the headache of keeping it up-to-date whenever Alex releases new features.

So, to make power tuning functions more accessible, I added support for it in the [lumigo-cli](https://www.npmjs.com/package/lumigo-cli). You can tune a function with a simple command `lumigo-cli powertune-lambda -r us-east-1 -n my-function --strategy balanced` .

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bc7e22e3c.png)

Since version `0.39.0` of the `lumigo-cli`, it’s now even easier to integrate it with CI/CD pipelines. Because I added support for storing the output of the app (see below) into a local file, so they can be easily parsed, and the ability to suppress the command line prompt to visualize the result.

```
{
  "power": 512,
  "cost": 8.32e-7,
  "duration": 15.411500000000002,
  "stateMachine": {
    "executionCost": 0.0003,
    "lambdaCost": 0.001075983999999999,
    "visualization": "https://lambda-power-tuning.show/..."
  }
}
```

Check out [**this repo**](https://github.com/theburningmonk/powertune-lambda-CICD-demo) for a demo project that automatically tunes its functions as part of its CI/CD pipeline. Let’s walk through it.

# The setup

The demo project uses the Serverless framework to configure and deploy its functions. But the same approach works with other deployment frameworks too. The important thing to note is that we have three functions:

```
functions:
  cpu-intense:
    handler: functions/cpu-intense.handler
  io-intense:
    handler: functions/io-intense.handler
    events:
      - http:
          path: /
          method: POST
  mixed:
    handler: functions/mixed.handler
```

By default, the Serverless framework configures functions with 1024MB of memory and 6 seconds timeout.

In the project root, there is an `examples` folder. This is where you put the example payloads to use when tuning each of the functions.

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bca1bacc9.png)

There is also a `build.sh` script, where much of the magic happens during the CI/CD pipeline.

# The build.sh script

As part of my projects, I usually include a `build.sh` script. This script encapsulates the key steps for my CI/CD pipelines, such as running tests and deploying the project. It simplifies the process of testing my CI/CD pipelines since I can easily run it locally. And it allows me to move between CI tools easily since the “meat” of the pipeline is in the scripts.

When adopted broadly, it gives you a DSL for all of your projects, e.g.

- `./build.sh deploy dev us-east-1` to deploy the project to the `dev` stage in the `us-east-1` region
- `./build.sh int-test dev us-east-1` to run the integration tests in the `dev` stage, against the `us-east-1` region
- `./build.sh e2e-test dev us-east-1` to run the end-to-end tests in the `dev` stage, against the `us-east-1` region
- and so on…

In this particular case, I have a command to tune the functions in this project to a strategy of my choosing — `cost`, `speed` or `balanced`. For example, by running `./build.sh tune dev us-east-1 balanced` .

{% gist https://gist.github.com/theburningmonk/3482f83697bc41a80aae377029f90736 %}

This command can be run AFTER the functions have been deployed. As you can see, it uses the `lumigo-cli` to tune each of the functions.

```
lumigo-cli powertune-lambda \
  -r $1 \
  -n $functionName \
  -s $4 \
  -f examples/$3.json \
  -o $3-result.json \
  -z > /dev/null
```

Couple of things to note here:

- the input file (`-f`) points to the aforementioned `examples` folder. The input files need to be named after the names of the functions in the `serverless.yml` . In this case, `cpu-intense.json` , `io-intense.json` or `mixed.json`.
- the output file (`-o`) would be named after the same function name too.
- the `-z` flag suppresses the command line prompt where the `lumigo-cli` asks you if you want to see a visualization of the results.

The `io-intense` function (see below) is an API Gateway function and extracts the `url` from the POST body. So, to tune this function we need to invoke it with a payload that looks like an API Gateway event.

{% gist https://gist.github.com/theburningmonk/abc82a4b1b36575c6ac8180176570a30 %}

Similar, if you have functions that process events from SNS, SQS, Kinesis and so on, you would need to tailor the payload for each. Hence the purpose of the `examples` folder.

Third-party tools such as [Lumigo](https://lumigo.io/) can make your life easier here. As you can see the invocation event for a function in the `Transactions` view. This makes it easy to capture sample payloads without having to temporarily add print statements to your functions.

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bccb31f84.png)

If the function’s memory size doesn’t match the optimal power, then we can update it in-place using the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html).

```
if ((optimalPower != memorySize)); then
  echo "updating function memory size to $optimalPower..."
  aws lambda update-function-configuration \
    --region $1 \
    --function-name $functionName \
    --memory-size $optimalPower > /dev/null
fi
```

# The CI/CD pipeline

I decided to use [CircleCI](https://circleci.com/) here because it’s free for public repos and I have used it to good effect in the past. But the approach works with other CI tools too.

Here, my entire pipeline involves setting up the dependencies and then running `./build.sh deploy dev us-east-1` and `./build.sh tune dev us-east-1 balanced` . In practice, I’d have used a custom docker image with all the dependencies (AWS CLI, jq, etc.) pre-installed.

{% gist https://gist.github.com/theburningmonk/2bf3133e57b3a1cb4896ef90dd4a5bb1 %}

And when the pipeline finishes, all 3 functions’ memory size would be fine-tuned to give the best performance-to-cost ratio.

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bd5d99a43.png)

# Wrap up

In this post, we saw how you can optimize the memory configuration for your functions as part of the CI/CD pipeline. This ensures that your functions are always fine-tuned to deliver the best performance at the lowest cost.

The approach is applicable to different deployment frameworks and CI tools. Broadly speaking, your pipeline would consist of these steps:

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bd753389b.png)

The functions’ configurations are updated in-place and the changes are never committed back into the source code. The problems with this approach are:

- Functions need to be tuned in every environment, after every deployment.
- The payloads might be environment-specific, which introduces extra complexity and overhead for managing these.
- It might not be possible to tune functions that write to databases, etc. in the production environment. At the very least, you’ll have to pay special attention to manage this to avoid introducing test data to the production environment.

To address these problems, you can extend the approach I have shown you in this post. For example, instead of updating the functions in-place, you can create a PR when improvements are identified. Assuming there are no environmental factors that can drastically affect performance, then you’d only need to run tuning in the deployment pipeline for `dev`. This addresses the aforementioned problems.

![](https://theburningmonk.com/wp-content/uploads/2020/03/img_5e76bd85785ba.png)

If you can standardise on the deployment and CI tool you use, then you can automate the process even more. For example:

- parse the `serverless.yml` to extract the function names so they don’t have to be hardcoded
- auto-generate the payload based on the configured event source for each of the functions
- create an organization-wide CLI that lets you bootstrap new projects with a templated `build.sh` script and CI/CD pipeline yml

And finally, here are some relevant resources for you to explore:

- The [demo project](https://github.com/theburningmonk/powertune-lambda-CICD-demo) used in this post
- [Alex Casalboni’s aws-lambda-power-tuning app](https://github.com/alexcasalboni/aws-lambda-power-tuning)
- the [Lumigo CLI](https://www.npmjs.com/package/lumigo-cli#lumigo-cli-powertune-lambda) used to automate the tuning process
- my course “[Learn you some Lambda best practice for great good!](https://theburningmonk.thinkific.com/courses/learn-you-some-lambda)” where I discussed power-tuning and other performance and cost optimization techniques for Lambda

Happy tuning!

Liked this article? Support me on Patreon and get direct help from me via a private Slack channel or 1-2-1 mentoring.

[![](https://theburningmonk.com/wp-content/uploads/2019/10/Screenshot-2019-10-19-at-11.44.09.png)](https://www.patreon.com/bePatron?u=905909)

 ![](https://theburningmonk.com/wp-content/uploads/2019/10/img_5dab0c477fc72.png)

Hi, my name is **Yan Cui**. I’m an **[AWS Serverless Hero](https://aws.amazon.com/developer/community/heroes/yan-cui/)** and the author of [**Production-Ready Serverless**](https://bit.ly/production-ready-serverless). I specialise in rapidly transitioning teams to serverless and building production-ready services on AWS.

Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.

You can contact me via [Email](mailto:theburningmonk.com), [Twitter](https://twitter.com/theburningmonk) and [LinkedIn](https://www.linkedin.com/in/theburningmonk/).

[Hire me.](https://theburningmonk.com/hire-me)

The post [How to: optimize Lambda memory size during CI/CD pipeline](https://theburningmonk.com/2020/03/how-to-optimize-lambda-memory-size-during-ci-cd-pipeline/) appeared first on [theburningmonk.com](https://theburningmonk.com).

 ![](http://feeds.feedburner.com/~r/theburningmonk/~4/S8UaKTosKZI)