Measuring Performance in .NET: Single Purpose vs Monolithic Lambda Function

Somebody who likes to code
Search for a command to run...

Somebody who likes to code
No comments yet. Be the first to comment.
In the AWS Lambda ecosystem, the cold start problem could be a key factor to use it or not, especially if you're developing a customer-facing application that needs to operate in real-time. AWS is continuously releasing new features to minimize the i...
Google processes tens of thousands of code changes every day across a codebase of hundreds of millions of lines. The secret isn't magic tooling — it's a documented, principled approach to code review

Amazon Simple Notification Service (SNS) looks straightforward on the surface — publish a message, deliver it to subscribers — but the gap between a topic that "works in dev" and one that is productio

Amazon Simple Queue Service (SQS) is deceptively simple to get started with, but surprisingly easy to misconfigure in ways that cause silent message loss, runaway costs, duplicate processing storms, o

HTTP API is the right default choice for the majority of .NET serverless workloads. At 70% less cost than REST API, lower latency, and native JWT authorization, it covers most production requirements

AWS Lambda has become a cornerstone of modern serverless architectures, but writing a function that "just works" is very different from writing one that is performant, cost-effective, secure, and read

Single Purpose and Monolithic Lambda Functions are two approaches to developing and deploying our applications (you can check the pros and cons here). But what are the differences from the performance perspective?
To answer this question, we develop two applications. One using .NET 6 Minimal API (Monolithic Lambda Function) and the other using the AWS Lambda Project Template (Single Purpose Lambda Function) from the NuGet package Amazon.Lambda.Templates, both are going to do the same (the code can be found here):
For both Lambda Functions, we are using 512 Mb. For testing (three times), we are using K6 with the following workloads:
Let's take a look at the results of the first run:
| Application | Min | Avg | Max | Median | P95 | P99 |
| Monolithic | 25ms | 48ms | 2054ms | 36ms | 85ms | 116ms |
| Single Purpose | 25ms | 46ms | 1296ms | 37ms | 79ms | 119ms |
Second execution:
| Application | Min | Avg | Max | Median | P95 | P99 |
| Monolithic | 25ms | 48ms | 2012ms | 37ms | 69ms | 99ms |
| Single Purpose | 25ms | 45ms | 1186ms | 36ms | 75ms | 114ms |
Last execution:
| Application | Min | Avg | Max | Median | P95 | P99 |
| Monolithic | 27ms | 50ms | 1910ms | 40ms | 70ms | 119ms |
| Single Purpose | 27ms | 46ms | 1043ms | 37ms | 72ms | 114ms |
As we can see the average response times are quite the same, and we could state that there is no difference between the two approaches. The real difference comes when we see the maximum response time which is related to the cold starts. The cold start produced by the Monolithic Lambda Function is higher than the Single Purpose Lambda Function option. This makes sense since the .NET 6 Minimal API has more code to load when compared to the AWS Lambda Project Template.
To confirm that the maximum response times are caused by the cold start, we enabled X-Ray in both applications to analyze the slowest requests (from the third run). Monolithic Lambda Function:

Single Purpose Lambda Function:

While the advantages of using the .NET 6 Minimal API to build our applications are great, there is a price to pay (longer cold start time) when using AWS Lambda as a deployment strategy. If your application needs to be as fast as possible on every request, we might suggest using the Single Purpose approach. And thinking even further, if the request duration is a requirement in your application, perhaps we could move away from the serverless approach and use Beanstalk or EKS to host our applications. Thanks, and happy coding.