Practical Guidance Working with Azure Availability Zones and Physical Zones

Andrew Citera
7 min readFeb 22, 2025

--

There has been plenty of discussion about Azure Regions, Availability Zones, and Physical Zones, but it’s worth revisiting how these concepts interact — especially because they can significantly affect both resiliency and performance in ways that aren’t always intuitive. In this article, we’ll clarify the differences between logical zones and physical zones, explain how Azure maps them behind the scenes, and show you how to query those mappings. We’ll also cover when (and why) you might care about physical placement, including the potential latency and resiliency tradeoffs.

Overview

An Azure Region is a collection of one or more physical datacenters, connected by a high-capacity, fault-tolerant, low-latency network connection. Azure datacenters are typically located within a large metropolitan area. Every region is contained within a single geography that serves as a fixed data residency boundary.

Source: Microsoft Documentation

An Azure Availability Zone is a collection of independent datacenters that contains isolated power, cooling, and network connections. Availability zones are physically located close enough together to provide a low-latency network, but far enough apart to provide fault isolation from such things as storms and isolated power outages. Most Azure services provide built-in support for availability zones and you can decide how to use them to meet your needs. Availability zones are typically separated by several kilometers, and usually are within 100 kilometers .For Azure Regions that support Availability Zones a region can be thought of as a collection of Availability Zones.

Source: Microsoft Document

An Azure Physical Zone is a specific physical Azure Datacenter. In most Azure documentation one will see the Availability Zone term most often used — this typically refers to the ‘Logical Zone’. For example, when looking at a VM in the Azure Portal under ‘Location’ if it references Zone 2 it’s referring to Logical Zone 2 not the physical zone. Physical zones are mapped to logical zones in your Azure subscription, and different subscriptions might have a different mapping order. Azure subscriptions are automatically assigned their mapping at the time the subscription is created. This design from Azure is primarily to help with their own capacity management to avoid unevenly distributed placements. Because of this, the zone mapping for one subscription could be different for other subscriptions. An example diagram is shown below:

Source: Microsoft Documentation

Main Takeaways

The main takeaways for those working in Azure environments from the above overview are that:

  1. Logical Zones are not the same as Physical Zones
  2. The mapping between a Logical Zone and a Physical Zone is only consistent within a subscription and not across different subscriptions
  3. When comparing zones between two different subscriptions one needs to identification the mapping first and then baseline against physical zones

While a majority of use cases will be indifferent to the Physical Zone it may need to be a consideration for some. For instance, if an application is particularly latency sensitive or if physical placement is important to address concentration risk associated with workload placement due to resiliency requirements. Microsoft strives to achieve an inter-zone communication with round-trip latency of less than approximately 2 milliseconds, but even this amount of latency can be too much for certain workloads such as with simulation or modeling tools. With that said, it’s still important to weigh the performance tradeoff with the reliability tradeoff since zone pinning workloads can reduce resiliency if not properly accounted for. The common recommendation is to default to zone-redundant deployments unless there are clear requirements that necessitate moving away from that model.

Useful Azure CLI Commands

If business or technical requirements result in needing to account for Logical Zone and Physical Zone mappings there are Azure CLI commands that can be used to query the Azure Resource provider. There are also equivalent PowerShell commands, but no native CLI support (without using the REST methods) and no other native SDK support. Before leveraging these commands the required provider must be registered and then re-registered.

For the commands we’ll cover to work one will need to run the following pre-req commands:

#First register the Microsoft.Resources provider
az provider register -n Microsoft.Resources
#Second register the required feature
az feature register -n AvailabilityZonePeering --namespace Microsoft.Resources
#Check that the feature has completed registering (can take anywhere from 15 minutes to an hour)
az feature show --namespace Microsoft.Resources --name AvailabilityZonePeering
#Once the above feature has completed registering one must re-register original provider
az provider register -n Microsoft.Resources

Once the above pre-reqs are run the following commands can be run to identify the intra and inter subscription zone mappings. I’d recommend copy / pasting these individually rather than as a complete script to understand the logic first.

###############################################################################
# These commands show how to retrieve the logical-to-physical zone mapping from
# two Azure subscriptions (labeled "Subscription A" and "Subscription B"), and
# then compare the logical zone mappings by checking zone peers.
#
# Replace <SubscriptionA> and <SubscriptionB> with your actual subscription IDs.
###############################################################################

###############################################################################
# 1. Retrieve location details from Subscription A
# - We make a GET request to list all locations for <SubscriptionA>.
# - We filter for "australiaeast" and non-null zone mappings.
###############################################################################
echo "=== 1. Retrieve location details from Subscription A ==="
az rest \
--method get \
--uri "/subscriptions/<SubscriptionA>/locations?api-version=2022-12-01" \
--query "value[?name=='australiaeast' && availabilityZoneMappings != null].{displayName: displayName, name: name, availabilityZoneMappings: availabilityZoneMappings}"

# SAMPLE OUTPUT (from Subscription A):
# [
# {
# "availabilityZoneMappings": [
# {
# "logicalZone": "1",
# "physicalZone": "australiaeast-az1"
# },
# {
# "logicalZone": "2",
# "physicalZone": "australiaeast-az3"
# },
# {
# "logicalZone": "3",
# "physicalZone": "australiaeast-az2"
# }
# ],
# "displayName": "Australia East",
# "name": "australiaeast"
# }
# ]

