Maximizing AWS Lambda Efficiency: Streamlined Cost Analysis and Automation

Midhun Das
Towards Dev
Published in
5 min readDec 17, 2023

--

In the ever-evolving landscape of cloud computing, managing costs efficiently is paramount. AWS Lambda, a serverless computing service, empowers developers to run code without the hassle of server management. However, keeping track of Lambda function usage and associated costs can be challenging. In this story, we’ll explore a Python script that streamlines Lambda cost analysis, estimates expenses, and generates comprehensive reports, ultimately saving time and providing actionable insights.

Factors Influencing AWS Lambda Costs

Request Count: Lambda costs are tied to the number of requests your functions receive. .Each request costs ~$0.0000002.

Duration: Duration is calculated from the time your code begins executing until it returns or otherwise terminates, rounded up to the nearest 100ms. But, the price is not charged per second. Rather, it is charged per GB-second, which is the duration in seconds multiplied by the maximum memory size in GB. Every GB-second costs $0.0000166667.

Free Tier Considerations: AWS offers a free tier for Lambda, allowing a specific number of requests and compute time at no cost. It’s essential to understand these limitations and how they may affect your overall expenses.

Account Pricing: Lambda pricing varies based on your AWS account and region. Different regions may have different costs per millisecond of execution time. Therefore, understanding your account’s pricing details is vital for accurate cost estimation.

Automating Lambda Cost Analysis

To streamline Lambda cost analysis, a Python script can automate the process, providing detailed insights without the need for manual exploration. Here’s an overview of how the script works.

The script utilizes the Boto3 library, the AWS SDK for Python, to interact with AWS services. Specifically, the boto3.client function creates an AWS Lambda client, enabling communication with the Lambda service.

session = boto3.Session(profile_name=aws_profile, region_name=region)
client = session.client('lambda', region_name=region)
cloudwatch = session.client('cloudwatch', region_name=region)

Listing Lambda Functions: The script then uses the list_functions method to retrieve a list of your Lambda functions. This method allows you to specify parameters such as the maximum number of functions to retrieve and a marker to paginate through the results if necessary.

  next_marker = None
while True:
if next_marker:
response = client.list_functions(MaxItems=200, Marker=next_marker)
else:
response = client.list_functions(MaxItems=200)
functions = response['Functions']
for function in functions:
function_name = function['FunctionName']
memory_size = function['MemorySize']
tags_response = client.list_tags(Resource=function['FunctionArn'])
tags = tags_response['Tags'] if 'Tags' in tags_response else {}
metrics_response = cloudwatch.get_metric_data(
MetricDataQueries=[
{
'Id': 'invocations',
'MetricStat': {
'Metric': {
'Namespace': 'AWS/Lambda',
'MetricName': 'Invocations',
'Dimensions': [
{
'Name': 'FunctionName',
'Value': function_name
},
]
},
'Period': cloud_watch_period,
'Stat': 'Sum',
},
},
{
'Id': 'duration',
'MetricStat': {
'Metric': {
'Namespace': 'AWS/Lambda',
'MetricName': 'Duration',
'Dimensions': [
{
'Name': 'FunctionName',
'Value': function_name
},
]
},
'Period': cloud_watch_period,
'Stat': 'Average',
},
},
],
StartTime=start_time,
EndTime=end_time,
)
invocation_values = metrics_response.get('MetricDataResults', [])[0].get('Values', []) if metrics_response else []
duration_values = metrics_response.get('MetricDataResults', [])[1].get('Values', []) if metrics_response else []
invocation_count = invocation_values[0] if invocation_values else 'N/A'
duration = duration_values[0] if duration_values else 'N/A'
# Calculate estimated cost based on Lambda pricing
estimated_cost = calculate_lambda_cost(invocation_count, duration, memory_size)

Calculating Cost Using CloudWatch Metrics

The script leverages CloudWatch metrics, retrieving key data points such as invocation count and duration. It then calculates the estimated cost for each Lambda function based on your specified pricing logic.

def calculate_lambda_cost(invocation_count, duration, memory):
# Replace this with your actual cost calculation logic based on Lambda pricing
invocation_count = float(invocation_count) if invocation_count != 'N/A' else 0
duration = float(duration) if duration != 'N/A' else 0
memory = memory if memory != 'N/A' else 0
duration_sec = duration/1000
gbsec = invocation_count * duration_sec * memory/1024
total_cost = gbsec * cost_per_sec
return round(total_cost, 3)

Generating the CSV Report

The script creates a CSV report containing crucial information about each Lambda function, including invocation count, duration, estimated cost, memory size, and associated tags. The report is sorted based on estimated costs to facilitate prioritized resource allocation.

# Write the sorted rows and total estimated cost row to the CSV file
with open(output_file, 'w', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(csv_rows)
writer.writerow({
'FunctionName': 'Total-estimated-cost',
'EstimatedCost($)(approx)': estimated_cost_sum
})

Mailing the Report

Upon generating the report, the script composes an email with an HTML body highlighting key insights. It attaches the CSV report to the email and sends it to the specified recipients via SMTP. This automated email delivery ensures that stakeholders receive timely and actionable cost information.

# Compose and send an email with the report and CSV attachment
message = MIMEMultipart()
# ...
message.attach(MIMEText(html_body, "html"))

# Attach the CSV file to the email
with open(output_file, 'rb') as file:
attachment = email.mime.base.MIMEBase('application', 'octet-stream')
attachment.set_payload(file.read())
email.encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', f'attachment; filename={output_file}')
message.attach(attachment)

try:
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.send_message(message)
print('Email sent successfully!')
except smtplib.SMTPException as e:
print('Error sending email:', str(e))

Advantages of Automated Lambda Cost Analysis

Transparency in Cost Allocation

One of the primary challenges in serverless architectures is understanding where costs accrue. The script utilizes CloudWatch metrics to fetch critical data points like invocation count, duration, and memory usage for each Lambda function. With this information, users gain transparency into how resources contribute to overall costs.

Automated Reporting for Timely Insights

The automated reporting feature of the script saves considerable time compared to manual exploration of Lambda details through the AWS Management Console. The script generates a CSV report with crucial details for each Lambda function, including invocation count, duration, estimated cost, and associated tags. Additionally, it sends an email with a summary and an attachment of the CSV report, ensuring timely delivery of cost insights.

Efficient Resource Allocation

Sorting Lambda functions based on estimated costs allows users to prioritize resource optimization efforts. By identifying top-performing functions contributing to higher costs, users can make informed decisions about resource allocation and potentially reduce expenses.

Seamless Integration with Jenkins

One of the script’s key strengths is its compatibility with Jenkins, a popular automation server. By passing AWS account details and analysis parameters as Jenkins parameters, users can seamlessly integrate this script into their continuous integration/continuous deployment (CI/CD) pipelines. This integration streamlines the cost analysis process, making it part of the development workflow without manual intervention.

In conclusion, this Python script emerges as a powerful tool for AWS users seeking to optimize Lambda cost management. By automating the analysis, reporting, and delivery processes, the script enables users to stay proactive in controlling expenses and making informed decisions about resource allocation. With its compatibility with Jenkins, integration into CI/CD pipelines becomes seamless, further enhancing the efficiency of the development workflow.

--

--