Skip to content

Storage Redundancy

Lab Objective

In this hands-on lab, you will learn how to:

  • Understand Azure Storage redundancy options and their use cases
  • Configure different redundancy types (LRS, ZRS, GRS, RA-GRS, GZRS, RA-GZRS)
  • Change redundancy settings for existing storage accounts
  • Test failover scenarios with geo-redundant storage
  • Monitor replication status and understand RPO/RTO implications
  • Analyze cost implications of different redundancy choices

Scenario: Your organization needs to implement appropriate data protection strategies for different types of data workloads. You’ll configure various redundancy options and test failover scenarios to understand their behavior and limitations.


Pre-Provisioned Environment

The following Azure resources have been pre-deployed in your environment:

Resource Overview

Resource TypeResource NameConfigurationPurpose
Resource GroupStorageRedundancy-Lab-RGContains all lab resourcesLogical container
Storage Accountlrsdata[unique]LRS - Hot tierLocal redundancy testing
Storage Accountzrsdata[unique]ZRS - Hot tierZone redundancy testing
Storage Accountgrsdata[unique]GRS - Hot tierGeo redundancy testing
Storage Accountragrsdata[unique]RA-GRS - Hot tierRead-access geo redundancy
Test VMTestVMWindows Server 2019Data upload and testing
Blob ContainersVariousPrivate accessTest data storage

Storage Account Configuration

AccountRedundancy TypePrimary RegionSecondary RegionRead Access
lrsdata[unique]LRSEast USNonePrimary only
zrsdata[unique]ZRSEast USNonePrimary only
grsdata[unique]GRSEast USWest USPrimary only
ragrsdata[unique]RA-GRSEast USWest USPrimary + Secondary

Data Distribution Scenarios

Local Redundant Storage (LRS)
Primary Region: East US
β”œβ”€β”€ Datacenter 1
β”‚ β”œβ”€β”€ Copy 1 (Rack A)
β”‚ β”œβ”€β”€ Copy 2 (Rack B)
β”‚ └── Copy 3 (Rack C)
└── No secondary region protection
Zone Redundant Storage (ZRS)
Primary Region: East US
β”œβ”€β”€ Availability Zone 1 (Copy 1)
β”œβ”€β”€ Availability Zone 2 (Copy 2)
└── Availability Zone 3 (Copy 3)
Geo Redundant Storage (GRS)
β”œβ”€β”€ Primary Region: East US (3 copies)
└── Secondary Region: West US (3 copies)
└── Asynchronous replication

VM Details

VMPrivate IPOperating SystemPurpose
TestVM10.0.1.4Windows Server 2019Upload test data and monitor replication

Lab Exercises

Part 1: Understand Current Redundancy Configuration

Step 1: Examine Storage Account Properties

  1. Navigate to StorageRedundancy-Lab-RG resource group
  2. Review each storage account:

For lrsdata[unique]:

  • Click the storage account
  • Go to Configuration
  • Observe: Replication = β€œLocally-redundant storage (LRS)”
  • Note: No secondary region listed

For zrsdata[unique]:

  • Observe: Replication = β€œZone-redundant storage (ZRS)”
  • Note: Same region, multiple zones

For grsdata[unique]:

  • Observe: Replication = β€œGeo-redundant storage (GRS)”
  • Note: Secondary region shown but not accessible

For ragrsdata[unique]:

  • Observe: Replication = β€œRead-access geo-redundant storage (RA-GRS)”
  • Note: Secondary region accessible for reads

Step 2: Check Secondary Endpoints

  1. For ragrsdata[unique], go to Endpoints
  2. Observe both endpoints:
    • Primary blob endpoint: https://ragrsdata[unique].blob.core.windows.net/
    • Secondary blob endpoint: https://ragrsdata[unique]-secondary.blob.core.windows.net/

Step 3: Review Pricing Implications

  1. Go to Cost Management + Billing
  2. Compare estimated costs for different redundancy types:
