Going Serverless drives me crazy or choosing between AWS Lambda and Azure Functions

When public clouds mature, the gap between their services fades and for many of us it’s a puzzle to choose the right cloud provider.
20.11.2018
Timur Bublik
Tags

When public clouds mature, the gap between their services fades and for many of us it’s a puzzle to choose the right cloud provider. And as serverless plays an essential role in modern cloud infrastructure, in this blogpost I will compare the serverless offerings of the two biggest (by market share, according to the 2017 Cloud Security Alliance report) public cloud providers out there, AWS and Azure, in order for you to find the right one more easily.

Pricing

AWS Lambda charges per request and per runtime duration. The first million requests and 400 000 GB seconds are covered by AWS Free Tier, after that it is $0,20 per one million requests and $0,00001667 per GB-second.

At the same time Azure Functions can be run in two different modes with two different pricing models. The first mode is the Consumption Plan, where you pay per request and per runtime duration, just like Lambda. The price is $0,000016 per GB-second and $0,20 per million requests. You should know, however, that the Consumption plan is not available in all Azure regions, e.g. not in Germany Northeast.

The second mode is the App Service Plan, where you reserve a certain managed instance and pay hourly. This one is not cost effective unless you are already planning to use Azure App Service, which is a managed service for hosting web apps, APIs, and mobile backends; in that case you would simply collocate your Functions with other apps. It also gives you a choice between Windows and Linux environments. The price is $0,115 per hour for a 1 CPU, 1 GB RAM and 50 GB storage instance (may differ per region). There are other more expensive and powerful choices available (the cheaper ones are not considered, as they have no autoscaling and not all of the cheaper ones are supported by Azure Functions).

Just to give you food for thought: you could replace App Service Plan via open-source functions like Oracle Fn, Kubeless, Apache OpenWhisk or OpenFaas (or even Azure Functions, they are open-source too!) and run them in AWS ECS/EKS on AWS Fargate. If you find it interesting, ping me and I will write my next blogpost about it.

Deployment

If you already have a battle-tested CI/CD system, you would probably like to tie the serverless’ deployment up into it as seamlessly as possible. AWS Lambda allows deploying source code via ZIP packages only. There are a number of third-party tools (like Apex or ZAPPA), as well as AWS’s own CodeDeploy, but they all do more or less the same under the hood: package to ZIP and deploy. Most probably in your CI/CD system you would have to define a script to run CLI commands after tests (you have them, right?) were successfully passed. Figure 1.1 depicts a delivery pipeline of code stored in AWS CodeCommit to AWS Lambda.

Screen Shot 2018-11-19 at 16.39.21
Figure 1.1. Example of AWS Lambda deployment workflow.

At the same time Azure Functions give you more choices: you can deploy not only from ZIP packages, but also via version control systems, e.g. from GitHub, BitBucket or an external repository of your choice. If you have that, you could, e.g. run tests via GitHub web-hooks on pull requests, and the code would be deployed after merge. You can also deploy from a function-specific repository created by Azure automatically if you do not have any CI/CD in place yet. You should know that external version control systems are not available in certain regions, like Germany Northeast. On figure 1.2 you can observe an example of Azure Functions code deployment pipeline via integration with GitHub.

Screen Shot 2018-11-19 at 16.40.09
Figure 1.2. Azure Functions CI pipeline.

Timeout

AWS Lambda has a built-in timeout of 15 minutes. It is possible to get around it, but the ways I know are hacky. Azure Functions on Consumption Plan allow you to run up to 5 minutes by default, but it can be increased in configuration to 10 minutes. This is not always the best solution, because running a function for 10 minutes and requesting it thousands of times per day may cost much too much; in that case you might start considering the App Service Plan. The App Service Plan due to its nature can run as long as the host under it.

Events and state management

Both services are event-driven (also time-driven, when needed) and have tight integration with other cloud-specific proprietary technologies, like NoSQL databases and object storages; nothing really special. What is interesting is HTTP event handling: Azure Functions have a HTTP trigger built-in, whereas AWS Lambda requires AWS API Gateway in order to receive HTTP events and that is what actually matters. Figure 1.3 shows a simple architecture enabling AWS Lambda to receive and answer HTTPS requests.

AWS API Gateway is not easy to bootstrap and manage, and it actually costs money ($3,7 per million requests received plus extra for caching when needed). API Gateway also has an integration timeout, which limits waiting for the response to the range of 50 milliseconds and 29 seconds. So although your Lambda function has 15 minutes to finish the task, API Gateway will only wait up to 29 seconds, therefore limiting your AWS Lambda runtime to 29 seconds as well.

The Azure Functions HTTP trigger waits up to 2,5 minutes, which gives you more space for manoeuvres. Figure 1.4 displays the architecture of Azure Functions for handling HTTP requests via built-in HTTP trigger.

Screen Shot 2018-11-19 at 17.05.21
Figure 1.3. AWS Lambda architecture for HTTPS requests handling.

Screen Shot 2018-11-19 at 17.05.41
Figure 1.4. Azure Functions architecture for HTTPS requests handling.

State management is needed when you have different applications that should work in a chain following certain logic. AWS Lambda can do so e.g. via additional AWS Step Functions service, whereas Azure Functions can do that internally in each Function App or even via Azure Logic Apps if you need communication with other backends.

Language choice

There are no serverless services, that supports all available programming languages, so you should choose wisely. If there are no experts around with knowledge of supported languages you might have a problem. Below I placed a table (table 1.1) with available languages (as of October 2018) for Azure and AWS. Note, that languages in experimental mode are not suitable for production. Support cases related to them are likely to be unanswered and the performance may suffer greatly.

Azure FunctionsAWS Lambda
JavaScriptNode.js
Python (Experimental)Python
Java (Experimental)Java
F#Go
C#C#
PowerShell (Experimental)PowerShell
Bash (Experimental)
Batch (Experimental)
PHP (Experimental)
TypeScript (Experimental)

Table 1.1. Programming languages supported by AWS Lambda and Azure Functions.

You might also find yourself in a situation in which you already have an application or a service that you want to migrate to serverless with minimum efforts, but the language it is written with is not supported in the cloud you have/want to have. In that case you can create a workaround by compiling and packaging the language you need and then wrap it with Node.js. You are not going to have native performance though.

Summary

As you can see Azure Functions offer more flexibility thanks to features like the built-in HTTP trigger, built-in CD and different pricing models. At the same time, in certain Azure regions you sacrifice almost half of them and the most critical in my opinion is Consumption Plan.

Azure Functions support mostly Windows-related languages, which is not really convenient for those coming from the Unix world full of Python and Go programming and vice versa. But they can be deployed or migrated in any cloud since the service is open-sourced.

In summary, these two systems obviously cannot provide perfect service. If I were you, I would only consider the case-specific critical points and rely on them.