Home Resume
Homeβ€Ί Blogβ€Ί AWS Architecture Series #6 β€” Aurora Global Databas…
AWS Architecture AWS Architecture Series

AWS Architecture Series #6 β€” Aurora Global Database: The Multi-Region Pattern Teams Get Half Right

Business Challenge

A financial services platform processes transactions in us-east-1. The compliance team requires a documented RTO of under 5 minutes and RPO of under 1 minute for the primary database tier. The platform team sets up Aurora Global Database with a secondary cluster in eu-west-1, runs a DR drill, promotes the secondary in 47 seconds, and files the compliance report. The architecture works.

Six months later, us-east-1 suffers a real 3-hour outage. The team promotes eu-west-1 in under a minute. Transactions resume. The RTO target is met. Then the primary region recovers β€” and nobody knows what to do next. The old primary is now a standalone cluster with 3 hours of write history that diverged the moment eu-west-1 was promoted. The new primary has 3 hours of production writes on top of that. There is no automatic merge. There is no automatic rejoin. The global cluster is permanently broken until someone rebuilds it manually.

The DR plan covered failover. It did not cover failback. This is the gap that makes Aurora Global Database implementations incomplete in most enterprises.

Failover and failback are two separate runbooks

Most teams write the failover runbook and consider the job done. Failback β€” re-attaching the recovered region as a secondary, reconciling diverged data, and running a second planned switchover β€” requires its own documented procedure and must be tested before an incident forces you to improvise it.

Architecture

Aurora Global Database replicates at the storage layer, not the SQL layer. The primary region maintains a writer instance and optional local readers. Up to ten secondary regions each maintain a read-only cluster. Replication is asynchronous but fast β€” typical lag is under one second because it operates on physical redo log segments, not logical SQL statements.

Aurora Global Database multi-region topology diagram
Aurora Global Database topology β€” primary writer in us-east-1, secondary readers in eu-west-1, storage-level replication under 1s lag, Route 53 for endpoint routing

Endpoint strategy

Applications must never hard-code Aurora cluster endpoints. Instead, Route 53 aliases sit in front of the cluster endpoints. During normal operation, write.db.internal points to the primary cluster writer endpoint. During failover, you update the Route 53 record to point to the promoted secondary. Applications reconnect to the same DNS name β€” no application config change required.

Read traffic uses a separate read.db.internal record with latency-based routing. EU users are served by the eu-west-1 reader cluster; US users by the us-east-1 reader endpoint. This gives you read scalability and geographic latency reduction without any application awareness of the global topology.

Aurora Global Database planned vs unplanned failover flow diagram
Planned switchover (zero data loss) vs unplanned failover (requires detach + promote + manual failback)

Write forwarding

Aurora Global Database supports write forwarding on secondary clusters. When enabled, write statements issued against the secondary are transparently forwarded to the primary writer. This simplifies application architecture β€” a single connection string works for both reads and writes in any region β€” but adds latency to writes from the secondary region (round-trip to primary plus replication lag back). Write forwarding is appropriate for low-volume, non-latency-sensitive writes from the secondary region, not for high-throughput write paths.

Why This Architecture Works

Storage-level replication beats logical replication

Aurora replicates redo log segments, not SQL statements. This means replication lag is measured in milliseconds regardless of transaction size, and the secondary does not re-execute queries. A 10GB bulk load that takes 2 minutes in the primary is visible in the secondary within 1 second of each storage write completing.

Secondary clusters serve real read traffic

This is not a cold standby. The secondary cluster actively handles production read queries with local latency. EU users reading account balances get sub-10ms query times from eu-west-1 instead of crossing the Atlantic to us-east-1. The DR capacity is earning its keep every day.

Planned switchover has zero data loss

When you initiate a planned switchover, Aurora drains in-flight writes from the primary before promoting the secondary. The replication lag reaches zero before the role switch completes. The old primary becomes a reader. No data is lost, no reconciliation is needed, and the global cluster remains intact.

RTO under 1 minute for managed failover

For planned switchover, Aurora handles the promotion automatically and the entire operation completes in under 1 minute. For unplanned failover, detaching and promoting the secondary is a single API call that typically completes in 1–2 minutes. Compare this to multi-AZ read replica promotion, which can take 5–10 minutes.

Key Design Decisions

1 Instance sizing in the secondary region

Many teams run the secondary at a smaller instance class to save cost β€” a db.r6g.large secondary behind a db.r6g.2xlarge primary. This works until failover happens and the secondary is suddenly handling full production write throughput on an undersized instance. The secondary must match the primary's write capacity, not its read capacity.

correct approach

Size the secondary writer at the same instance class as the primary writer. You can run fewer reader instances in the secondary to reduce cost, but the promoted writer must be able to absorb peak write load immediately.

2 The failback runbook must exist before the incident

After an unplanned failover, the promoted secondary is a standalone cluster. When the original primary region recovers, it comes back as a standalone cluster with diverged data from the outage period. You cannot simply re-attach it. You must: snapshot the recovered primary, create a new Aurora cluster from the snapshot in the secondary role, attach it to the global cluster with the current promoted cluster as primary, then run a planned switchover back.

correct approach

Document and test the failback procedure as a separate runbook. Include data reconciliation steps for any writes that occurred on the old primary during the outage if the region recovered while still in an inconsistent state.

3 RDS Proxy reduces connection storm on failover

When the writer endpoint changes during failover, all application connections drop simultaneously. If the application opens connections directly to the Aurora endpoint, a few hundred application instances attempting to reconnect at the same moment can overwhelm the promoted writer before it has finished stabilising.

correct approach

