Boosting AWS Lambda Performance with In-memory Cache
Introduction
AWS Lambda users can utilize in-memory cache to improve performance and reduce costs.
For example, a secret value stored in your Secrets Manager can be cached outside the handler
unless you need the latest value. This technique is known as static initialization.
This post demonstrates how to optimize AWS Lambda functions with in-memory cache using JavaScript closures.
Non-optimized Lambda Function
Key Issues
- Instantiates
SecretsManagerClient
on every invocation. - Fetches a secret value from Secrets Manager every time the function is called.
import {
SecretsManagerClient,
GetSecretValueCommand,
} from '@aws-sdk/client-secrets-manager';
export async function handler(event) {
const client = new SecretsManagerClient();
const command = new GetSecretValueCommand({ SecretId: '<YOUR_SECRET_ID>' });
const { SecretString } = await client.send(command);
return {
statusCode: 200,
body: SecretString,
};
}
Execution Results
Running this function multiple times reveals inefficiencies. For instance, the following logs show a Duration
of 153.66 ms per invocation:
Function Logs
START RequestId: 55f3596f-b4c1-4fcd-bc34-2c63674bd3cd Version: $LATEST
END RequestId: 55f3596f-b4c1-4fcd-bc34-2c63674bd3cd
REPORT RequestId: 55f3596f-b4c1-4fcd-bc34-2c63674bd3cd Duration: 153.66 ms Billed Duration: 154 ms Memory Size: 128 MB Max Memory Used: 89 MB
Optimized Lambda Function
Key Improvements
- Implements caching with closures in
useGetSecret
. - Caches the secret value on the first call, minimizing subsequent fetches until the Lambda runtime is terminated.
- Ensures separation of concerns, where callers of
getSecret
remain unaware of the caching logic.
import {
SecretsManagerClient,
GetSecretValueCommand,
} from '@aws-sdk/client-secrets-manager';
const getSecret = useGetSecret('<YOUR_SECRET_ID>');
export const handler = async (event) => {
const secret = await getSecret();
return {
statusCode: 200,
body: secret,
};
};
function useGetSecret(id) {
const client = new SecretsManagerClient();
const command = new GetSecretValueCommand({ SecretId: id });
let secret = '';
return async () => {
if (secret) {
return secret;
}
const { SecretString } = await client.send(command);
secret = SecretString;
return secret;
};
}
Execution Results
The optimized function significantly reduces execution time. For example, the following logs show a Duration
of only 1.28 ms per invocation:
Function Logs
START RequestId: aaba6d16-19ee-437a-9592-f708b3ed7c8b Version: $LATEST
END RequestId: aaba6d16-19ee-437a-9592-f708b3ed7c8b
REPORT RequestId: aaba6d16-19ee-437a-9592-f708b3ed7c8b Duration: 1.28 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 88 MB
Conclusion
AWS Lambda users can greatly improve function performance and reduce costs by adopting in-memory caching techniques like closures. This simple adjustment minimizes redundant processes and enhances execution efficiency.
Happy Coding! 🚀