Skip to main content

Disaster Recovery

Multi-Region Shopping Mall implements disaster recovery (DR) strategies targeting RPO < 1 second, RTO < 10 minutes. This document details data replication lag, failover procedures, and recovery processes.

DR Goals​

MetricTargetDescription
RPO (Recovery Point Objective)< 1 secondAcceptable data loss range
RTO (Recovery Time Objective)< 10 minutesService recovery time
Availability99.99%Annual downtime under 52 minutes

Data Replication Lag​

Replication Lag by Data Store​

Data StoreReplication MethodAverage LagMaximum LagRPO Compliance
Aurora PostgreSQLGlobal Database< 100ms< 1 secondO
DocumentDBGlobal Cluster< 100ms< 1 secondO
ElastiCache ValkeyGlobal Datastore< 50ms< 500msO
MSK KafkaMSK Replicator< 500ms< 2 secondsO
OpenSearchNone (per-region)N/AN/AN/A

Monitoring Replication Lag​

-- Check Aurora Global Database replication lag
SELECT
server_id,
session_id,
replica_lag_in_msec,
last_update_timestamp
FROM aurora_global_db_instance_status()
WHERE session_id = 'GLOBAL';
# Check ElastiCache Global Datastore lag
aws elasticache describe-global-replication-groups \
--global-replication-group-id production-global-datastore \
--query 'GlobalReplicationGroups[0].Members[*].{Region:ReplicationGroupRegion,Lag:GlobalReplicationGroupMemberRole}'

