☁️ Azure

Azure VM Deployment, Sizing & Performance

📅 July 21, 20269 min readITVedas

A practical guide to Azure VM series selection, availability sets vs zones, managed disk tiers, and data-driven right-sizing.

INTERMEDIATE
⏱ 9 min read
Prerequisites:
Key Facts
  • Availability sets protect against rack-level failure within one datacenter using fault and update domains; availability zones protect against datacenter-level failure by spanning physically separate facilities
  • Ultra Disk and Premium SSD v2 let you tune IOPS and throughput independently of provisioned capacity, without resizing the disk
  • B-series VMs accrue and spend CPU credits, so sustained high-CPU workloads will exhaust the credit balance and get throttled to baseline performance
  • A VM cannot be a member of both an availability set and an availability zone — the placement model is chosen at creation time and is not mutually convertible

Choosing a VM series

Azure VM sizes are grouped into series that trade off vCPU count, memory ratio, and burst behavior. Picking the right series first narrows the sizing decision to a handful of SKUs instead of the entire catalog.

B-series (burstable) VMs — for example Standard_B2s or Standard_B4ms — run at a lower baseline CPU performance and accrue CPU credits while idle. Those credits are spent when the VM bursts above baseline. This makes B-series a good fit for dev/test boxes, low-traffic web front ends, and small management VMs with spiky but not sustained CPU demand. It is a poor fit for anything with continuous high CPU utilization — once credits are exhausted, performance drops to the baseline vCPU percentage and stays there until credits rebuild, which shows up as a hard, confusing performance ceiling in production.

D-series (general purpose), such as Standard_D4s_v5, targets a balanced vCPU-to-memory ratio (roughly 4 GiB RAM per vCPU on the current Dsv5 generation) and is the default starting point for application servers, mid-size databases, and most stateless services. The v5 suffix denotes the hardware generation and the s denotes Premium Storage support — always prefer the s-enabled variant unless you have a specific reason not to, since it's a prerequisite for Premium SSD and Ultra Disk attachment.

E-series (memory-optimized), such as Standard_E8s_v5, roughly doubles the memory ratio to around 8 GiB per vCPU. Use it for in-memory caches, SQL Server or SAP workloads with large buffer pools, and any process where you're memory-bound before you're CPU-bound. Don't reach for E-series just because "more RAM is safer" — the extra memory is billed whether or not the workload uses it.

F-series (compute-optimized), such as Standard_F8s_v2, inverts the ratio to roughly 2 GiB per vCPU and gives you a higher clock-for-clock CPU allocation per dollar than D-series. It suits batch processing, web servers under heavy request-processing load, gaming servers, and analytics workers where memory is not the constraint.

All four series exist because vCPU and memory don't scale in a fixed ratio for every workload — sizing by "how many cores did the old server have" instead of by the actual CPU:memory:IO profile is the single most common cause of both overspend and under-provisioning.

Deploying VMs with the Azure CLI

A minimal production-leaning deployment specifies the image, size, authentication, and disk SKU explicitly rather than relying on defaults:

az vm create \
  --resource-group rg-app-prod \
  --name vm-app01 \
  --image Ubuntu2404 \
  --size Standard_D4s_v5 \
  --admin-username azureuser \
  --generate-ssh-keys \
  --os-disk-sku Premium_LRS \
  --zone 1 \
  --vnet-name vnet-app-prod \
  --subnet snet-app

Two things worth calling out: --os-disk-sku defaults to whatever the image publisher set, which is often Standard SSD — for production workloads set it explicitly. And --zone pins the VM to a specific availability zone at creation time; it cannot be added retroactively without redeploying.

Resizing an existing VM is a separate operation and isn't always free of disruption:

az vm resize \
  --resource-group rg-app-prod \
  --name vm-app01 \
  --size Standard_D8s_v5

