More and more teams are building their applications on AWS Lambda. That makes sense: AWS handles the infrastructure, and your developers can focus their time on functionality. Lambda is also known for being inexpensive. I’ve done the math and tested whether that’s actually true. For many web applications, it isn’t.
EC2 vs. Lambda: The Simple Math
Both EC2 and Lambda are billed based on CPU and memory usage. With a Lambda function, you only set the memory allocation. AWS applies a fixed ratio of 1 vCPU per 1,769 MB, which you cannot change. This ratio is close to that of EC2’s compute-optimized instances (the c-family), which have 1 vCPU per 2 GB of memory.
A c6g.large instance has 2 vCPUs and 4 GB of memory. Running it for a full month in the Ireland region (eu-west-1) costs $53.29 on-demand, without reservations, Savings Plans, or Spot.
To achieve the same computing power on Lambda, set the memory to 3,538 MB. Suppose the function runs for 1 second and receives exactly 1 request per second. In that case, a single function runs 24/7, which costs $121.60 per month: 2.29 times as much as the comparable EC2 capacity.
Paying twice to avoid having to manage instances can be a conscious choice. For many applications, however, the difference is much greater than a factor of two.
A lambda function is also idle
Most applications retrieve data from elsewhere: a row from a database, an object from an S3 bucket, or a response from an external API. A typical request goes through the following steps: parsing the request, checking permissions, sending a query to the database, processing the response, and sending the response back to the client.
There's one step missing from that list: waiting for the database. That wait time usually lasts between 5 and 1,000 ms. The function doesn't process anything during that time, but you still pay for the duration.
An EC2 instance doesn’t sit idle during that time, but a Lambda function does. API Gateway initiates a separate Lambda invocation for each request: 1,000 requests per second equate to 1,000 invocations per second. If an invocation takes an average of 4 ms and waits 200 ms, you’ll be charged for 204 ms—1,000 times per second. The costs on Lambda therefore increase linearly with the response time of the services you’re waiting for.
That doesn't happen on EC2. Depending on the application, even a small instance can handle thousands of requests at once, no matter how slowly the downstream service responds.
The Load Test on EC2
To measure that, I set up the configuration shown below. A c6g.xlarge instance generates the load against a c6g.large instance running a simple Node.js application built on Express. That application makes a single fetch() call to an external API and returns the result. The external API waits for a configurable amount of time before responding. I varied that response time from 20 to 1,000 ms.
Each test uses the "hey" tool to send 50,000 requests over 5,000 connections. The two extremes are shown below.
The fastest response time slowed by about one second, but throughput dropped by only about 500 requests per second: from 2,336 to 1,824. If you consistently utilize a fleet of instances to full capacity, this will increase the cost per request on EC2 by about 28%.
For a Lambda function with exactly the same application, costs would increase by 607%.
EC2 is so much more efficient here because the instance bundles all requests. If a request is waiting for network I/O, Node.js’s asynchronous processing ensures that the CPU handles other connections in the meantime. A Lambda invocation gets its own execution environment for exactly one request and cannot take advantage of that benefit.
When Lambda Is and Isn't the Right Choice
In production, you rarely see these ratios reflected so precisely. Lambda has built-in fault tolerance. To achieve the same level of resilience on EC2, you need to distribute instances across three availability zones and run with at least 33% overcapacity. In addition, the load in production is rarely stable, and instances almost never run continuously at 100% capacity.
With large-scale web applications, these effects do matter. Lambda is a good service, but it isn’t the cheapest option for every application. With a high volume of requests and slow downstream services, you’re mainly paying for wait time on Lambda. Be sure to factor that in before choosing an architecture. We also take those architectural choices into account when conducting a cloud cost analysis.
To learn how SUE reduces and keeps cloud costs low, visit the Cloud Cost Optimization and FinOps page. The guide to reducing cloud costs shows which measures are most effective.