# CloudWatch metrics
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name AuroraGlobalDBReplicationLag \
--dimensions Name=DBClusterIdentifier,Value=production-aurora-global-us-west-2 \
--start-time $(date -d '1 hour ago' -u +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 60 \
--statistics Average

Failover Decision Matrix​

Response by Failure Type​

Failure TypeImpact ScopeDetection MethodFailover TypeExpected RTO
Single EC2/Pod failurePartial serviceEKS Health CheckAutomatic (Kubernetes)< 30 seconds
Single AZ failureResources in AZRoute 53 Health CheckAutomatic (Multi-AZ)< 1 minute
Aurora Primary failureWrite operationsAurora Auto-failoverAutomatic (Aurora)1-2 minutes
EKS cluster failureRegional servicesALB Health CheckAutomatic (Route 53)< 2 minutes
Full region failureAll servicesManual verificationManual5-10 minutes

Failover Decision Flow​

Automatic Failover​

Route 53 Health Check Based​

Terraform Configuration​

# Route 53 Health Check
resource "aws_route53_health_check" "alb_use1" {
fqdn = aws_lb.use1.dns_name
port = 443
type = "HTTPS"
resource_path = "/health"
failure_threshold = 3
request_interval = 10

tags = {
Name = "alb-us-east-1-health-check"
}
}

resource "aws_route53_health_check" "alb_usw2" {
fqdn = aws_lb.usw2.dns_name
port = 443
type = "HTTPS"
resource_path = "/health"
failure_threshold = 3
request_interval = 10

tags = {
Name = "alb-us-west-2-health-check"
}
}

# Latency-based routing with health check
resource "aws_route53_record" "api_use1" {
zone_id = aws_route53_zone.main.zone_id
name = "api.atomai.click"
type = "A"

alias {
name = aws_lb.use1.dns_name
zone_id = aws_lb.use1.zone_id
evaluate_target_health = true
}

latency_routing_policy {
region = "us-east-1"
}

set_identifier = "us-east-1"
health_check_id = aws_route53_health_check.alb_use1.id
}

resource "aws_route53_record" "api_usw2" {
zone_id = aws_route53_zone.main.zone_id
name = "api.atomai.click"
type = "A"

alias {
name = aws_lb.usw2.dns_name
zone_id = aws_lb.usw2.zone_id
evaluate_target_health = true
}

latency_routing_policy {
region = "us-west-2"
}

set_identifier = "us-west-2"
health_check_id = aws_route53_health_check.alb_usw2.id
}

Aurora Automatic Failover​

Aurora Global Database automatically promotes Secondary on Primary cluster failure.

Manual Failover Procedure​

Full Region Failover​

When full region failure occurs, Secondary must be manually promoted to Primary.

Detailed Procedures​

Step 1: Aurora Global Database Detach and Promotion​

#!/bin/bash
# aurora-failover.sh

# 1. Detach Secondary cluster from Global Database
aws rds remove-from-global-cluster \
--global-cluster-identifier production-aurora-global \
--db-cluster-identifier production-aurora-global-us-west-2 \
--region us-west-2

# 2. Wait for detached cluster to become standalone
aws rds wait db-cluster-available \
--db-cluster-identifier production-aurora-global-us-west-2 \
--region us-west-2

# 3. Verify new Primary cluster
aws rds describe-db-clusters \
--db-cluster-identifier production-aurora-global-us-west-2 \
--region us-west-2 \
--query 'DBClusters[0].{Status:Status,Endpoint:Endpoint}'

echo "Aurora failover completed. New primary: us-west-2"

Step 2: DocumentDB Global Cluster Promotion​

#!/bin/bash
# documentdb-failover.sh

# 1. Promote Secondary cluster to Primary
aws docdb failover-global-cluster \
--global-cluster-identifier production-docdb-global \
--target-db-cluster-identifier production-docdb-global-us-west-2 \
--region us-west-2

# 2. Wait for promotion to complete
aws docdb wait db-cluster-available \
--db-cluster-identifier production-docdb-global-us-west-2 \
--region us-west-2

echo "DocumentDB failover completed. New primary: us-west-2"

Step 3: ElastiCache Global Datastore Promotion​

#!/bin/bash
# elasticache-failover.sh

# 1. Promote us-west-2 to Primary in Global Datastore
aws elasticache failover-global-replication-group \
--global-replication-group-id production-global-datastore \
--primary-region us-west-2 \
--primary-replication-group-id production-elasticache-us-west-2

# 2. Check status
aws elasticache describe-global-replication-groups \
--global-replication-group-id production-global-datastore \
--query 'GlobalReplicationGroups[0].Members'

echo "ElastiCache failover completed. New primary: us-west-2"

Step 4: DNS and Traffic Switch​

#!/bin/bash
# dns-failover.sh

# 1. Change Route 53 record weights (us-east-1: 0, us-west-2: 100)
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "api.atomai.click",
"Type": "A",
"SetIdentifier": "us-east-1",
"Weight": 0,
"AliasTarget": {
"HostedZoneId": "Z0EXAMPLE7654321",
"DNSName": "alb-use1.us-east-1.elb.amazonaws.com",
"EvaluateTargetHealth": false
}
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "api.atomai.click",
"Type": "A",
"SetIdentifier": "us-west-2",
"Weight": 100,
"AliasTarget": {
"HostedZoneId": "Z0EXAMPLEABCDEFG",
"DNSName": "alb-usw2.us-west-2.elb.amazonaws.com",
"EvaluateTargetHealth": false
}
}
}
]
}'

echo "DNS failover completed. All traffic routed to us-west-2"

Recovery Procedure (Failback)​

Failback After Original Primary Recovery​

Failback Script​

#!/bin/bash
# failback-to-use1.sh

echo "=== Step 1: Verify us-east-1 is healthy ==="
# Check infrastructure status
aws ec2 describe-availability-zones --region us-east-1

echo "=== Step 2: Re-establish Aurora Global DB ==="
# Create new Global DB (us-west-2 is current Primary)
aws rds create-global-cluster \
--global-cluster-identifier production-aurora-global-v2 \
--source-db-cluster-identifier production-aurora-us-west-2 \
--region us-west-2

# Add Secondary cluster to us-east-1
aws rds create-db-cluster \
--db-cluster-identifier production-aurora-us-east-1-v2 \
--global-cluster-identifier production-aurora-global-v2 \
--engine aurora-postgresql \
--engine-version 15.4 \
--region us-east-1