RedundancyRelative CostDurabilityAvailability
LRS1x (baseline)99.999999999% (11 9’s)99.9%
ZRS~1.25x99.9999999999% (12 9’s)99.9%
GRS~2x99.99999999999999% (16 9’s)99.9%
RA-GRS~2.5x99.99999999999999% (16 9’s)99.99%

Part 2: Upload Test Data

Step 1: Connect to Test VM

  1. Navigate to TestVM
  2. Click Connect β†’ RDP
  3. Use credentials:
    • Username: azureuser
    • Password: LabPassword123!

Step 2: Install Azure PowerShell (if needed)

From TestVM PowerShell (as Administrator):

Terminal window
# Install Azure PowerShell module
Install-Module -Name Az -Force -AllowClobber
Import-Module Az
# Connect to Azure
Connect-AzAccount

Step 3: Create Test Data

Terminal window
# Create test files of different sizes
$testDataPath = "C:\TestData"
New-Item -ItemType Directory -Path $testDataPath -Force
# Small file (1 MB)
$smallFile = "$testDataPath\small-file.txt"
$content = "Test data for redundancy lab`n" * 50000
$content | Out-File -FilePath $smallFile
# Medium file (10 MB)
$mediumFile = "$testDataPath\medium-file.bin"
$bytes = New-Object byte[] (10MB)
(New-Object Random).NextBytes($bytes)
[System.IO.File]::WriteAllBytes($mediumFile, $bytes)
# Large file (100 MB)
$largeFile = "$testDataPath\large-file.bin"
$bytes = New-Object byte[] (100MB)
(New-Object Random).NextBytes($bytes)
[System.IO.File]::WriteAllBytes($largeFile, $bytes)
# Verify files created
Get-ChildItem $testDataPath | Select-Object Name, Length

Step 4: Upload Data to All Storage Accounts

Terminal window
# Define storage accounts
$storageAccounts = @(
"lrsdata[unique]",
"zrsdata[unique]",
"grsdata[unique]",
"ragrsdata[unique]"
)
$resourceGroup = "StorageRedundancy-Lab-RG"
$containerName = "testdata"
foreach ($accountName in $storageAccounts) {
Write-Host "Uploading to $accountName..."
# Get storage context
$storageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name $accountName
$ctx = $storageAccount.Context
# Create container if it doesn't exist
New-AzStorageContainer -Name $containerName -Context $ctx -Permission Off -ErrorAction SilentlyContinue
# Upload test files
Set-AzStorageBlobContent -File $smallFile -Container $containerName -Blob "small-file.txt" -Context $ctx -Force
Set-AzStorageBlobContent -File $mediumFile -Container $containerName -Blob "medium-file.bin" -Context $ctx -Force
Set-AzStorageBlobContent -File $largeFile -Container $containerName -Blob "large-file.bin" -Context $ctx -Force
Write-Host "Upload completed for $accountName"
}

Part 3: Test Read Access to Secondary Region

Step 1: Test RA-GRS Secondary Read Access

Terminal window
# Test primary endpoint access
$primaryEndpoint = "https://ragrsdata[unique].blob.core.windows.net/testdata/small-file.txt"
$secondaryEndpoint = "https://ragrsdata[unique]-secondary.blob.core.windows.net/testdata/small-file.txt"
# Get storage account key for authentication
$ragrsAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name "ragrsdata[unique]"
$key = (Get-AzStorageAccountKey -ResourceGroupName $resourceGroup -Name "ragrsdata[unique]")[0].Value
# Test primary access
try {
$headers = @{
'x-ms-version' = '2020-10-02'
'Authorization' = "SharedKey ragrsdata[unique]:$key"
}
$response = Invoke-WebRequest -Uri $primaryEndpoint -Headers $headers -Method HEAD
Write-Host "Primary endpoint: SUCCESS - Status $($response.StatusCode)"
} catch {
Write-Host "Primary endpoint: FAILED - $($_.Exception.Message)"
}
# Test secondary access (may take time to replicate)
try {
$response = Invoke-WebRequest -Uri $secondaryEndpoint -Headers $headers -Method HEAD
Write-Host "Secondary endpoint: SUCCESS - Status $($response.StatusCode)"
Write-Host "Data successfully replicated to secondary region"
} catch {
Write-Host "Secondary endpoint: FAILED - Data not yet replicated or access issue"
Write-Host "Error: $($_.Exception.Message)"
}

