In my previous story, Gabriel Flores asked me about cost comparison. Indeed, choosing a solution from a technical point of view is important, but the cost of a service isn’t to forget because, in auto scaling environment, it can blow up without warning.
The comparison performed in only based on the pricing and Quotas & limits of each product. The performance of processing are supposed equals in both solutions.
Cloud functions pricing is based on the vCPU in GHz/s and the memory in Gb/s, rounded up to the nearest 100ms. The specificity of functions is that you can adjust the memory and the CPU speed, but not separately. Both are linked, increase the memory if you want more MHz and vice versa
Network egress price is a flat rate of $0.12/Gb
Finally, requests are billed at $0.40 the million of requests after the 2 millions of free quota
Cloud Run (managed)
Cloud Run pricing is based on vCPU/s and the memory in Gb/s, rounded up to the nearest 100ms. It’s not possible to use partial vCPU per instance. Your instance has always 1 vCPU assigned. Memory can be adjusted from 128Mb to 2Gb
An instance can handle up to 80 concurrent request. Thereby, for a given instance, you are only charged when at least one request is being processed by the instance.
Network egress is based on Network Premium Tier pricing after 1Gb of free tier.
Finally, requests are billed at $0.40 each million of requests after 2 million requests of free quota
The network cost is slightly different with 5Gb of egress free tier for Cloud Functions and only 1 for Cloud Run -> about $0.50 of difference. But the egress Gb price isn’t the same, and more complex on Cloud Run, based on Network Premium Tier. In Europe and North America, it’s quickly cheaper with Cloud Run and comparable for Asia.
Cloud Functions allow to adjust the vCPU speed accordingly with the memory used. But can handle only 1 request per instance.
Cloud Run always use 1 vCPU; you can only adjust the memory. But Cloud Run can process concurrent requests on the same instance.
Finally the cost of the number of requests is strictly the same.
By the way, we can consider 2 main cases of comparison: With only 1 concurrent request, and with several concurrent requests.
I built a GSheet for playing with memory, concurrency and process requirement values.
One concurrent request case
In this case, only the processing of 1 request is compared. In this case, Cloud Run and Cloud Functions have exactly 1 instance up for processing this unique request, and thus only this instance is charged.
This case can happen if you set the currency to 1 in Cloud Run, or if you have sparse and sequential requests to your service.
Thereby, in the same condition, with 1 vCPU (2.4Ghz) and 2Gb of memory, the pricing and the performance are strictly the same between Cloud Run and Cloud Functions.
Several concurrent requests case
Most of time, a service handles several requests in the same time. Cloud Run has the capability to handle up to 80 concurrent requests with the same instance.
At the opposite, Cloud Functions create as many instances as the concurrent requests.
Thereby, more you can process request concurrently with Cloud Run, cheaper is the service
What to consider?
The best choice depends on what you want to optimize, your use-cases and your specific needs.
If your objective is the lowest latency, choose Cloud Run.
Indeed, Cloud Run use always 1 vCPU (at least 2.4Ghz) and you can choose the memory size from 128Mb to 2Gb.
With Cloud Functions, if you want the best processing performance (2.4Ghz of CPU), you have to pay 2Gb of memory. If your memory footprint is low, a Cloud Functions with 2Gb of memory is overkill and cost expensive for nothing.
Cutting cost is not always the best strategy for customer satisfaction, but business reality may require it. Anyway, it highly depends of your use-case
Both Cloud Run and Cloud Function round up to the nearest 100ms. As you could play with the GSheet, the Cloud Functions are cheaper when the processing time of 1 request is below the first 100ms. Indeed, you can slow the Cloud Functions vCPU, with has for consequence to increase the duration of the processing but while staying under 100ms if you tune it well. Thus less Ghz/s are used and thereby you pay less.
For example, with a low processing requirement (20Mhz required) that required only 128Mb of memory, you have:
- Cloud Functions: 100ms of processing for a cost of $0.23e-6
- Cloud Run: 8ms of processing for a cost of $2.4e-6
Sure, Cloud Functions is 10 times cheaper, but your customers wait 10 times more. And this pricing comparison is true ONLY if you have sequential requests.
In this example, with more than 10 concurrent requests, Cloud Run is cheaper! Indeed, Cloud Run handles up to 80 concurrent requests on the same instance before creating (and billing) a new one.
At opposite, Cloud Functions handles concurrent requests on different instances, and thus, you have to pay each running instance in addition of the cold start overcost for each instance created.
There is an other case where Cloud Functions are cheaper and where it’s a good idea to slow the vCPU: When an app calls APIs and waits the responses. Having a function with 200Mhz is enough and a full vCPU of Cloud Run is overkill (for no or few processing) and thereby expensive.
In the Limitation and Quota page of each product, the number of parallel instances is limited to 1000.
However, with Cloud functions, it’s possible to set a custom upper bound to limit the number of parallel instances. Initially released for limiting resource usage (for example, database connection), it’s also a great functionality to limit expenses and to set the upper bound of your service cost. But always with a negative impact on user satisfaction in case of saturation.
Cloud run don’t yet offer this kind of customizable limitation
At the opposite, Cloud Run containers can be only called by HTTP requests. However, it’s possible to use PubSub push subscription for pushing PubSub events to be processed by Cloud Run. In addition, it’s also possible to publish Storage event to PubSub topic and thus, to process Storage events with Cloud Run again through a PubSub push subscription. But, no more.
Thereby, except for PubSub and Storage events, Cloud Functions are unavoidable for all others types of events. No choice possible.
VPC connection requirement
Your serverless app can require some private resources only available in your VPC. For example, a memory store for low latency key-value storage, or a VPN/direct connect access for reaching external resources (OnPremise or on other cloud).
Cloud Functions allow to set up a VPC connector for connecting your serverless functions to your VPC, and thus to route the traffic as required.
Until now, it’s not possible with managed Cloud Run but it’s could change by the end of 2019.
What to choose?
Before my conclusion, I would like to add some additional considerations, not directly linked to the platform pricing, but also in the whole process of development, serving, and monitoring.
Additional thoughts on cost
Public clouds come with a new capability: The real knowledge of cost. In my company, Cloud cost generated fears: Woah, it’s expensive ! No, it isn’t, but it’s known, visible. On premise environment, it’s very hard to know the real cost per service, especially human cost or on mutualized resources (network, storage, hosting,…).
When you choose a technical solution, it’s important to take into account all the pieces of the project, and first of all your human resources. Cloud Functions seem cheaper because your use case fit them well. But, is your team is able to develop functions in the available languages?
In my company, our legacy stack (and expertise) was PHP and C++ and this not fit with Cloud Functions capability. That’s why, containers were our choice, even before Cloud Run product exists.
Do you really know the cost of your team ?
- Risk of resign because people are not well-being with new stack
- Training session cost in addition of no productivity during the training session
- The lack of code quality, reliability, performance and productivity because of the new stack
All these reasons are, most of time, far more expensive than the cloud provider cost.
In addition of this human aspect, what will be the cost of refactoring in case of portability ? What will be the cost of X% more bugs because of difficulties of tests or lack of experience in a new language?
Today, Cloud Run is in beta. On Google Cloud Platform, the betas are really stable and can be used in production. However there is no Google commitment on the service and support can be less efficient.
Cloud Functions are in GA for Python 3, Node 8 and Go 1.11
In mission critical application with restrictive SLA, this can be the first criteria choice, above the cost itself.
Limits and Quotas
There is few differences between the 2 services but they can imply organizational change or technical solution design redesign. This is indirect cost but to take into account if you plan to deploy hundreds of Cloud Functions with a high rollout velocity.
Indeed, Cloud Functions are limited to 1000 functions per project, and to 120 minutes of compilation per days and per project.
In Cloud Run, there is no limit on compilation because it’s performed outside the platform, and there is the same limit of 1000 services per project. BUT a service can serve several endpoints.
Another aspect, is the size of each request/response 3 times higher with Cloud Run than with Cloud Functions. Is your use-case is impacted by this?
Other limits are hard to compare or are not relevant for a large majority of projects.
As you can see, the cost comparison between Cloud Functions and Cloud Run goes further than simply comparing a pricing list. Moreover, on your projects, you often will have to use the 2 solutions for taking advantage of their strengths and capabilities.
My first choice for development is Cloud Run. Its portability, its testability, its openess on the libraries, the langages and the binaries confer it too much advantages for, at least, a similar pricing, and often with a real advantage in cost but also in performance, in particular for concurrent requests. Even if you need the same level of isolation of Cloud functions (1 instance per request), simply set the concurrent param to 1!
However, some reasons, like GA support, VPC capabilty or eventing, can force you to choose Cloud Functions, but, most of time, it won’t be for a pricing reason.
Finally, the variety of use-cases, differences in organization and the complexity of human resources (skills, wishes, motivations) generate too many combinaisons and I can only provide tips, and things not to forget in your decision process. It’s not possible to provide a unique answer.
In any case, be sure to choose the right partner, with an external point of view, to help you in this journey, talk with your teams and try by yourself for finding the best answer to your use cases!