Azure Function is a Serverless compute offering from Azure that runs on demand, supports billing on demand and can host developer code without having to provision underlying infrastructure. Before getting deep into the topic let us try to understand what a Serverless Compute offering is. To start with, Serverless Computing does not mean that the code does not run without being hosted on a server. Serverless hosting model has a server hosting the code under the hood. However the server and other infrastructure aspects are abstracted from the developers. Developers just need to build the code and upload to the Serverless Compute Offering without worrying about the underlying hosting infrastructure. Sounds similar to Platform as a Service offering right? There are two big differences: the way it is billed and the way it scales out. Serverless Components can be billed on a Consumption basis. They are billed only when the hosted code is invoked and is running. They are not billed when the hosted code is not in use though the compute service is running. The Serverless components scale out automatically and inherently per need basis. There is not an extra bill for auto scaling feature. The below figure explains details of different cloud hosting models.
Whatever we discussed above is all good in theory. In real client scenarios there are lot of design considerations to be taken care of. The Serverless Architecture is not as simple as it is explained. In this article we will discuss different design considerations while using Azure Functions.
Design Considerations based on underlying Infrastructure
Let us start with couple of use cases and then build on these to understand design considerations.
Use Case 1
We need to host a code that does some generic processing and does not need much of compute power. It is okay that the scaling is handled automatically and no control is needed. The code completes in a shorter duration at max 10 minutes.
Use Case 2
We need to host a code and have more control on compute requirement. The code runs for a longer duration -- much more than 10 minutes. Needs VNET connectivity and runs nearly continuously. It is okay that the scaling is handled automatically and no control is needed.
Use Case 3
We need to host a code and have more control on compute requirement like running the code on dedicated VM or Isolated SKU. The code runs for a longer duration much more than 10 minutes. Needs VNET connectivity and runs nearly continuously. Should be able to scale manually.
Let us try to understand the Hosting Plans available for Azure Functions and how they can help address these use cases. While considering a Function Design the first step is to choose the right Hosting Plan. So let us start with this.
Consumption Plan
This is the best suited and ideal plan while designing a Function. This is the plan that actually fits the Serverless definition. Consumption Plan allows code to run for a max of 10 minutes, default being 5 minutes. After that amount of time execution will time out. Scaling is automatic here. Instances are added on the fly to enable scale out functionality for the hosted code. Instances are removed automatically when the load is less. Scaling in Functions is handled by Scale Controller components. Scale controller allocates or removes resources based on the load so as to run multiple instances of Functions. There is no control over compute size being allocated and is handled by platform automatically. User is charged only when the function executes.
This fits the best to the Use Case 1 as the execution time is short and there is no control needed over compute size and scaling. Platform can handle the scaling and compute requirements. No explicit control needed for scaling and compute requirements.
Premium Hosting Plan
Website, irrespective of wherever it is hosted, is a bit slower in serving first time user requests as compared to the subsequent requests. To address this, the website is browsed for the first time before making the website public. This is called warming up the website. Warming a website takes care of essential activities like prepopulating cache or a CDN and other necessary activities that makes the website fast. With Premium Hosting plan website is always warmed up. At least one instance is always warmed and ready to serve. This makes scaling smooth and fast. This plan also supports VNET or VPN configuration. Premium SKUs support control of the compute you need. We can choose a plan to match the compute. By default time out allowed is 30 minutes and can be set to time out at max 60 minutes. This is a best choice when the hosted code runs nearly continuously. You are billed on usage time, memory consumed and also on warmed up instances used. Scaling is handled by platform and we do not have control over it.
For the Use Case 2 this is the best fit. VNET support, control over compute, more timeout duration and nearly continuous execution makes it the best choice here.
App Service Plan
This supports running the hosted code on dedicated VMs. We can choose from App Service SKUs like Basic, Standard, Premium and Isolated SKUs. We get a control over scaling. Auto scaling can be set and manual scaling configuration can also be applied. This comes handy when a complete control over scaling and compute is needed and at the same time we need to use the Function features goodness like smooth integration with other Azure Services and can be invoked with triggers. Also if you have hosted a code on VM and the code does not fully utilize the compute power and other resources of VM then this option can be used. Users are charged exactly same as in App Services.
A word of caution, these functions execute and go on sleep. Underlying Platform does not wake it up by default. Always On settings should be turned on so as to handle waking up the function using Http Triggers.
This is the best fit for Use Case 3.
The design decision is summarized in the figure below.
Design Considerations Based on Application Pattern and Data Persistence
Now let us discuss a few more use cases.
Use Case 4
We have a Fan Out, Fan In situation where data is chunked for further processing and passed on to functions executing in parallel and once all the parallel function completes execution the processed data from each function is passed on to another single function for aggregation activities. The below figure describes this use case.
Use Case 5
We have a Function Chaining scenario where one function executes the second function and the second function calls the third function. Data is passed among the functions. The below figure demonstrates this scenario.
Both these use cases can be handled using Durable Functions. Durable Functions support Function Chaining as well executing the Functions in parallel. Data can be passed between functions. The figure below depicts the key concept of Durable functions.
Durable Functions have three major components,
- Activity Functions
They perform the actual business tasks.
- Orchestrator Functions
They do the actual orchestration. They invoke the Activity Functions. Handle data pass on among them and go to sleep. They wake up once the Activity Function triggered by it completes and it has to invoke the next Activity Function.
- Orchestrator Client
They invoke the Orchestration Function.
In a nutshell Orchestrator Client invokes Orchestrator Function. Orchestrator Function invokes the Activity Function and goes to sleep. Activity Functions perform business logic. Once invoked Activity Functions complete execution Orchestrator Function wakes up to invoke next set of Activity Functions.
Containerized Deployments
Azure supports containerizing the code along with its dependencies using Docker and hosts the Docker in the Function. If there are a lot of dependencies and underlying OS considerations to handle then go for Dockers and host it in Azure Functions.
Other Considerations
Finally once we have thought from Infrastructure perspective and application pattern perspective we need to think of other important aspects listed as below.
Functions using App Services plan can have max 20 instances. Functions using Premium plan can have at max 30 instances. Function using Consumption Plan can have at max 200 instances.
There can be 100 Hosting Plans per Resource Group in case of App Service Plan and Premium plan. There can be 100 Hosting plans per Region for Consumption Plan.
There can be max 100 Function Apps per Premium plan and Consumption Plan. However App Service Plans supports unlimited Function Apps.
Consumption Plan supports max 1.5 GB of memory per instance. Premium Plan supports 3.5 to 14 GB of memory per instance. App Service Plan supports 1.75 to 14 GB of RAM per instance.
Max URL length can be 8192 characters and query string length cannot be more than 4096 characters.
Max Request size can be 100 MB.
Max Outbound connections allowed for Consumption Plan is 600 active and 1200 total. There is no such limit for other plans.
Make sure we secure the Functions by using right Authorization levels.
Winding up
Here in this article we unlocked design considerations for Function Apps. All the considerations are summarized as in the below figure.
Azure Functions appear to be simple but require a lot of thinking while using them. They have to be designed and implemented with all considerations so as to get the best out of Serverless Architecture. Azure Functions are the driving units of Serverless Architecture on Azure Function.