{"id":166,"date":"2026-08-28T13:21:30","date_gmt":"2026-08-28T12:21:30","guid":{"rendered":"https:\/\/mgc-it.co.uk\/?p=166"},"modified":"2026-08-28T13:21:31","modified_gmt":"2026-08-28T12:21:31","slug":"dont-starve-your-lambda-functions","status":"publish","type":"post","link":"https:\/\/mgc-it.co.uk\/index.php\/2026\/08\/28\/dont-starve-your-lambda-functions\/","title":{"rendered":"Don&#8217;t starve your Lambda functions!"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Reducing Lambda memory does not always reduce Lambda cost.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I recently tuned an AWS Lambda function that processes medical-report notifications received through Amazon SQS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is not a minimal Lambda function. It runs on a <strong>PowerShell custom runtime<\/strong> and uses multiple Lambda layers, including:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the PowerShell runtime;<\/li>\n\n\n\n<li>Firely SDK assemblies for parsing FHIR R4 messages;<\/li>\n\n\n\n<li>AWS Tools for PowerShell;<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">During a cold start, Lambda must create the execution environment, load the custom runtime, make the layers available, import the modules and load the .NET assemblies before processing the message.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That matters because Lambda memory is also a performance setting. AWS allocates CPU in proportion to configured memory, so reducing memory can slow runtime initialisation and execution.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The test<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I compared four memory settings using the same synthetic medical-report notification.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For each setting, I collected four confirmed cold starts and measured:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>billed duration;<\/li>\n\n\n\n<li>initialisation duration;<\/li>\n\n\n\n<li>maximum memory used;<\/li>\n\n\n\n<li>billed GB-seconds.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">GB-seconds are the key cost measure because Lambda compute usage depends on both allocated memory and execution duration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The results<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Memory<\/th><th>Average billed duration<\/th><th>Average GB-seconds<\/th><\/tr><tr><td>384 MB<\/td><td>13.83 seconds<\/td><td><strong>5.187<\/strong><\/td><\/tr><tr><td>512 MB<\/td><td>10.88 seconds<\/td><td><strong>5.442<\/strong><\/td><\/tr><tr><td>624 MB<\/td><td>8.77 seconds<\/td><td><strong>5.343<\/strong><\/td><\/tr><tr><td>768 MB<\/td><td>7.29 seconds<\/td><td><strong>5.467<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Maximum memory use stayed close to 330 MB throughout, but execution became faster as the configured memory increased. Because AWS allocates CPU in proportion to Lambda memory (reference: <a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/configuration-memory.html\">Configure Lambda function memory &#8211; AWS Lambda<\/a>), the results suggest that the workload benefited from the additional compute capacity rather than from additional usable RAM.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"523\" src=\"https:\/\/mgc-it.co.uk\/wp-content\/uploads\/2026\/08\/image-1024x523.png\" alt=\"\" class=\"wp-image-167\" srcset=\"https:\/\/mgc-it.co.uk\/wp-content\/uploads\/2026\/08\/image-1024x523.png 1024w, https:\/\/mgc-it.co.uk\/wp-content\/uploads\/2026\/08\/image-300x153.png 300w, https:\/\/mgc-it.co.uk\/wp-content\/uploads\/2026\/08\/image-767x392.png 767w, https:\/\/mgc-it.co.uk\/wp-content\/uploads\/2026\/08\/image-1536x785.png 1536w, https:\/\/mgc-it.co.uk\/wp-content\/uploads\/2026\/08\/image-2048x1046.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The 384 MB setting produced the lowest GB-second figure, but it was approximately <strong>58% slower than 624 MB<\/strong> for a saving of only around <strong>3%<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">More unexpectedly, 512 MB was both:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>approximately <strong>24% slower<\/strong> than 624 MB;<\/li>\n\n\n\n<li>approximately <strong>2% more expensive<\/strong> in measured GB-seconds.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Reducing memory had made the function slower without making it cheaper.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At 768 MB, execution was faster again, but compute use increased slightly. For this asynchronous SQS workload, that additional speed was not valuable enough to justify the extra capacity.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why 624 MB?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The 624 MB value was not originally selected as a carefully calculated target. It was simply a value reached while increasing memory during earlier testing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In hindsight, <strong>640 MB would have been a more logical test point<\/strong>, because it is a multiple of 128 MB. However, 624 MB was the setting for which we already had operational and performance evidence, and the results showed it to be the best tested balance.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The lesson<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Do not size Lambda functions using maximum memory consumption alone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This function using approximately 330 MB was not necessarily best configured with just a little headroom at 384 MB. Memory allocation also affects the CPU available for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>custom-runtime startup;<\/li>\n\n\n\n<li>module imports;<\/li>\n\n\n\n<li>Lambda layer loading;<\/li>\n\n\n\n<li>dependency initialisation;<\/li>\n\n\n\n<li>parsing;<\/li>\n\n\n\n<li>serialisation;<\/li>\n\n\n\n<li>application processing.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Lamdba functions clearly need tuning once created. Don&#8217;t just ask if there&#8217;s enough memory to complete execution, instead:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Which memory setting gives the best balance of execution time, compute usage and operational performance?<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">For this function, the sweet spot was <strong>624 MB<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Sometimes the cheapest way to run a Lambda function is to stop starving it.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Further references<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/alexcasalboni\/aws-lambda-power-tuning\">alexcasalboni\/aws-lambda-power-tuning: AWS Lambda Power Tuning is an open-source tool that can help you visualize and fine-tune the memory\/power configuration of Lambda functions. It runs in your own AWS account &#8211; powered by AWS Step Functions &#8211; and it supports three optimization strategies: cost, speed, and balanced.<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Reducing Lambda memory does not always reduce Lambda cost. I recently tuned an AWS Lambda function that processes medical-report notifications received through Amazon SQS. This is not a minimal Lambda function. It runs on a PowerShell custom runtime and uses multiple Lambda layers, including: During a cold start, Lambda must create the execution environment, load [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[14],"class_list":["post-166","post","type-post","status-publish","format-standard","hentry","category-cloud-engineering","tag-aws"],"_links":{"self":[{"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/166","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/comments?post=166"}],"version-history":[{"count":2,"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/166\/revisions"}],"predecessor-version":[{"id":169,"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/166\/revisions\/169"}],"wp:attachment":[{"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/media?parent=166"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/categories?post=166"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mgc-it.co.uk\/index.php\/wp-json\/wp\/v2\/tags?post=166"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}