This post is about raising awareness of a performance penalty when initializing the AWS SDK for .NET.
This is a startup tax incurred by all AWS Lambda functions using .NET. Fortunately, it's trivial to make it happen during the INIT phase where it's free. However, there is no way of avoiding it during a cold start. I can't help but think the initialization overhead should be much lower.
For this benchmark, our code is almost identical with the baseline function, except that we initialize an S3 client in the constructor.
using System.IO;
using System.Threading.Tasks;
using Amazon.S3;
namespace Benchmark.AwsSdk {
public sealed class Function {
//--- Fields ---
private IAmazonS3? _s3Client;
//--- Constructors ---
public Function() {
// initialize S3 client
_s3Client = new AmazonS3Client();
}
//--- Methods ---
public async Task<Stream> ProcessAsync(Stream request) {
return Stream.Null;
}
}
}
Cold Start Durations
The following table shows the new measurements using .NET 6, Tiered Compilation, and ReadyToRun with 3 different memory configurations: 1,024 MB, 1,769 MB, and 5,120 MB.
Initializing the AWS SDK for .NET adds a 120+ ms penalty to the cold start duration. The impact remains the same, no matter the memory configuration since the initialization is happening during the INIT phase.
Architecture | Memory Size | Tiered | Ready2Run | PreJIT | Init | Cold Used | Total Cold Start | Penalty |
---|---|---|---|---|---|---|---|---|
arm64 | 1024MB | yes | yes | no | 380.461 | 41.773 | 422.234 | 147.21 |
arm64 | 1769MB | yes | yes | no | 377.036 | 29.365 | 406.401 | 141.856 |
arm64 | 5120MB | yes | yes | no | 349.227 | 28.428 | 377.655 | 136.467 |
x86_64 | 1024MB | yes | yes | no | 344.643 | 29.678 | 374.321 | 128.797 |
x86_64 | 1769MB | yes | yes | no | 339.3 | 23.058 | 362.358 | 122.975 |
x86_64 | 5120MB | yes | yes | no | 325.178 | 22.468 | 347.646 | 124.422 |
Potential Cause
Looking at the code for the AWS SDK for .NET, I suspect the culprit of the slow initialization is the endpoints.js file. This 700+ KB megalodon JSON file is parsed every time the AWS SDK is initialized. Since this happens in the AWS Core assembly, this penalty is incurred by all AWS service clients.
I hope this is something the AWS team fixes in the future. As a clueless layman, I would expect the endpoint definitions to belong to their respective packages. This would also produce a smaller Lambda deployment package as the current AWSSDK.Core.dll assembly size is an eyewatering 1.5 MB!
What's Next
In the next post, I'm benchmarking the impact of using top-level statements with Lambda functions. This new way of writing Lambda code is aesthetically pleasing, but does it have a hidden cost?
Top comments (0)