Place RDS Proxy in front of the writer in each region. Proxy maintains a persistent connection pool to Aurora and presents a stable endpoint to applications. During failover, Proxy re-establishes its pool connections to the new writer without the application layer experiencing a mass reconnect storm.

4 Automate the Route 53 update, not the promotion decision

Some teams try to fully automate failover β€” CloudWatch alarm triggers Lambda which calls the promotion API and updates Route 53. This creates false-positive failover risk: a brief CloudWatch metrics gap triggers promotion unnecessarily, and now you have a broken global cluster to repair from a non-event.

correct approach

Keep the promotion decision human. Automate the Route 53 record update and notification only. An on-call engineer confirms the regional failure is real before initiating promotion. The promotion itself takes under 2 minutes β€” the decision confirmation is the only meaningful delay.

Tradeoffs

Decision Benefit Cost / Risk
Aurora Global Database vs Multi-AZ Cross-region DR, read scaling, <1s RPO 2Γ— instance cost, failback complexity
Write forwarding enabled Single connection string, simpler app logic Added write latency (cross-region round trip)
RDS Proxy in front of writer Connection pooling, cleaner failover Additional cost (~$0.015/hr per AZ), extra hop
Planned switchover for maintenance Zero data loss, global cluster stays intact Requires coordination, brief write interruption
Automated promotion on alarm Faster recovery, no human in the loop False positives cause unnecessary failover and data reconciliation work

Terraform Pattern

The key resource is aws_rds_global_cluster β€” this is the global cluster object that the primary and secondary regional clusters attach to.

HCL
# Global cluster object (region-agnostic)
resource "aws_rds_global_cluster" "main" {
  global_cluster_identifier = "platform-global"
  engine                    = "aurora-postgresql"
  engine_version            = "16.4"
  database_name             = "platform"
  storage_encrypted         = true
}

# Primary cluster β€” us-east-1
resource "aws_rds_cluster" "primary" {
  provider                  = aws.us_east_1
  cluster_identifier        = "platform-primary"
  engine                    = aws_rds_global_cluster.main.engine
  engine_version            = aws_rds_global_cluster.main.engine_version
  global_cluster_identifier = aws_rds_global_cluster.main.id
  database_name             = "platform"
  master_username           = var.db_username
  master_password           = var.db_password
  db_subnet_group_name      = aws_db_subnet_group.primary.name
  vpc_security_group_ids    = [aws_security_group.aurora_primary.id]
  kms_key_id                = aws_kms_key.aurora_primary.arn
  storage_encrypted         = true
  skip_final_snapshot       = false
  final_snapshot_identifier = "platform-primary-final"
}

resource "aws_rds_cluster_instance" "primary_writer" {
  provider             = aws.us_east_1
  identifier           = "platform-primary-writer"
  cluster_identifier   = aws_rds_cluster.primary.id
  instance_class       = "db.r6g.2xlarge"
  engine               = aws_rds_cluster.primary.engine
  engine_version       = aws_rds_cluster.primary.engine_version
  publicly_accessible  = false
}

# Secondary cluster β€” eu-west-1
resource "aws_rds_cluster" "secondary" {
  provider                  = aws.eu_west_1
  cluster_identifier        = "platform-secondary"
  engine                    = aws_rds_global_cluster.main.engine
  engine_version            = aws_rds_global_cluster.main.engine_version
  global_cluster_identifier = aws_rds_global_cluster.main.id
  db_subnet_group_name      = aws_db_subnet_group.secondary.name
  vpc_security_group_ids    = [aws_security_group.aurora_secondary.id]
  kms_key_id                = aws_kms_key.aurora_secondary.arn
  storage_encrypted         = true
  skip_final_snapshot       = false
  final_snapshot_identifier = "platform-secondary-final"

  depends_on = [aws_rds_cluster_instance.primary_writer]
}

resource "aws_rds_cluster_instance" "secondary_reader" {
  provider             = aws.eu_west_1
  identifier           = "platform-secondary-reader"
  cluster_identifier   = aws_rds_cluster.secondary.id
  instance_class       = "db.r6g.2xlarge"   # match primary writer size
  engine               = aws_rds_cluster.secondary.engine
  engine_version       = aws_rds_cluster.secondary.engine_version
  publicly_accessible  = false
}

# Route 53 write endpoint alias
resource "aws_route53_record" "db_write" {
  zone_id = var.private_zone_id
  name    = "write.db"
  type    = "CNAME"
  ttl     = 30
  records = [aws_rds_cluster.primary.endpoint]
}

Closing Thought

Aurora Global Database solves the hard part of multi-region database architecture: keeping a secondary region current enough to take over production traffic within seconds, not hours. The replication lag target of under one second is not a marketing claim β€” it reflects the architecture's use of physical storage replication rather than logical query replay.

But the architecture only delivers its promise when the team has practised the full lifecycle. Failover without a tested failback plan is a trap: the drill passes, the compliance report is filed, and the real incident reveals a gap that takes days to close. Build both runbooks, test both paths, and size the secondary to absorb writes from day one β€” not from the moment a region goes down.

Next in this series: CUR 2.0 + Athena β€” Self-Service Cost Intelligence

Most organisations look at their AWS bill once a month, after the fact. We look at how to build a self-service cost intelligence platform using Cost and Usage Report 2.0 and Athena that gives engineering teams real-time visibility into where spend is going and why.

Official AWS Reference

Amazon Aurora User Guide β€” Aurora Global Database β€” covers global cluster creation, adding secondary regions, managed planned failover (switchover), unplanned failover, write forwarding configuration, and monitoring replication lag via the AuroraGlobalDBReplicationLag CloudWatch metric.

Comments

How was your experience?
Your feedback helps improve this site.
PoorExcellent