echo "=== Step 3: Wait for sync ==="
# Wait until replication lag approaches 0
while true; do
lag=$(aws rds describe-db-clusters \
--db-cluster-identifier production-aurora-us-east-1-v2 \
--region us-east-1 \
--query 'DBClusters[0].GlobalWriteForwardingStatus' \
--output text)
if [ "$lag" == "enabled" ]; then
break
fi
sleep 10
done

echo "=== Step 4: Planned failover to us-east-1 ==="
aws rds failover-global-cluster \
--global-cluster-identifier production-aurora-global-v2 \
--target-db-cluster-identifier production-aurora-us-east-1-v2

echo "=== Step 5: Gradually shift traffic ==="
# Gradual traffic shift: 10% -> 50% -> 100%
for weight in 10 50 100; do
echo "Setting us-east-1 weight to $weight%"
# Update Route 53 weights
sleep 300 # 5 minute monitoring
done

echo "Failback completed!"

Monitoring and Alerts​

CloudWatch Alarms​

# Aurora replication lag alarm
resource "aws_cloudwatch_metric_alarm" "aurora_replication_lag" {
alarm_name = "aurora-global-replication-lag-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 3
metric_name = "AuroraGlobalDBReplicationLag"
namespace = "AWS/RDS"
period = 60
statistic = "Average"
threshold = 1000 # 1 second

dimensions = {
DBClusterIdentifier = "production-aurora-global-us-west-2"
}

alarm_actions = [aws_sns_topic.alerts.arn]
ok_actions = [aws_sns_topic.alerts.arn]

alarm_description = "Aurora Global DB replication lag exceeds 1 second"
}

# Route 53 Health Check alarm
resource "aws_cloudwatch_metric_alarm" "route53_health_use1" {
alarm_name = "route53-health-us-east-1-unhealthy"
comparison_operator = "LessThanThreshold"
evaluation_periods = 1
metric_name = "HealthCheckStatus"
namespace = "AWS/Route53"
period = 60
statistic = "Minimum"
threshold = 1

dimensions = {
HealthCheckId = aws_route53_health_check.alb_use1.id
}

alarm_actions = [aws_sns_topic.alerts.arn]

alarm_description = "us-east-1 ALB health check failing"
}

DR Dashboard​

{
"widgets": [
{
"title": "Aurora Global DB Replication Lag",
"type": "metric",
"properties": {
"metrics": [
["AWS/RDS", "AuroraGlobalDBReplicationLag", "DBClusterIdentifier", "production-aurora-global-us-west-2"]
],
"period": 60,
"stat": "Average",
"region": "us-west-2"
}
},
{
"title": "Route 53 Health Check Status",
"type": "metric",
"properties": {
"metrics": [
["AWS/Route53", "HealthCheckStatus", "HealthCheckId", "health-check-use1"],
["AWS/Route53", "HealthCheckStatus", "HealthCheckId", "health-check-usw2"]
],
"period": 60,
"stat": "Minimum"
}
},
{
"title": "Cross-Region Latency",
"type": "metric",
"properties": {
"metrics": [
["Custom/MultiRegion", "CrossRegionLatency", "SourceRegion", "us-east-1", "TargetRegion", "us-west-2"]
],
"period": 60
}
}
]
}

DR Testing​

Regular DR Drills​

Drill TypeFrequencyScopeImpact
Tabletop exerciseMonthlyProcedure reviewNone
Component failoverQuarterlyIndividual DBMinimal
Full region failoverAnnuallyFull stackPlanned downtime

Test Checklist​

  • Verify Route 53 Health Check behavior
  • Test Aurora auto-failover
  • Test DocumentDB Secondary promotion
  • Test ElastiCache Global Datastore failover
  • Verify MSK Replicator replication lag
  • Verify application connection string auto-switch
  • Verify monitoring alert delivery
  • Update runbook

Next Steps​