This article was originally published at blogs.siliconorchid.com on 30-May-2019
This is part three of a three-part series that shows you how to use Azure to distribute your application globally and ensure that users get the best experience.
In part 1 of this series, we talk about how to scale an application and look at a demonstration application.
In part 2 of this series, we look at using Azure CDN to distribute static content.
In part 3 of this series, we look at using Azure Front Door to globally distribute an application back end hosted in dual Azure Regions.
Azure Front Door is a newly-available "Network Entrypoint" service from Azure, which became generally available in April 2019. You should not interpret "newly-available" as meaning that this is a completely new service because it isn't. This is a tried and tested technology that Microsoft has been using with their own services (e.g. Office365 and Xbox Live) for about 5 years.
Front Door is pretty awesome and offers tonnes of features that can improve most applications by offering a layer of caching, acceleration, global distribution, and failover.
An interesting feature to be aware of is that you don't necessarily have to have a backend powered by Azure to use and benefit from the service. By simply overlaying Front Door, over your existing service, wherever they happen to be hosted (they don't have to be in Azure), you could potentially see some performance improvements for users.
In this demo we separated static content to use Azure CDN, so as to demonstrate the use of the CDN in isolation.
If you are choosing to use Azure Front Door, you don't separately need to use the CDN because Front Door provides global distribution for static content also.
To begin to explain what Azure Front Door is, we need to have a little background understanding of the infrastructure that underpins Azure.
Microsoft owns and operates its own global network, which is used to connect its various data centre locations together.
This network utilises high capacity dedicated connections, which are not considered to be part of the public internet. This means any traffic that is within the Azure network will benefit from increased performance. As a paying Azure client, network interactions that you make within the service will be using this high-performance dedicated network.
For example, imagine you had a web API application hosted in the East US Region, that connected to a SQL database hosted in the West US Region. The traffic between your two servers (i.e. queries and data results) would traverse the private Microsoft network. However, onward traffic between your users and the web API server (e.g. JSON) would use public networks.
This global network represents not only the large Azure Region data centres (reported by Microsoft to be 54 in number, at time of writing) but also a huge number of satellite locations which form part of their wider network.
Microsoft is a little coy about detailing exactly the makeup of their network (no doubt because of competitive and national secrecy reasons), but according to this document which markets their network to enterprise users, at time of writing, there are:-
"Edge Nodes", in particular, are of interest to us because an "Edge Node" is a way to create additional well-connected Points-Of-Presence for the Azure network.
In other words, from your own location (at home, in the office, etc), rather than having to make a network connection across the public internet to a major Azure Region, you can instead make the shorter connection across the public network to nearby "Edge Node". From that point, you maintain your contact with that node, which in turn makes requests to your underpinning application, across Microsoft's high-performance dedicated connection.
An analogy that may help you visualise this, is to imagine that you live in a rural village and that you need to travel to a major city to collect a parcel.
Normally, you would use the public road network to drive there by car. This would typically comprise of a journey on local roads and major highways, that are probably congested and across multiple, different junctions.
Imagine instead, that you just needed to drive to a local town where you would meet a courier. This courier would in turn use a private autobahn, with little congestion and potentially higher speed limits, that connects directly from the town to the city. The courier could quickly zip back and forth to the city to get your parcel for you, taking much less time.
The following graphic, duplicated from here, gives fascinating insight not only into the location of Regions and Nodes, but also an approximation of the physical routes that comprise the infrastructure links:
Azure Front Door is a premium service which gives your application access to this network of Edge Nodes.
Without making any modifications to your existing application, just by adding Front Door as a service layer, you can potentially improve network access performance for your users.
Instead of having to traverse the public internet to connect directly to your application, hosted in an Azure Region, your users can now take advantage of the Microsoft network, as previously described.
The service offers several features including geographic load-balancing. This is the feature that we'll demonstrate in this article, as we'll dynamically connect our users to a geographically closer service.
For other features, check out the Microsoft Front Door: Product summary page. It's worth noting that the overhead of SSL encryption can be offloaded from your application server and onto the Edge Node. Also worth noting is that Front Door provides firewall and DDOS protection.
To demonstrate a global infrastructure, we're going to need to create App Service Plans in at least two separate Azure Regions.
For the purpose of our demo, we're going to provision one in UK South (London) and the other in West US (California). We'll use the following settings and resourcename(s). When you come to do your own version, you'll need to use your own unique names:
App Name(s) :
Resource Group Name :
- Hosting Plan : "Consumption Plan"
- Location : "UK South" and "West US"
We also need to create a pair of corresponding Application Insight Resources. These will become important to have available later in the demo, as they will show us how the services are being utilised.
Earlier, we discussed that our Azure Function requires a small piece of configuration to be included, which will be used to display the name of the Azure Region in effect.
Go ahead and add the following configuration into both of your Functions. You should provide a value which is appropriate for the Azure Region you are using.
- Configuration Key :
CurrentHostingLocation. Value :
- Configuration Key :
If you are unfamilar with Azure Function configuration, please refer to my earlier article where I demonstrate how to create configuration settings.
Both sets of Azure Functions also need to have a CORS entry, set up independently on each resource, in order for our web client to be able to successfully access these API resources.
In this example, we will need to add a CORS entry for the website
If you don't know how to update the CORS entry in Azure Functions, I have detailed the steps in a previous article.
This article is not intended to be a tutorial of how to publish Azure Functions to the cloud. If you don't already know how to do this, please refer to my previous article where we walk through one way to publish, directly from Visual Studio.
From Visual Studio 2019, we'll now publish our Function application directly to Azure. We need to do this twice - to both Azure Regions. This means that you'll end up creating two Deployment Profiles.
With the Functions deployed, the easiest way to test that they are working correctly and returning the expected result, is simply to use our web browser to check for a response. For me, the URL(s) to test are:-
If everything is working correctly, you'll see the following message displayed in your browser:-
Hello, there are 41539 prime numbers in the range 0 - 500000. This result was calculated in London
Note: By the time I publish this article, I will have disabled my Azure Function App Service, as I don't want to run up an unnecessary bill - so please don't expect the above links to be live and working - they are purely to provide a realistic and consistent context to talk about.
Now we're finally getting to the exciting part.
- In the Azure Portal, Create a resource and search for "Front Door". Select Microsoft Front Door from the list and click Create
- Select your existing Resource Group - for me, this is "GlobalScalingDemo"
- Select the option Next : Configuration (don't choose "Review + Create" just yet)
- In the panel "Front End Host", click the + symbol in the top-right corner.
- A blade will slide out from the right, prompting you to enter a Host Name.
- I entered
GlobalScalingDemoFrontendHost, but you will need to provide your own unique name.
- I left the "Session Affinity" option in its default "off" setting, as this isn't relevant to this demo (session affinity is a way to "glue" users to a particular service on subsequent visits, which could be relevant if your application has user persistence of some description).
- Click Add to create the front end host
- In the second panel, "Backend Pools", click the + symbol in the top-right corner.
- Another blade will slide out from the right, prompting you to enter a "Name".
- I entered
GlobalScalingDemoBackendPool, but you will need to provide your own unique name.
- You now need to register backend services. For us, this will be the pair of Function App Services that we created earlier.
- Click the "Add Backend" option.
- When prompted for "Backend Host Type", choose "App Service"
- Under the option for "Backend Host Name" choose one of our Function Apps
- Repeat the process of "Adding Backend" a second time for our other App Service.
- Under the option "HEALTH PROBES", leave the setting "interval" at its default "30sec". We'll return to talk about this subject in a moment.
- Leave the "Load Balancing" options at their default setting.
- In the third panel, "Routing Rules", click the + symbol in the top-right corner.
- Another blade will slide out from the right, prompting you to enter a "Name".
- I entered
GlobalScalingDemoRouting, but you will need to provide your own unique name.
- Leave all other option at their default setting.
- Finally, click Create button to validate, review and create the new resource.
Before we move on to testing the new solution, let's talk about the topic of "Health Probes" (one of the settings we just looked at).
Azure Front Door polls your resources to ensure that they are still in a healthy condition.
Should a backend resource become unresponsive, then the Front Door service can detect this and "fail over", meaning that users will be directed to an alternative, healthy, resource, albeit, with increased latency.
Something to consider about this constant health-checking is that your underlying Azure Function will be triggered each time a check is made.
For a production system, this is not an undesirable thing, as failures can be rapidly detected and responded to swiftly.
If you are just experimenting with the technology, be conscious that this will generate a low-level amount of activity. In the case of Azure Functions, the current pricing model provides you with a surprisingly generous free quota of usage, so it shouldn't cost you anything extra.
[Article Update 12 June 2019] : I was speaking with my friend MVP Shahid Iqbal last night at a community meetup. He raised an interesting point about the traffic generated by AFD's health-check probe.
- When I originally wrote this article, I did consider that this may be an issue, but then dismissed it on the basis that calling something like an Azure Function API, even a few thousand times a day, would be an inexpensive operation.
- What Shahid has highlighted, to make me reconsider this opinion, is that if you call other types of default resource (specifically, a default webpage), this can actually consume a meaningfully large amount of bandwidth (that you will be charged for).
- Researching this topic does not currently bring up much information, but I did find this stack-overflow article.
- Therefore, I would recommend creating a simple REST API that does nothing more than return an HTTP-200 OK response. This can be used as a lightweight dedicated-responder to the health-check probe. You will need to explicitly register the URL to this API in the "path" field of the "backend pool, health probe" configuration in Azure.
Normally, if an Azure function is not used for a while, the platform unloads the service from memory and the function goes dormant. This is called "going cold". The impact of this is that the next person to request the resource will experience a "cold start" meaning they could face a slight delay, whilst the function is started back up.
According to this recent article by Mikhail Shilkov, benchmarks indicate that a typical cold-state for a C# Azure Function 2.0, is ~3 seconds.
A useful side-effect of using Front Door is that because your App Service is constantly being polled, it will never go cold, meaning that it will always be in a state ready to immediately serve the next user.
Before we move further, let's just take an inventory to make sure that we really have set up all the Azure Resources that this demonstration requires.
In the Azure Portal, navigate to the homepage and select your Resource Group. For me, this is called
GlobalScalingDemo. Click on that Resource Group to view a list of resources contained within.
Having followed all the steps in the article, we should have a total of 12 separate resources. Please refer to the following screenshot as a reference. As a reminder, the resource names and regions that I have used are intended for this demo and, in many cases, you will have had to use your own unique names:-
With the Azure Front Door resource created and configured, the easiest way to check that it is working correctly is to use your browser to request a result directly from the "Frontend Host Name", the service API endpoint. For me, I used this URL:
A successful result should respond with a message that indicates it was generated in the Azure Region nearest to you. For me, using a native internet connection, I would expect London.
....\GlobalScalingDemo\src\GlobalScalingDemo.Web\wwwroot\js\client.jsyou need to update the variable
const serviceEndpoint = 'https://globalscalingdemofrontendhost.azurefd.net/api/';
There are a couple of ways we could check that the service is routing to an appropriate Azure Region (for example, a low-tech way might be to ask a friend in another country to check for you).
A more scientific way is to alter your Internet Point-of-Presence (POP). There are a few ways you might do this:-
- Use a VPN (if you work for an international company - or - use a VPN service).
- Remotely connect to a distant machine you have access to - e.g. temporarily provision an Azure VM - and operate this using a Remote Desktop Connection.
For the purpose of testing, I used a private VPN service to change my POP. You can watch my test in the following animation, but briefly, the steps I made were:-
- Use VPN to connect to a POP in Frankfurt, Germany
- Navigate to the CDN-hosted client app in the browser.
- Wait for the application to return a result from the backend.
- Verify that the result identifies as having originated from London (which is the nearest service to Germany).
- Disconnect VPN and reconnect to a different POP, in Denver, USA
- Refresh the browser window; the client app will make a fresh request to the backend.
- Verify that the result identifies as having originated in California.
Firstly, let's make sure we understand how to see what's actually going on in Azure.
- Decide which of the two App Service resources we are going to inspect. Initially, you should choose the Region which you know is geographically closest to you. For me, this is my "London" version.
- From the Azure Portal, locate and open the Application Insight resource that corresponds with this App service. For me, this is called "GlobalScalingDemoFuncAppLondonAppInsight"
- With the Application Insight blade open, locate the option "Live Metrics Stream" and select it.
- In the panel that appears, scroll down towards the bottom so that it displays the section "Servers"
This report is really interesting to watch, as it shows the incoming requests placing a load on the service. It also shows the number of actual Azure Function host instances that have been [automatically] provisioned for you. If a service is worked hard, we can expect to see extra instances appear.
A low-tech way to test your service could be to refresh your browser window really quickly, so as to trigger a number of HTTP calls. However, you'll probably break your mouse button before making much of an impact on Azure.
Instead, we're going to use automation tools to create an artificial workload. There are a couple of ways that we could do this.
One of my favourite tools, Postman, has a feature which allows you to trigger a queue of API requests. You can read about the amusingly named "Postman Collection Runs" in this article : Postman Learning Centre : Intro to collection runs
Download and install Artillery. Installation is as simple as running the following command ( but you can follow the official instructions on the website: Getting Started With Artillery):-
npm install -g artillery
Next we want to create a load on our server. The following command will connect to our Front Door global endpoint and create 20 virtual users, each of which call the API 50 times. The process is set to run over a period of 30 seconds.
artillery quick --count 20 -n 50 --duration 30 https://globalscalingdemofrontendhost.azurefd.net/api/CalculatePrimeNumber/
When you have started the test, you should watch Application Insights to see how your service reacts. You should see results similar to the following animation:-
- Microsoft Documentation : Static Content Hosting pattern
- INFOQ : Microsoft Introduces Azure Front Door, a Scalable Service for Protecting Web Applications
- Azure global network
- Azure Friday : AFD Preview
- How Microsoft builds its fast and reliable global network
No third party (i.e. Microsoft) compensate me for my promotion of their services. I have no bias to recommend their services.
Thanks to Layla Porter for being my document reviewer. I don't have a team to back me up and sometimes you need another set of eyes!
Thanks to Shahid Iqbal for highlighting a potential issue related to the health-check polling mechanism.