If the target size is available on the same hardware cluster the current VM is running on, the resize can happen without deallocation in some cases. If it isn't — which is common when jumping between series, not just up a tier — the VM must be stopped and deallocated first, the resize applied, then the VM restarted. Plan resizes as a maintenance action, not a live operation, unless you've confirmed otherwise for that specific size pair.

Availability sets vs availability zones

These two constructs solve different failure scenarios and are often confused because both are described as "high availability."

An availability set is a logical grouping within a single Azure datacenter that spreads VMs across fault domains and update domains. A fault domain groups VMs sharing a common power source and network switch — typically 2 or 3 per set — so a rack-level hardware or power failure doesn't take out every instance. An update domain governs the order in which VMs are rebooted during planned host maintenance — typically up to 20 — so Azure doesn't patch every replica simultaneously. Availability sets carry a 99.95% SLA when you run two or more VMs in the set. They protect against hardware failure and planned maintenance, but not against the datacenter itself going offline.

az vm availability-set create \
  --resource-group rg-app-prod \
  --name avset-app \
  --platform-fault-domain-count 3 \
  --platform-update-domain-count 5

An availability zone is a physically separate facility within the same Azure region, with its own independent power, cooling, and networking. Regions that support zones typically expose three of them. Deploying VMs across zones protects against a full datacenter outage — the failure domain is the building, not the rack. VMs spread across two or more zones carry a 99.99% SLA. The tradeoff is slightly higher and more variable network latency between zones compared to same-datacenter, same-fault-domain traffic, which matters for latency-sensitive tiers like synchronous database replication.

A VM is provisioned into either an availability set or a specific availability zone at creation time — the two models are mutually exclusive for a given instance, and you cannot convert one into the other without redeploying. A common production pattern is zone-redundant front-end tiers behind a zone-redundant load balancer, with availability sets reserved for regions or resource types that don't yet support zones.

Managed disk tiers and performance tradeoffs

Managed disks come in four performance tiers, and the right one is determined by IOPS and throughput requirements, not just capacity.

Standard HDD is magnetic-backed storage with the lowest cost and the highest latency variability. It's appropriate for backup targets, infrequently accessed data, and dev/test disks where performance consistency doesn't matter.

Standard SSD offers meaningfully more consistent latency than Standard HDD at a modest cost increase, without the full IOPS ceiling of Premium SSD. It's a reasonable default for lightly used web servers, domain controllers, and application tiers that aren't disk-bound.

Premium SSD is the standard choice for production workloads with real IO demand — databases, transaction logs, and anything sensitive to disk latency. It requires an s-suffixed VM size (Premium Storage-capable) to attach. IOPS and throughput scale with the provisioned disk size tier, so undersizing a Premium SSD for capacity reasons can silently cap performance below what the workload needs — check the performance ceiling for the specific disk size, not just its capacity, before assuming it will keep up.

Ultra Disk sits above Premium SSD and is the only tier (alongside the newer Premium SSD v2) that lets you tune provisioned IOPS and throughput independently of the disk's capacity, and adjust them on the fly without downtime. It targets the lowest and most consistent latency Azure offers, for workloads like SAP HANA or top-tier SQL/Oracle instances where both throughput and latency SLAs matter simultaneously. Ultra Disk is a zonal resource — the disk and the VM must be deployed in the same availability zone, which needs to be factored into the availability-zone decision above, not treated as an afterthought.

az disk create \
  --resource-group rg-app-prod \
  --name disk-app01-data \
  --size-gb 512 \
  --sku Premium_LRS \
  --zone 1

az vm disk attach \
  --resource-group rg-app-prod \
  --vm-name vm-app01 \
  --name disk-app01-data

A frequent mistake is provisioning a large Standard HDD or Standard SSD purely for capacity and then being surprised by IO wait times under load — capacity and performance are separate axes on every tier below Ultra Disk, and only Ultra Disk and Premium SSD v2 decouple them fully.

Monitoring and diagnosing VM performance

