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