One of the key motivators in pursuing a serverless architecture is reducing infrastructure costs. This is most important in the early stages of application growth, where the user base is still expanding and the application’s resource usage is markedly lower than a fully-mature application.
In the early stages of your application, leveraging a serverless architecture to reduce costs can free up precious resources that allow you to add additional value, more quickly growing your user base and reaching product-market fit.
However, as your application scales your operational costs will scale with it – potentially eclipsing the cost of maintaining a traditional web application entirely. This gives rise to a basic question – how much does a serverless application cost, in comparison to a traditional client-server model? What about when compared with a container-based microservice application?
In this guide we’ll cover the costs of running a serverless application, and compare them with the resources used by a more traditional application architecture. We’ll discuss the pricing structure of serverless functions among a number of providers, and explore the costs of a serverless application’s infrastructure. We’ll build on that to determine if there is
a tipping point at which it makes sense to swap your infrastructure out and manage your application using a dedicated web server.
Web applications following a traditional architecture have the benefit of a clearly-defined cost structure.
Renting a server in a rack, or a virtual machine, or a slot in a container service, comes with a monthly cost that, in most cases, does not fluctuate often. This makes costs predictable, and allows you to easily tell what your burn rate is going to be from a month-to-month basis.
The other thing this approach allows you to do is build an application that is always available. Your application is running on a machine in a server farm, ready to serve the next user as soon as they send a request. You’re able to scale your application by simply upgrading the capabilities of your standalone server, or by adding other servers to the mix in a load balancer that evenly distributes traffic among your available resources.
This approach is well-understood, and used the world over to run high-availability applications with millions of users. But what if your application doesn’t have millions of users? Or what if you don’t need the workload capacity offered by a dedicated resource, because your application only performs intensive work once a day? If your application faces a large amount of idle time followed by bursts of work to complete, your server spends a large portion of its day sitting idle, costing you money without providing you any value more complex than “it’s there when I need it.”
This is where serverless pricing truly shines. Instead of paying for resources that are always available by the month, serverless pricing focuses on paying only for the resources when you use them. This is known as Pay-As-You-Go (PAYG) pricing. PAYG pricing focuses on the resources used by your application, charging you for CPU cycles and resource usage instead of charging you a flat rate to have a machine constantly available to serve requests. Thus, using a PAYG approach, if your application is idle you don’t pay a cent.
Take, for example, a payments application serving 1,000 users a day. If the user requests are spaced evenly throughout the day, you are going to see one user every 86 seconds. If your requests take three seconds on average to complete, you will have 83 seconds of idle time for each user that visits your application.
Using a traditional client-server model, you simply eat these costs in the interest of keeping your application constantly available with minimal latency. In comparison, a serverless model will only bill you for the 3 seconds used on every request, and will not charge you anything during the time your application is idle. This reduces the amount you spend on infrastructure proportionately, freeing those resources to allow you to develop new features and drive user value.
AWS Lambda functions are billed on two different factors – the number of requests made, and the amount of work performed during those requests. For requests, AWS charges a flat rate of $.20 per 1 million requests after a free buffer is consumed.Usage cost is billed in terms of GB-seconds, which is the number of gigabytes of memory allocated to a task per the seconds that it runs. AWS Lambda gives you the first 400,000 GB-seconds of activity for free, then afterwards charges a small aggregate amount per additional GB-second of operation.
On the Lambda pricing page, AWS helpfully breaks this out into prices per 100 milliseconds of compute time. This amount scales based on the amount of memory allocated to your function, as AWS is billing you for the amount of resources you request – even if you don’t use them. In short – the larger the memory size allocated to your function, the more each 100 millisecond block costs. In addition, you are billed for any data transfer from outside your function’s region (such as from the web at large, or from other AWS services) at the standard AWS transfer rates.
Amazon EC2 usage is billed in one of four different ways:
Depending on your application’s needs, EC2 can either provide stability that your developers can leverage to create robust web applications, or it can provide on-demand usage billed primarily on computing resources used instead of on the simple presence of a dedicated server.
When comparing with AWS Lambda pricing, it’s important to know the characteristics of your application. While Lambda is billed based upon the GB-seconds your functions use during their execution, EC2 requires you to put more thought into machine design as the costs scale with the specifications of the machine you choose. If you can confidently predict your work loads, as well as your hardware requirements, you can likely optimize the costs of EC2 in a significant way.
However, while the actual resource costs could potentially be lower, your development costs are likely to be higher. With an EC2 instance, you need to fully develop your machine’s content, from selecting a web server to spinning up an application instance via middleware in response to user requests. Compare this to AWS Lambda, where you simply need to write your application’s functionality at the most granular level. The time spent on this by your developers can be significant, as can the associated costs.
Comparing a dedicated machine instance to an ephemeral resource like AWS Lambda will always be very situationally-dependent, but there are a few advantages at the conceptual level that can lend weight to choosing a Function-as-a-Service architecture over a more traditional approach:
For low workloads, AWS Lambda is simply cheaper – particularly if your usage falls within the fairly generous free usage tier. Depending on your specific use case, the reduced infrastructure of a Lambda function can be far superior to an equivalent EC2 instance, which would require additional development and configuration. If you’re not reliant upon a specific operating system in an atomic Lambda function, you can eliminate all of the extraneous configuration effort required to make your code functional – simply deploy the code and go!
AWS Lambda gives you far more granular ways to measure your costs than EC2, which bills based on time instead of based on resource usage. You get a per-execution view into the resources used by your Lambda functions, and can use that data to more accurately predict the cost of future executions. This can allow you to react more quickly to increased demand, allowing you to optimize costs as you develop a complete picture of your application’s behavior.
Building upon the granularity of AWS Lambda functions, you can use the data provided to implement cost-driven logic in your application. Each response includes a report on the resources used, giving you the opportunity to leverage this information to postpone or redirect the more expensive operations in your application to more cost-effective resources dynamically. With some clever arbitrage, you can increase your margins while keeping your execution costs low.
With every execution, you get a clear view into what charges your organization incurred. This data, if fed into pricing models, can be used to mitigate the costs of each request. Coupling this with a dynamic pricing engine allows you to change how much you charge your users based upon their actual resource usage. This cost-based pricing allows you to ensure you’re being appropriately paid for the effort your application performs, instead of relying upon a blanket monthly fee that is only profitable for a percentage of your user base.
While the flexibility of Lambda over EC2 gives you a lot of leeway in optimizing your application’s resource expenditures, the serverless approach introduces some unique challenges to gauging your infrastructure expense levels. These disadvantages can add unpredictability to your application’s running costs if not carefully monitored and managed.
One of the hardest parts of optimizing an application is finding out exactly how many resources your application consumes. This is doubly challenging in a serverless environment, as each application path can include an indeterminate number of Lambda invocations. This complicates cost forecasting, adding confusion to infrastructure budgeting.
Lambda can be very susceptible to cost increases due to heightened usage. While ideally this heightened usage can result from an increasing user-base, lending some predictability to the growth, there are several scenarios where you can end up with a large bill with very little warning. DDoS attacks, for example, can very quickly drive your AWS Lambda bills through the roof, since each individual request involved in the attack costs you additional money.
Setting aside the potential for nefarious actors, simple development bugs can result in greatly inflated costs if your developers, for example, add an infinite loop or fail to make use of caching. Even with good development practices and solid application security, you can also end up with inflated costs due to the configuration of your Lambda functions – allocate too much memory to your function, for example, and your costs can scale very quickly.
Building a robust serverless application doesn’t stop at the invocation of your Lambda functions. You need services to store user data, additional development and maintenance load for the disparate functions of your application, and so on. Each of these elements has the potential to increase your costs in a way that wouldn’t necessarily be present in a more traditional EC2-based application.
Take, for example, data storage – with an EC2 instance you could potentially co-locate your database server with your web server using a tool like Docker. With AWS Lambda, however, you’ll need to pay for any data transfer to different AWS regions, and then pay for the storage costs on top of the pure data transmission expenses.
One of the great benefits of a serverless architecture is its general resiliency when scaling. Instead of needing to allocate and deploy additional servers, the serverless provider manages that complexity on your behalf. While this is a significant benefit for application responsiveness and performance, it has the potential to create a severe impact with your next month’s AWS bill. It’s important to recognize how your lambda functions are being used, and by which triggers in the AWS ecosystem. Services that issue a lot of triggers will lead to a lot of invocations of your functions, increasing compute usage and, eventually, your infrastructure bill.
Predicting and responding to these changes in pricing is crucial to ensuring you can get ahead of significant resource usage before it occurs. Each Lambda function response includes information about its execution, statistics which are also pushed to CloudWatch. This information can be used to predict traffic levels and allow you to react to cost-incurring events as they occur. An automated approach is highly-recommended, as predicting sudden bursts of activity in an application is nearly impossible – by writing a script to automatically parse execution data out of your application’s function responses, you can build a predictive model that allows you to set thresholds and alerting. Some open-source projects already exist to provide this information – Concurrency Labs offers a couple in their GitHub repo, for example.
With the flexibility of a serverless application, you gain another benefit over a traditional application when it comes to optimizing your execution costs. The granularity of AWS Lambda billing – and the frequency with which you are given the relevant information – gives you a lot of flexibility in optimizing your application’s resource usage. Below are a few strategies you can use to reduce your infrastructure costs and increase your serverless application’s profit margins.
One of the oft-ignored costs in AWS Lambda development is the cost in data transfer between AWS regions. If your application relies upon AWS resources spread across multiple regions, you’re paying for the data transfer between those services. Moving your Lambda functions to the same region as the resources they depend upon can greatly reduce your data transfer costs, allowing you to focus on the cost of execution alone.
The granularity of Lambda billing gives you great visibility into how much individual function calls are costing your organization. This information is invaluable in optimizing your Lambda costs, as it allows you to quickly identify the financial pain points in your call stack. By using this billing data as a driver, you can accurately identify functions in your stack that seem to be doing more work than necessary, giving you a refactoring opportunity that has significant cost advantages. Additionally, using this approach you can combine groups of independent functions into larger modules, reducing duplicated effort and centralizing costs.
Simply put – if your code is not executing, you aren’t being charged. A solid caching approach can also have a significant effect on your AWS Lambda execution costs.By adding caching to your serverless functions, or performing client-side caching in your front end code, you can reduce your costs simply by performing less work – particularly if your operations are atomic and well-defined.
Microsoft Azure Functions are billed at a very similar level to their AWS Lambda counterparts. Both services grant you one million free requests per month, and charge $.20 per additional million requests. However, Azure gives you a slight cost advantage for aggregate resource usage. AWS Lambda bills at $0.0000166667 per GB-second, while Microsoft Azure Functions are billed at a flat $0.000016. This difference is indeed small, but over time adds up to a price savings of $0.67 per million GB-seconds of execution.
Google Cloud Functions have some unique billing considerations when compared against AWS Lambda. Where AWS Lambda gives you one million free requests, Google Cloud Functions are given two million. Once you’ve exceeded this free tier, Google Cloud Functions will cost twice as much as AWS Lambda ($.40 per million for GCF, compared to $.20 per million for AWS Lambda). In terms of resource usage, Google takes a unique approach in splitting out processor and memory usage into separate cost categories.
The difference in pricing structure complicates the comparison between the two services, but we can estimate that a Google Cloud Function will cost you $0.0000100 for one GHz-second of compute, and $0.0000025 for one GB-second of memory usage if we’re willing to make the assumption that the two scale in proportion to each other. This may not always be the case, though, particularly for a memory-intensive function. A more useful figure is their reported cost per 100ms of execution – for similar-sized machines of 128 MB memory (and a 200 MHz processor on the GCF side), AWS Lambda will run you $0.208 per million seconds versus $0.231 for Google Cloud Functions.
OpenFaaS takes a markedly different approach to AWS Lambda, making it difficult to compare costs. Where AWS Lambda provides you with all the infrastructure you need to execute your functions, OpenFaaS focuses on giving you the execution infrastructure in a hosting-independent fashion. This means that you have to pay to host your functions yourself, rather than relying on the pure usage-based pricing offered by AWS and other providers.
Ultimately this will become a similar comparison to our earlier EC2 vs AWS Lambda section. However, for this extra cost you are gaining a provider-independent platform for your serverless functions. This helps you avoid the vendor lock-in that would be inherent in choosing a provider like AWS, and gives you the ability to more easily transition your serverless framework to a new hosting provider if the costs make more sense.
AWS Lambda can be a powerful tool to help your application get on its feet early. When compared against a traditional client-server architecture, you can realize significant cost savings in the development and launch stages of your application’s life cycle simply by restricting your charges only to the resources you use. Once your application grows you’ll likely want to consider moving to a more traditional hosting scheme, or even switching serverless providers entirely. The granularity of Lambda billing makes finding this tipping point much easier, though it will always be heavily dependent on your application’s size, complexity, and popularity.
While monitoring and maintenance are likely to cost more in a serverless application than in a traditional client-server architecture, these costs are shared by every serverless function provider. AWS Lambda is priced competitively with both Google Cloud Functions and Microsoft Azure Functions, with some minor variances between the three providers, and you also have the option to pursue an OpenFaaS-based solution if you are concerned about ending up locked to a specific vendor. With some careful analysis, you should be able to more effectively optimize your application’s running costs, giving you the ability to respond to cost increases more quickly and minimize your organization’s infrastructure budget.