###############################################################################
# 2. Retrieve location details from Subscription B
# - Similar logic for <SubscriptionB>. Same filters: "australiaeast" and
# non-null zone mappings.
###############################################################################
echo "=== 2. Retrieve location details from Subscription B ==="
az rest \
--method get \
--uri "/subscriptions/<SubscriptionB>/locations?api-version=2022-12-01" \
--query "value[?name=='australiaeast' && availabilityZoneMappings != null].{displayName: displayName, name: name, availabilityZoneMappings: availabilityZoneMappings}"

# SAMPLE OUTPUT (from Subscription B):
# [
# {
# "availabilityZoneMappings": [
# {
# "logicalZone": "1",
# "physicalZone": "australiaeast-az2"
# },
# {
# "logicalZone": "2",
# "physicalZone": "australiaeast-az1"
# },
# {
# "logicalZone": "3",
# "physicalZone": "australiaeast-az3"
# }
# ],
# "displayName": "Australia East",
# "name": "australiaeast"
# }
# ]

###############################################################################
# 3. Check zone peers from Subscription A perspective
# - We POST to the checkZonePeers endpoint for <SubscriptionA>, passing
# <SubscriptionB> in the body. This returns how the logical zones in A
# map to those in B.
###############################################################################
echo "=== 3. Check zone peers from Subscription A perspective ==="
az rest \
--method post \
--uri "https://management.azure.com/subscriptions/<SubscriptionA>/providers/Microsoft.Resources/checkZonePeers?api-version=2022-12-01" \
--body "{\"location\": \"australiaeast\", \"subscriptionIds\": [\"/subscriptions/<SubscriptionB>\"]}"

# SAMPLE OUTPUT (from Subscription A perspective):
# {
# "availabilityZonePeers": [
# {
# "availabilityZone": "1",
# "peers": [
# {
# "availabilityZone": "2",
# "subscriptionId": "<SubscriptionB>"
# }
# ]
# },
# {
# "availabilityZone": "2",
# "peers": [
# {
# "availabilityZone": "3",
# "subscriptionId": "<SubscriptionB>"
# }
# ]
# },
# {
# "availabilityZone": "3",
# "peers": [
# {
# "availabilityZone": "1",
# "subscriptionId": "<SubscriptionB>"
# }
# ]
# }
# ],
# "location": "australiaeast",
# "subscriptionId": "<SubscriptionA>"
# }

###############################################################################
# 4. Check zone peers from Subscription B perspective
# - Similar logic, but we POST for <SubscriptionB> and pass <SubscriptionA>
# in the body, letting us see the logical zone relationships from B's view.
###############################################################################
echo "=== 4. Check zone peers from Subscription B perspective ==="
az rest \
--method post \
--uri "https://management.azure.com/subscriptions/<SubscriptionB>/providers/Microsoft.Resources/checkZonePeers?api-version=2022-12-01" \
--body "{\"location\": \"australiaeast\", \"subscriptionIds\": [\"/subscriptions/<SubscriptionA>\"]}"

# SAMPLE OUTPUT (from Subscription B perspective):
# {
# "availabilityZonePeers": [
# {
# "availabilityZone": "1",
# "peers": [
# {
# "availabilityZone": "3",
# "subscriptionId": "<SubscriptionA>"
# }
# ]
# },
# {
# "availabilityZone": "2",
# "peers": [
# {
# "availabilityZone": "1",
# "subscriptionId": "<SubscriptionA>"
# }
# ]
# },
# {
# "availabilityZone": "3",
# "peers": [
# {
# "availabilityZone": "2",
# "subscriptionId": "<SubscriptionA>"
# }
# ]
# }
# ],
# "location": "australiaeast",
# "subscriptionId": "<SubscriptionB>"
# }

The ‘Locations’ endpoint is used to determine the specific mapping of a specific subscription whereas the ‘GetZonePeers’ allows you to see how that mapping compares to another subscription. This allows you to determine the peer mapping without needing to authenticate against that particular subscription. It’s essentially the code equivalent on the earlier visual diagram showing the mappings of zones between subscriptions. These commands could be used to build deployment automation or run reports.

Closing Remarks

This practical guidance should serve as a foundation for understanding the relationship between Azure Regions, Azure Availability Zones, and Azure Physical Zones. Remember — the majority of workloads will not need to concern themselves of this mapping although there are specific use cases that may require the lower level consideration. Additionally, it’s worth noting that even co-location within zones in a subscription does not guarantee the expected performance especially when working with managed services. For example, I’ve found that even placing a VM in the same zone as a PSQL Flexible Server PaaS offering from Azure doesn’t always guarantee the lowest latency and should be verified with thorough testing although I’d imagine this may be less of an issue if only using IaaS.

Thank you for taking the time to read. I’d love to hear your thoughts, feedback, or any challenges you’ve faced related to the topic — feel free to share your insights, ask questions in the comments, or reach out directly.

The views expressed in this post are my own and do not necessarily reflect the official policies, positions, or views of the global EY organization or its member firms.

--

--

No responses yet