Step 2: Monitor Replication Status

Terminal window
# Check last sync time for RA-GRS account
$ragrsAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name "ragrsdata[unique]"
# Get replication status
$replicationStatus = Get-AzStorageAccountKey -ResourceGroupName $resourceGroup -Name "ragrsdata[unique]"
Write-Host "Storage account properties:"
$ragrsAccount | Select-Object StorageAccountName, Location, SecondaryLocation, StatusOfPrimary, StatusOfSecondary
# Check blob properties for replication metadata
$ctx = $ragrsAccount.Context
$blob = Get-AzStorageBlob -Container "testdata" -Blob "small-file.txt" -Context $ctx
Write-Host "Blob last modified: $($blob.LastModified)"
Write-Host "Blob ETag: $($blob.ETag)"

Part 4: Change Redundancy Configuration

Step 1: Upgrade LRS to GRS

  1. Navigate to lrsdata[unique] storage account
  2. Go to Configuration
  3. Change replication from LRS to GRS:
    • Click on Replication dropdown
    • Select β€œGeo-redundant storage (GRS)”
    • Note: Some configurations may require recreating the storage account

Step 2: Test Redundancy Change Limitations

Try different upgrade paths:

FromToSupportedNotes
LRSZRSLimitedRequires live migration
LRSGRSYesDirect upgrade
GRSRA-GRSYesDirect upgrade
ZRSGZRSYesDirect upgrade
GRSLRSYesData loss warning

Step 3: Monitor Upgrade Progress

Terminal window
# Monitor the LRS to GRS upgrade
$lrsAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name "lrsdata[unique]"
Write-Host "Current replication type: $($lrsAccount.Sku.Name)"
Write-Host "Primary location: $($lrsAccount.PrimaryLocation)"
Write-Host "Secondary location: $($lrsAccount.SecondaryLocation)"
# Check if upgrade is in progress
Write-Host "Replication state: $($lrsAccount.GeoReplicationStats)"

Part 5: Simulate and Test Failover Scenarios

Step 1: Initiate Account Failover (RA-GRS only)

Note: This is a destructive operation that should only be done in testing

  1. Navigate to ragrsdata[unique] storage account
  2. Go to Geo-replication
  3. Review failover implications:
    • Data loss potential (RPO)
    • Service downtime (RTO)
    • Cost implications

Step 2: Test Failover Prerequisites

Terminal window
# Check if account is eligible for failover
$ragrsAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name "ragrsdata[unique]"
Write-Host "Failover eligibility check:"
Write-Host "Account type: $($ragrsAccount.Sku.Name)"
Write-Host "Primary location: $($ragrsAccount.PrimaryLocation)"
Write-Host "Secondary location: $($ragrsAccount.SecondaryLocation)"
# Check last sync time (important for data loss assessment)
$geoStats = $ragrsAccount.GeoReplicationStats
Write-Host "Last sync time: $($geoStats.LastSyncTime)"
Write-Host "Replication status: $($geoStats.Status)"

Step 3: Simulate Application Behavior During Outage

Terminal window
# Simulate primary region unavailable by trying secondary endpoint
$secondaryCtx = New-AzStorageContext -StorageAccountName "ragrsdata[unique]" -StorageAccountKey $key -Endpoint "core.windows.net" -Protocol "https"
try {
# List containers using secondary endpoint
$containers = Get-AzStorageContainer -Context $secondaryCtx
Write-Host "Secondary region access: SUCCESS"
Write-Host "Available containers: $($containers.Count)"
# Try to read data from secondary
$blobs = Get-AzStorageBlob -Container "testdata" -Context $secondaryCtx
Write-Host "Blobs accessible from secondary: $($blobs.Count)"
} catch {
Write-Host "Secondary region access: FAILED - $($_.Exception.Message)"
}