Two distinct diagnostic tools cover two distinct failure modes, and it's worth being clear on which one to reach for.

Boot diagnostics captures serial console output and periodic screenshots of the VM's display during startup, persisted to a storage account. It answers "why won't this VM come up" — kernel panics, missing boot drivers after a migration, a stuck disk check, or a guest OS that never reaches the point of accepting network connections. Enable it at creation or after the fact:

az vm boot-diagnostics enable \
  --resource-group rg-app-prod \
  --name vm-app01

It is not a performance monitoring tool — it tells you nothing about a VM that boots fine but runs slowly.

Azure Monitor VM insights answers the performance question. It installs the Azure Monitor Agent on the guest and collects performance counters — CPU utilization, available memory, disk IOPS and latency per disk, and network throughput — into a Log Analytics workspace, along with process and dependency maps. This is the source of truth for whether a VM is actually CPU-bound, memory-bound, or IO-bound, as opposed to guessing from application-layer symptoms. Host-level platform metrics (visible without any agent) cover CPU and disk at the hypervisor level but do not include in-guest memory pressure, so VM insights or the guest-level agent is required if memory is a suspect.

When diagnosing a specific slowdown, check disk queue depth and IO latency per disk alongside CPU — a VM that looks CPU-constrained in host metrics is sometimes actually blocked waiting on a Standard SSD that can't keep up with write volume, which host-level CPU graphs alone won't reveal.

Right-sizing based on actual utilization

Sizing decisions made from a single utilization snapshot or from "what we always provision" are the most common source of both wasted spend and recurring performance incidents. Use Azure Monitor metrics over a representative window — a minimum of 30 days to capture weekly and month-end cycles — and look at percentiles rather than averages: average CPU can look comfortably low while p95 CPU during the daily peak is pegged near 100%, which an average would hide entirely.

Azure Advisor generates right-sizing recommendations automatically from this same utilization history and will flag both over-provisioned VMs (candidates for a smaller size or a cheaper series) and VMs showing sustained pressure that a larger size or different series would relieve. Treat these as a starting point to investigate, not an instruction to execute blind — Advisor doesn't know about planned traffic growth, upcoming batch jobs, or seasonal load.

Before resizing, confirm which resource is actually constrained: a VM pegged on memory gains nothing from more vCPUs, and a VM blocked on disk IO gains nothing from a bigger size unless the new size also raises the disk-throughput cap it's attached to (larger sizes generally support higher uncached and cached disk throughput limits, independent of the disks themselves). Cross-check the target size's published disk and network throughput limits against the current bottleneck, not just its vCPU and memory numbers, before committing to a resize.

az monitor metrics list \
  --resource /subscriptions/<sub-id>/resourceGroups/rg-app-prod/providers/Microsoft.Compute/virtualMachines/vm-app01 \
  --metric "Percentage CPU" \
  --interval PT1H \
  --start-time 2026-06-21T00:00:00Z \
  --end-time 2026-07-21T00:00:00Z \
  --aggregation Average Maximum

Re-run this evaluation periodically rather than treating a sizing decision as permanent — workload profiles drift, and a size that was correct at launch is a common source of both silent overspend and slow performance degradation eighteen months later.

Key Takeaways

  • Match VM series to workload shape (vCPU:memory ratio and burst tolerance) before matching it to a benchmark number
  • Availability sets and availability zones solve different failure domains and are frequently used together with a load balancer, not as substitutes for each other
  • Disk tier selection should be driven by IOPS/throughput/latency requirements per workload, not just capacity in GB
  • Boot diagnostics and VM insights answer different questions — one tells you why a VM won't come up, the other tells you why a running VM is slow
  • Right-size from 30+ days of Azure Monitor percentile data, not from a single CPU spike or a guess based on the application's reputation

Related Articles

Azure AD & Entra ID: User ManagementAzure Networking: VNets, NSG & ExpressRouteAzure SQL Database vs SQL Server on VMsAzure Cost Management & FinOps