Introduction
In the part 27 of this article series, we introduced (full) APIGatewayProxyRequestEvent SnapStart priming and compared its Lambda performance with DynamoDB request invocation priming. We saw that the former has consistently lower (up to several hundred milliseconds, depending on the percentile) cold start times, which is quite impressive. Particularly, the effect of the APIGatewayProxyRequestEvent Lambda SnapStart priming was noticeable with respect to the SnapStart tiered cache (see the last 70 measurements). The warm start times were nearly the same, except for the max values, as the proper priming reduces one-time initialization during handleRequest method invocation as well. It's up to you to adopt this for your use case or not, because yes, it requires some additional (but simple) code to be written.
One of the readers asked the question of how this priming technique behaves with less memory given to the Lambda function, as I always give it 1024 MB as a starting point. Trying out different Lambda memory settings is one of the biggest factors that impact Lambda performance and cost. Maybe even 256 MB would be acceptable and deliver a good performance, and we can save money?
Measuring cold and warm start time of the AWS Lambda function with the different memory settings
We'll use the same sample project and way of measuring Lambda performance as described in part 27, but with different Lambda memory settings between 256 MB and 1792 MB. Here are the results:
Cold (c) and warm (w) start time in ms:
| Scenario Number | c p50 | c p75 | c p90 | c p99 | c p99.9 | c max | w p50 | w p75 | w p90 | w p99 | w p99.9 | w max |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 256 MB | 1374 | 1423 | 1877 | 1901 | 1901 | 1902 | 6.21 | 14.10 | 21.23 | 63.93 | 159.38 | 1230 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 256 MB | 1357 | 1393 | 1432 | 1543 | 1543 | 1543 | 6.02 | 13.66 | 20.57 | 61.95 | 149.65 | 1001 |
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 512 MB | 888 | 970 | 1385 | 1399 | 1399 | 1400 | 5.47 | 6.21 | 7.87 | 31.83 | 93.67 | 866 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 512 MB | 869 | 906 | 983 | 1182 | 1182 | 1182 | 5.47 | 6.11 | 7.75 | 31.33 | 81.20 | 523 |
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 768 MB | 720 | 757 | 1348 | 1386 | 1397 | 1398 | 5.55 | 6.30 | 7.51 | 20.41 | 53.74 | 736 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 768 MB | 713 | 732 | 780 | 921 | 921 | 921 | 5.47 | 6.21 | 7.39 | 20.09 | 50.44 | 334 |
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 1024 MB | 642 | 671 | 1207 | 1227 | 1232 | 1241 | 5.64 | 6.30 | 7.27 | 15.50 | 38.45 | 748 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 1024 MB | 628 | 652 | 686 | 791 | 791 | 791 | 5.59 | 6.25 | 7.21 | 15.14 | 36.37 | 264 |
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 1280 MB | 596 | 682 | 1144 | 1157 | 1158 | 1160 | 5.59 | 6.30 | 7.33 | 13.43 | 37.25 | 639 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 1280 MB | 579 | 616 | 677 | 773 | 773 | 773 | 5.50 | 6.20 | 7.16 | 12.80 | 35.23 | 201 |
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 1536 MB | 604 | 661 | 1147 | 1160 | 1173 | 1174 | 5.59 | 6.25 | 7.33 | 13.01 | 36.08 | 551 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 1536 MB | 582 | 604 | 640 | 689 | 689 | 689 | 5.59 | 6.25 | 7.33 | 13.11 | 32.79 | 176 |
| SnapStart enabled with full APIGatewayProxyRequestEvent priming, all, 1792 MB | 604 | 662 | 1182 | 1192 | 1195 | 1197 | 5.64 | 6.35 | 7.51 | 13.22 | 37.84 | 730 |
| SnapStart enabled with full APIGatewayProxyRequestEvent, last 70, 1792 MB | 585 | 595 | 644 | 670 | 670 | 670 | 5.59 | 6.30 | 7.39 | 13.11 | 33.31 | 190 |
Conclusion
We see that setting 256 MB of memory to the Lambda function, even with the full APIGatewayProxyRequestEvent priming, leads to very high Lambda cold and warm start times. Depending on the performance and cost requirements of our use case, memory settings between 512 MB and 1024 MB may be very acceptable. Giving Lambda more memory between 1024 MB and 1280 MB for this particular use case leads to only a slight improvement in the Lambda performance but a much higher cost. This might be an acceptable trade-off from the business perspective. Giving the Lambda function more memory than 1280 MB didn't improve Lambda performance (besides the max value for the warm start times) but led to a much higher Lambda cost. Trying out to set more than 1792 MB of memory only makes sense if our application can benefit from doing things in parallel, but our sample application is single-threaded. When the allocated memory crosses the Lambda memory size limit of 1.792 MB, it adds the equivalent of one full vCPU (one vCPU-second of credits per second), so for the maximum of 10 GB of Lambda memory to be set, we get access to maximal 6 full vCPUs.
Update from 7 July 2025
As described in the part 27, I discovered that the aws-lambda-java-serialization dependency is also provided by the AWS Lambda Java Runtime Interface Client, so we can set its scope to provided in pom.xml like this :
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-serialization</artifactId>
<version>1.1.5</version>
<scope>provided</scope>
</dependency>
That's why, please re-measure Lambda performance for the above-provided Lambda memory settings by not packaging the aws-lambda-java-serialization dependency in the deployment artifact. We've already re-measured it for the 1024 MB memory setting in part 27 and saw some slight improvements in the Lambda performance.
Top comments (0)