Part 6: Performance and Cost Analysis

Step 1: Measure Access Performance

Terminal window
# Test read performance from different redundancy types
function Test-StoragePerformance {
param($StorageAccountName, $RedundancyType)
$account = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name $StorageAccountName
$ctx = $account.Context
$downloadPath = "C:\temp\downloaded-$RedundancyType.bin"
# Measure download time
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
Get-AzStorageBlobContent -Container "testdata" -Blob "medium-file.bin" -Destination $downloadPath -Context $ctx -Force
$stopwatch.Stop()
Write-Host "$RedundancyType - Download time: $($stopwatch.ElapsedMilliseconds) ms"
# Clean up
Remove-Item $downloadPath -ErrorAction SilentlyContinue
}
# Test each redundancy type
Test-StoragePerformance -StorageAccountName "lrsdata[unique]" -RedundancyType "LRS"
Test-StoragePerformance -StorageAccountName "zrsdata[unique]" -RedundancyType "ZRS"
Test-StoragePerformance -StorageAccountName "grsdata[unique]" -RedundancyType "GRS"
Test-StoragePerformance -StorageAccountName "ragrsdata[unique]" -RedundancyType "RA-GRS"

Step 2: Analyze Cost Implications

Terminal window
# Calculate storage costs for different redundancy types
$fileSize = 100MB # Size of our test file
$monthlyStorage = $fileSize * 30 # Simulate 30 files per month
$costAnalysis = @{
"LRS" = @{
"StorageCost" = 1.0
"TransactionCost" = 1.0
"ReplicationCost" = 0.0
}
"ZRS" = @{
"StorageCost" = 1.25
"TransactionCost" = 1.0
"ReplicationCost" = 0.25
}
"GRS" = @{
"StorageCost" = 2.0
"TransactionCost" = 1.0
"ReplicationCost" = 1.0
}
"RA-GRS" = @{
"StorageCost" = 2.5
"TransactionCost" = 1.2
"ReplicationCost" = 1.5
}
}
Write-Host "Cost Analysis (Relative to LRS baseline):"
$costAnalysis.GetEnumerator() | ForEach-Object {
$total = $_.Value.StorageCost + $_.Value.TransactionCost + $_.Value.ReplicationCost
Write-Host "$($_.Key): Storage $($_.Value.StorageCost)x, Transactions $($_.Value.TransactionCost)x, Total: $($total)x"
}

Part 7: Disaster Recovery Testing

Step 1: Create Disaster Recovery Plan

Document recovery scenarios:

ScenarioAffected StorageRecovery MethodRTORPO
Datacenter failureLRSRestore from backup4-8 hoursUp to 24 hours
Zone failureZRSAutomatic failoverMinutesNear zero
Region failureGRSManual failover1-2 hoursUp to 1 hour
Region failureRA-GRSAutomatic failoverMinutesUp to 15 minutes

Step 2: Test Recovery Procedures

Terminal window
# Simulate recovery by switching to secondary endpoint
function Test-DisasterRecovery {
param($AccountName, $RedundancyType)
Write-Host "Testing DR scenario for $RedundancyType ($AccountName):"
$account = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name $AccountName
if ($RedundancyType -like "*GRS*") {
# Test secondary region access
$secondaryEndpoint = $account.PrimaryEndpoints.Blob -replace "\.blob\.", "-secondary.blob."
Write-Host "Secondary endpoint: $secondaryEndpoint"
try {
# Test if secondary is accessible
$uri = "$secondaryEndpoint/testdata/small-file.txt"
$response = Invoke-WebRequest -Uri $uri -Method HEAD
Write-Host "Secondary region: ACCESSIBLE"
} catch {
Write-Host "Secondary region: NOT ACCESSIBLE - $($_.Exception.Message)"
}
} else {
Write-Host "No secondary region available for $RedundancyType"
}
}
# Test DR for each account type
Test-DisasterRecovery -AccountName "lrsdata[unique]" -RedundancyType "LRS"
Test-DisasterRecovery -AccountName "zrsdata[unique]" -RedundancyType "ZRS"
Test-DisasterRecovery -AccountName "grsdata[unique]" -RedundancyType "GRS"
Test-DisasterRecovery -AccountName "ragrsdata[unique]" -RedundancyType "RA-GRS"

