DEV Community

Wallace Freitas
Wallace Freitas

Posted on

Techniques to Save Costs Using AWS Lambda Functions with CDK

When properly managed, AWS Lambda offers a serverless computing solution that is reasonably priced. However, if functions are not optimized, expenses may increase. With infrastructure as code, developers may save money by effectively provisioning and optimizing Lambda functions with the help of the AWS Cloud Development Kit (CDK). In this post, we'll examine a number of cost-cutting strategies for AWS Lambda functions that make use of the CDK's flexibility and automation capabilities.

1. Optimize Memory Allocation and Timeout Settings

Memory and timeout settings for Lambda functions are critical cost factors. Allocating the right amount of memory ensures the function runs efficiently without excessive costs.

CDK Example: Setting Optimal Memory and Timeout

With CDK, you can define memory and timeout configurations to ensure that each Lambda has the resources it needs without over-allocation:

import * as lambda from 'aws-cdk-lib/aws-lambda';

const myLambda = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('path/to/my/function'),
  memorySize: 512, // Set optimal memory based on testing
  timeout: cdk.Duration.seconds(10), // Set based on expected execution time
});
Enter fullscreen mode Exit fullscreen mode

By adjusting memory and timeout values, you can avoid excess charges from prolonged executions or under-optimized performance.

2. Enable Provisioned Concurrency Only When Necessary

Provisioned Concurrency keeps functions warm, reducing cold starts for latency-sensitive applications. However, enabling it unnecessarily can increase costs. CDK makes it easy to apply Provisioned Concurrency selectively.

CDK Example: Conditional Provisioned Concurrency

const myLambda = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.PYTHON_3_9,
  handler: 'app.handler',
  code: lambda.Code.fromAsset('lambda'),
});

// Set provisioned concurrency only for critical functions
const alias = new lambda.Alias(this, 'MyFunctionAlias', {
  aliasName: 'Prod',
  version: myLambda.currentVersion,
  provisionedConcurrentExecutions: 5, // Adjust as needed
});
Enter fullscreen mode Exit fullscreen mode

By using aliases, you can allocate Provisioned Concurrency only to critical Lambda functions, reducing unnecessary expenses.

3. Use Reserved Concurrency for Cost Control

Setting reserved concurrency helps manage the maximum number of concurrent executions, which can prevent cost overruns during high-traffic periods.

CDK Example: Reserved Concurrency

const myLambda = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('lambda'),
  reservedConcurrentExecutions: 10, // Limit to control usage
});
Enter fullscreen mode Exit fullscreen mode

This approach can cap usage to an acceptable limit, helping avoid unexpected spikes in execution costs.

4. Implement Efficient Logging and Monitoring

AWS Lambda functions incur additional costs from excessive logging in Amazon CloudWatch. Use CDK to set log retention policies and control the volume of logs.

CDK Example: Configuring Log Retention

const myLambda = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.PYTHON_3_9,
  handler: 'app.handler',
  code: lambda.Code.fromAsset('lambda'),
  logRetention: logs.RetentionDays.ONE_WEEK, // Set log retention to reduce costs
});
Enter fullscreen mode Exit fullscreen mode

This reduces the cost of long-term log storage by retaining logs only as needed.

5. Reuse Lambda Layers to Reduce Package Size

Larger deployment packages lead to increased latency, potentially extending runtime costs. By leveraging Lambda Layers, you can reuse common libraries across functions, reducing individual package sizes.

CDK Example: Adding a Lambda Layer

const layer = new lambda.LayerVersion(this, 'MyLayer', {
  code: lambda.Code.fromAsset('path/to/layer'),
  compatibleRuntimes: [lambda.Runtime.NODEJS_18_X],
});

const myLambda = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('lambda'),
  layers: [layer], // Reuse layer for multiple functions
});
Enter fullscreen mode Exit fullscreen mode

By reusing layers, you can keep Lambda package sizes small, which can help reduce execution time and improve performance.

6. Use S3 Event Triggers for Low-Cost Storage and Processing

Instead of storing large data within Lambda, offload it to S3. Configure S3 event triggers to invoke Lambda only when necessary, allowing you to minimize data processing within the function.

CDK Example: S3 Trigger for Lambda

import * as s3 from 'aws-cdk-lib/aws-s3';

const bucket = new s3.Bucket(this, 'MyBucket', {
  versioned: true,
});

bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(myLambda));
Enter fullscreen mode Exit fullscreen mode

This setup uses S3 as a low-cost storage solution and invokes Lambda only when a file is uploaded, saving on continuous processing costs.

7. Schedule Functions with EventBridge Instead of Frequent Invocations

Frequent invocations can increase costs, especially for periodic or batch tasks. By using EventBridge to schedule Lambda functions, you can control invocation frequency based on specific times rather than continuous monitoring.

CDK Example: EventBridge Scheduled Invocation

import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';

const rule = new events.Rule(this, 'Rule', {
  schedule: events.Schedule.expression('rate(1 hour)'),
});

rule.addTarget(new targets.LambdaFunction(myLambda));
Enter fullscreen mode Exit fullscreen mode

This rule invokes the Lambda function on a set schedule, helping reduce unnecessary executions and associated costs.

Conclusion

Although AWS Lambda's serverless paradigm is naturally economical, significant savings can be achieved by optimizing for maximum efficiency. You can optimize the efficiency of your Lambda functions while controlling expenses by utilizing CDK to manage configurations like memory allocation, parallelism, log retention, and event triggers. These methods offer a cost-effective, scalable, and efficient way to implement serverless features.

Top comments (0)