Many undocumented subtleties figure prominently when designing and scaling the Azure architecture of a new Azure Web App, whether starting from scratch or porting an existing .NET app to the Azure Cloud. It’s always best to determine system compatibilities and custom needs prior to deployment. While Microsoft’s Azure documentation is generally good, navigating the often undocumented details can prevent pitfalls and optimize the scalability of your Azure Cloud-based solution.
Scaling Up: growing the size of an existing resource
Azure resources are generally simple but relatively expensive to grow in size or scale up:
- Click the resource (DB, Web App Service Plan, VM, etc.)
- Choose a more powerful (and typically more expensive) Service Tier
- Scaling up an Azure Web App tends to provide linear benefits: i.e., the next tier up often doubles performance
E.g., 100% page load speed increase
- Scaling up an Azure SQL DB tends to provide geometric benefits: a few extra DTUs may provide a large increase in available resources
E.g., 25 more Azure SQL DTUs may mean 20% of the effective RAM/CPU resource requirements
- Scaling up an Azure VM is harder to predict: certain applications may even perform better at a less-expensive tier
E.g.: one specific performance analysis found F1S tier VMs ran a Windows Service faster than the newer, more expensive DS1_V2 tier VM
Since scaling up is relatively cheap in terms of effort, one can experiment with various combinations of tiers for different resource to find the sweet-spot for a given application.
Just remember to turn down the heat (dial-down from the most expensive tiers) if you intend to leave a test project on the burner for weeks or months!
Scaling Out: multiplying and pooling the number of allocated resources
Azure resources are generally much more difficult to scale out, depending on what type of resources they are. However, Cloud Computing shines in a cost-benefit analysis when nearly unlimited resources are available at a moment’s notice but resources must only be paid for if and when they are needed; the trick is the Cloud’s ability to scale quickly enough to respond to peak loads.
Here are three commonly-scaled resource types ordered in ascending scale-out difficulty:
- Azure Web Apps
- Azure SQL Databases
- Azure VM Servers
Azure Web Apps
Load Balancers can be configured to delegate incoming requests to a pool of back-end VMs or Web Apps. Out of the box, a single Web App Service plan can host one or more instances of a website.
Separate App Plans can be individually scaled, or a single App Plan’s Deployment Slots can be leveraged to deploy several different sites or different versions of the same site, e.g.:
- small Admin Tool (very few super-users) two slots: admin_prod & QA (testing
- large Main Website (many public users): three slots: production, QA (testing), & development (collaboration)
If premium-tier multiple app instances still can’t handle the load, an Azure Load Balancer can delegate to multiple Web App Service Plans.
Azure SQL Databases
Azure SQL offers the power of SQL Server without the work of installing, configuring and maintaining a server.
Furthermore, thousands of very large databases can be individually scaled, even when running on the same Azure SQL server, which should be thought of more as a security and organizational silo than a container of limited performance or size.
Migrating an existing SQL Server Database to Azure
- SSMS 2014+ provides the built-in Database context-menu Task: “Deploy Database to Microsoft Azure SQL Database…”
- SSMS can batch migrate SQL Server DB’s into the Azure SQL managed-DB environment without any major compatibility issues
- Official MS Azure SQL migration compatibility reference
- Common SQL Server features not supported by Azure SQL include:
- msdb.dbo.sp_send_dbmail (aka Database Mail)
- SQL Server assemblies (.NET DLLs imported into a DB)
- NT_AUTHORITY/SYSTEM Security User-mapping: Integrated Windows OS authentication
- Old SQL Server syntax variations, e.g.: “(NOLOCK)” must be replaced by: “WITH(NOLOCK)”
If your Web App load is highly variable (i.e., you need to handle large spikes in traffic or database load), Azure Elastic DB pools can also be used to dynamically-size Azure SQL services to provide high-performance when you need it but lower costs when you don’t.
- See doc: SQL Database: Elastic Pool Guidance
- Rule of thumb for Elastic Pool adoption is based on a minimum number of databases
If the sum of the DTUs of performance levels for single databases is more than 1.5x the eDTUs needed for the pool, then an elastic pool is more cost effective.
- See eDTU and storage limits for elastic pools/databases.
Azure VM Servers
This blog’s pragmatic focus precludes a survey of the full array of Azure offerings including Cloud Services, Service Fabrics, Containers, Functions and Batches.
Basic Azure Wep Apps can often play host to an existing website after minimal porting effort, including the re-deployment of background Windows Services as worker-level Azure Web Jobs. In many cases, the existing Website project and its Windows Service dependencies can be deployed to Azure by simply right-clicking on the projects in Visual Studio and selecting ‘Publish Web App’ and ‘Publish as Azure WebJob’, respectively.
But let’s face it; sometimes even a cloud-deployed Web App still needs the support of a good, old-fashioned server, whether that means a full, RDP-enabled Windows Server or an auto-scaled VM spun up from a generalized image that we can never directly reconfigure.
Azure VMs running Windows Server OS remain a popular choice for many organizations who may:
- prefer not to expend the effort to port existing (legacy) Windows Services to the Azure Cloud as Web Jobs
- rely on custom features or protocols that are not supported by Azure
For example, Azure Web Apps and Web Jobs do not support:
- Custom Ports: only port 80 is supported
- Non-HTTP Networking: other protocols like UDP (uni-directional) network protocol are not supported by AzureUDP support is required by many remotely-deployed IoT, cellular and GPS devices. While Azure does offer an IoT API, it must be ported to and installed on remote devices, which is not easy and often impractical.
As with Azure Web Apps, if a single premium-tier VMs still can’t handle the load, an Azure Load Balancer can delegate to a pool of VMs in an Azure Availability Group.
VM Creation for Load-balanced Backend Pool
Capture Image from VM:
Once a VM is in the desired state, an image is captured to clone the VM; cloning may need to be repeated if significant changes are made to the VM.
- Download & install the latest version of AzCopy
- Open a Powershell window with Administrator privileges
- Login to Azure by running the command Login-AzureRmAccount
- Stop the VM to be cloned
- Open a Windows Command prompt
- cd “C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy”
- Fill-in the and run the following command:
.\AzCopy /Source:https://<vm_storage_account_source>.blob.core.windows.net/<your_vm_storage_container_source> ` /Dest:https://<vm_storage_account_target>.blob.core.windows.net/<your_vm_storage_container_target> ` /SourceKey:<storage_source_key> ` /DestKey:<storage_dest_key> ` /Pattern:<virtual_hd_name>.vhd
Restart the VM that was stopped
Create (clone) VM from Image:
- !!! The new VM must be created in the Availability Set of the Load Balancer
I.e., Availability Set cannot be set after VM creation
- Upon creation, a VM must be added to the Backend Pool of the Load Balancer
I.e., Membership in an Availability Set does not automatically add a VM to a Load Balancer’s Backend Pool
- See Azure documentation for details of VM creation from a .vhd (stored) Image
My next blog installment will explain how to configure an Azure Load Balancer and will compare Manual VM scaling to Auto-Scaling via Azure Scale Sets.