To be serverless or not…. an honest and opinionated comparison of Azure Functions and AWS Lambda functions for the modern software developer — Part 1–Oct. 2023 — Evolution and Vendor Support
In this day and age, where we all are hit daily with buzzwords, products, advertisement and why not say it: “opinions” about almost everything I just thought I could share my own point of view and experiences with Azure Functions and AWS Lambdas. Most of the information you can find on this article are things you can read on the internet or other blogs, but some are real-world situations that you might find useful to know about or perhaps even entertaining.
So here I go….
Part 1: Evolution and Vendor Support
I started developing Azure Functions around 2017 in C# with Net Framework (I know I know this is like archeology in 2023), but at the time this was the only option from MS and Net Core although wildly available at the time, was very new for Azure Functions. Over time we migrated all of these to Net Core, ending up at Net 6 in 2023. And, this is what I consider was the weakest point about Azure functions from MS.
Also, Azure Functions in Net Framework (aka v1) did not have the full-fledged integration with App Insights, so we could only see “requests” into the apps, but not “dependencies” going out, so observability became a deficit from day #1.
Some context: The reason why we started using Azure Functions around 2017 was that for our customer, Virtual Machines or AppServices were too expensive, so one day, an almighty Architect woke up from its bed and yelled “eureka” we are going to transform all our AppServices into Azure Functions (because these are free). *P.1.1=Try to remember this statement, I will get back to this later.
Eventually we migrated these from v1 to v2, from v2 to v3 and finally to v4 in Net 6. Why? simply because MS said every 1 or 2 years that the older frameworks were becoming obsolete and wouldn’t have any support anymore. But was the migration effortless? Not at all, some were complete re-writes and were very expensive *P.1.1 from a project’s budget point of view of course.
In terms of performance, security or functionality, I don’t recall seeing any major improvements in these Azure Functions, there might have been some (full support for requests and dependencies in app insights was a given), but we never needed any particular improvements. We just had to keep pace with the new releases because MS said so or we would be running unsupported code in production (As I write this I am already planning on writing a special article on the Net 6 migration Azure functions which was a special case in its own right).
Side note: So if you read between the lines here, we became slaves to MS’ release schedule for new Azure Function frameworks, all in hope of getting rid of appservices to reduce costs *P.1.1 (the irony is implied).
Now how can I compare this experience of an “evolution-path” with AWS Lambdas? I recently started with Lambdas in .Net, Java and to a minor degree in Node Js, but I can’t say I have 7 years of experience with Lambdas. But browsing the internet and using some common sense, I haven’t seen any articles “demanding” companies to migrate from AWS v.x to v.x+1, simply because such a thing doesn’t exist in AWS. But AWS keeps a “deprecation policy” about the language frameworks / runtimes for Lambdas, namely here: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
Read the above page, and you will see the following sentence “Phase 2 — you can no longer create or update functions that use the runtime.” . In my understanding this means: you would end up with code in production that can no longer be modified until you upgrade the framework/runtime (*Oct 2024 update). So IMHO, when comparing to MS’ policy, I prefer MS’ one. At least with Azure Functions you can keep on developing your unsupported code much much longer, at your own risk of course.
*Oct 2024 update = I just had the opportunity of creating a Cloudwatch dashboard custom widget with a Lambda and it got created as a node js 16 lambda which is totally unsupported in 2024. However, I did my own Cloudformation script creating that widget as a Node Js 16 app and it worked. Meaning, AWS won’t let you manually create lambdas for deprecated frameworks, but still create them with automation tools.
A difference with AWS though, is that you can create your own custom “runtime”, which according to my understanding of the deprecation policy, it wouldn’t be ever get into the “phase 2”, since that’s your own thing to support (a self managed Lambda so to say).
Another major fact about the evolution paths of these 2 technologies, is that MS started Azure Functions as “Consumption Plan”, then Premium and then probably Dedicated (I don’t have a recolection of what came out first exactly), whereas in AWS I don’t even see such a taxonomy existing today.
The 3 flavours of Azure Functions are a migration path for development teams to embrace, because:
- Azure Functions in consumption plan are free up to a million requests, but after that they can become expensive. They can have very slow startup times (cold-starts) and are limited on connectivity and scalability configurations.
- Premium are not free and guarantee startup times of new instances or provide warm instances. Scalability options are more manageable.
- Dedicated are basically AppServices with fixed costs and all scalability options available on AppServices. Now, this is a catch. Is an Appservice serverless? Most likely not, you are too much involved in defining a plan, scale out policies, etc. But this is a subject for another blog.
AWS Lambdas, don’t provide these 3 types because:
- You are always charged for the time you use them
- If you want to provide better performance or availability you can increase memory, CPU arquitecture, storage, or warm instances with concurrency options.
In this sense AWS Lambdas are better suited to handle extreme load, however you must make sure that your account is configured to scale out Lambdas to the level you are expecting to support.
One big difference on the subject of Vendor Support, is that although both have very clear SLAs, there is no mention in Azure Functions’ credits for issues while running them during the free period. In other words, if you are not charged for a service, you can’t complain about failures. Now another grey area, is how to prove a failure, which is a chapter on its own.
About tech support calls, in my recent experience with AWS, I can only say their level of support has been great so far, but I must admit my employer paid an extra for developer support. As for MS’ support, even being on a premium support tier, I found their service level barely acceptable. Over the years with MS we had many failures related to patches applied to AppServices (not Azure Functions per se), connectivity issues *P.1.2 and the response was, although completely valid, in most cases “upgrade to the latest SDK” or latest Azure Function version.
*P.1.2=Another topic I will reference in the future.
Extreme cases I have seen in Azure with all services are those when Azure “injects” errors between HTTP communications, your applications log them because a developer said “let’s log the http status of a failure” but never thought of logging the response text (there was no requirement in a user-story to do so :-)). So a 400 http status coming back from a service (being an Azure Function or not) could have been generated by the Application itself or by Azure. I have seen development teams spending days or weeks trying to reproduce such a case, until somebody said let’s log the response, which when finally found again said “Azure Network error, Azure Server Error”, etc. These are the cases that are almost impossible to get support for by the vendor (another case of *P.1.2 syndrome)
That, I haven’t heard of with AWS yet — touch wood.
Managed “patches”: this is an interesting topic that I haven’t heard or read being discussed much. All cloud providers have the buzzword “managed service”, which simply means: the provider is going to take care of the basic maintenance needed to have your services running with the latest and most secure code (patches) and with a proper configuration and monitoring to guarantee a very high degree of availability (and luckily keep you informed of deprecations and guide you on migration paths :-).
Now one interesting difference with AWS Lambdas and Azure Functions, is that both run on Operating Systems that need to be patched now and then. And here comes the difference: AWS Lambdas do only run as one instance for the time they are running a function, in other words “one request maps to one new server instance” every time. Of course an already running instance, can be re-used and called upon many times, until it finally unloads (a docker container in the end). So, all this this means, you cannot have an AWS Lambda image serving multiple requests at the same time.
With Azure Functions this is exactly the opposite. Azure functions serve as many requests as they can on each instance and once the instance becomes overloaded (and performance deteriorates), new traffic is not rejected but not connected to the overloaded instance, a new intance is then created and the paused traffic is then redirected to the new instance.
There is nothing wrong with both approaches, actually MS’ one makes perfect sense if they are offering you a free service (Consumption Plan), and since AWS always charges for the time consumed, makes also sense to provide some predictable throughput, which MS lacks when sharing an instance.
But about patches? MS has some articles explaining that APP Services should ideally be grouped as odd numbers of instances, e.g. 3 servers running in parallel (optionally more dynamically to scale out) because patches are applied on pairs of servers, this means a set of 2 servers are usually shutdown and patches applied, so if you have 3, you will always have at least one responding. So the same rule applies to Azure Functions in Dedicated mode. Now for Consumption plan or Premium, this is a big question mark. For example if we had 10 users being served on one instance of a Consumption or Premium instance and MS suddenly patches a server and reboots it, we would get 10 failed requests. This is not uncommon to see with any of the Azure Function types, but then again try to prove this happened to you and good luck trying to get some support for this, basically because you will not be told when a server was patched (this is all serverless, there are no servers, right? :- pun intended).
Now with AWS Lambdas, patches are also applied. I haven’t heard yet of anyone complaining of a server being shutdown in the middle of an operation, nor any rule about keeping uneven/odd numbers of servers running on a given concurrency setup, however by applying just some common sense, if every request is one server instance, then the chances of harming production operations by a server suddently restarting due to a patch or whatever reason is much lower than with Azure Functions.
Ok I think this is it for Part 1, I hope you found this article interesting,
thank you for reading.
Boris J.
New: Part 2 is available here.
References and other good stories:
- https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html?icmpid=docs_lambda_console
- https://iamondemand.com/blog/aws-lambda-vs-azure-functions-ten-major-differences/#:~:text=AWS%20Lambda%20charges%20for%20full,may%20lead%20to%20noticeable%20reductions
Legal Disclaimer: The views and opinions expressed here are those of the author only and do not necessarily reflect the views or positions of any other entity that the author has or has had any relation with.