Troubleshooting Guide

Common Redundancy Issues

IssueSymptomsPossible CauseSolution
Secondary endpoint access denied403 errors on secondaryGRS instead of RA-GRSUpgrade to RA-GRS for read access
Slow replicationData not appearing in secondaryNetwork or service issuesCheck geo-replication status
Cannot change redundancyConfiguration option grayed outAccount type limitationsCheck compatibility matrix
High costsUnexpected billingWrong redundancy for use caseAnalyze requirements and downgrade
Failover unavailableFailover option not shownAccount not eligibleVerify account type and region

Redundancy Selection Guide

Use CaseRecommended RedundancyJustification
Dev/Test dataLRSCost-effective, acceptable risk
Production apps (single region)ZRSZone failure protection
Business critical dataRA-GRS or RA-GZRSMaximum availability and durability
Archive dataGRSCost-effective long-term storage
Disaster recoveryRA-GRSRead access during outages

Additional Experiments

Try these optional exercises to deepen your understanding:

  • GZRS Configuration: Set up Geo-Zone Redundant Storage for maximum protection
  • Cross-Region Replication: Implement custom cross-region backup strategies
  • Lifecycle Management: Configure automatic tier transitions based on redundancy
  • Monitoring Setup: Create alerts for replication lag and failover events
  • Cost Optimization: Implement policies to automatically adjust redundancy based on data age

Key Takeaways

After completing this lab, you should understand:

  • Different redundancy types provide varying levels of protection and cost
  • LRS and ZRS protect against hardware/zone failures within a region
  • GRS and RA-GRS protect against entire region failures
  • Secondary read access is only available with RA-GRS and RA-GZRS
  • Failover operations can result in data loss and should be carefully planned
  • Cost increases significantly with higher redundancy levels
  • Redundancy choice should align with business requirements and budget

Azure Storage Redundancy Matrix

Protection Levels

RedundancyLocal FailuresZone FailuresRegion FailuresRead Access
LRSβœ…βŒβŒPrimary only
ZRSβœ…βœ…βŒPrimary only
GRSβœ…βŒβœ…Primary only
RA-GRSβœ…βŒβœ…Primary + Secondary
GZRSβœ…βœ…βœ…Primary only
RA-GZRSβœ…βœ…βœ…Primary + Secondary

Durability and Availability

RedundancyDurability (per year)Availability SLATypical RPOTypical RTO
LRS99.999999999% (11 9’s)99.9%0Minutes
ZRS99.9999999999% (12 9’s)99.9%0Minutes
GRS99.99999999999999% (16 9’s)99.9%< 1 hour< 1 hour
RA-GRS99.99999999999999% (16 9’s)99.99%< 15 minutes< 15 minutes

Decision Framework

Choosing the Right Redundancy

Step 1: Assess Requirements

  • What is the acceptable data loss (RPO)?
  • What is the acceptable downtime (RTO)?
  • What is the budget for storage costs?
  • Are there compliance requirements?

Step 2: Evaluate Risks

  • What are the consequences of data loss?
  • How critical is continuous availability?
  • Are there seasonal or business cycle considerations?

Step 3: Select Redundancy

  • Mission-critical, zero tolerance: RA-GZRS
  • Business-critical, some tolerance: RA-GRS or GZRS
  • Important, single region: ZRS
  • Development, testing: LRS

Additional Resources