Aurora Replicas vs RDS Read Replicas for Read Scaling

Problem statement: Your read traffic is outgrowing a single writer and you are scaling out replicas on AWS — but Aurora readers and RDS read replicas scale reads through fundamentally different storage models, and that difference decides your lag floor, your failover speed, and how much the writer pays for each replica you add.


Symptom Identification

You are at the point where this choice matters when you see:

  • Read CPU on the writer sustained above 70% while write CPU sits low — reads need their own capacity tier.
  • A read:write ratio north of 10:1, where even a handful of replicas materially offloads the primary.
  • Post-write reads occasionally returning stale data, forcing a decision about how tight your lag floor must be.
  • A plan to add a fifth, tenth, or fifteenth replica, where the per-replica cost to the writer starts to dominate the design.

If any of these apply, the storage model behind your replicas — shared or independent — becomes the deciding factor, not the instance class.


Root Cause Analysis

Aurora and RDS scale reads through opposite storage architectures, and every downstream difference follows from that.

Aurora replicas are compute nodes attached to the same distributed, multi-AZ storage volume as the writer. A reader never replays a WAL stream. When the writer commits, the storage layer makes the change durable across six copies in three AZs, and readers only invalidate and refresh the affected buffer-cache pages. There is no apply queue to fall behind on, which is why AuroraReplicaLag typically reads in single-digit to low-tens of milliseconds even under heavy write load. You address the whole reader tier through a single reader endpoint that load-balances across up to 15 readers, and failover to a reader completes in often under 30 seconds because the promoted node already has the storage attached.

RDS read replicas are physical streaming replicas with their own independent storage. The source ships a WAL stream to each replica, which replays it into a separate EBS volume. That independence is a feature — an RDS replica can live in another region, be a replica of a different engine version, chain as a replica-of-a-replica, and be promoted into a fully standalone writable instance. The cost is a higher lag floor (tens to low hundreds of milliseconds in steady state, more under bulk load) and a per-replica WAL-sender burden on the source.

This is the read-scaling axis of the broader managed vs self-managed read replica decision, and it interacts directly with the read-scaling trade-offs in high-traffic applications you are already navigating.


Architecture: Shared Storage vs Independent Storage

Aurora shared-storage readers versus RDS independent-storage streaming replicas The Aurora side shows a writer and two readers all attached to a single shared distributed storage volume, addressed by a reader endpoint. The RDS side shows a source instance shipping WAL streams to two replicas that each own a separate storage volume. Aurora — shared storage Writer Reader 1 Reader 2 reader endpoint balances readers Distributed storage volume 6 copies / 3 AZ · no WAL replay lag ≈ single-digit ms RDS — independent storage Source WAL stream per replica Replica 1 own EBS volume Replica 2 own EBS volume lag ≈ tens–hundreds ms · cross-region capable

Read-Scaling Scorecard

This table weighs the axes that matter specifically for scaling out reads, with representative numbers.

Axis Aurora replicas RDS read replicas
Storage model Shared distributed volume Independent EBS per replica
Typical replica lag Single-digit to ~20 ms Tens to low-hundreds ms
Max replicas 15 readers 15 (RDS Postgres); 5 default (RDS MySQL)
Read routing Reader endpoint (built-in LB) You load-balance replica endpoints
Failover to a replica Often under 30 s ~60–120 s (promotion)
Cross-region reads Aurora Global Database Native cross-region replica
Replica of a replica No (single reader tier) Yes (cascading)
Promote to standalone No (cluster-bound) Yes (independent instance)
Writer cost per added replica Minimal (shared storage) WAL sender + egress per replica
Cost dimensions Instance + storage + I/O Instance + storage per replica

The clean rule: choose Aurora when you want the lowest, most predictable lag and the simplest reader scaling inside one region, and choose RDS when you need independent-storage capabilities — cross-region physical replicas, cascading, cross-version, or the ability to promote a replica into a standalone database. For the cross-region case specifically, see cross-region read replicas on RDS.


Step-by-Step Resolution

Step 1: Provision the reader tier

bash
# Aurora: add a reader to an existing cluster (promotion-tier controls failover order)
aws rds create-db-instance \
  --db-instance-identifier appdb-aurora-reader-2 \
  --db-cluster-identifier appdb-aurora-cluster \
  --engine aurora-postgresql \
  --db-instance-class db.r6g.2xlarge \
  --promotion-tier 1

# RDS: add a streaming read replica to a source instance
aws rds create-db-instance-read-replica \
  --db-instance-identifier appdb-rds-replica-2 \
  --source-db-instance-identifier appdb-rds-primary \
  --db-instance-class db.r6g.2xlarge

Inline verification: aws rds describe-db-instances shows the new instance reaching available; on Aurora it also appears in the Aurora DB cluster’s reader list.

Step 2: Route reads to the correct endpoint

Point read traffic at the Aurora reader endpoint (which load-balances across readers automatically) or, for RDS, at a load balancer fronting the replica instance endpoints. Never hardcode individual instance endpoints — you lose the ability to add or drain replicas without a redeploy.

text
# Aurora reader endpoint — resolves across all readers
appdb-aurora-cluster.cluster-ro-xxxx.us-east-1.rds.amazonaws.com:5432

Inline verification: Repeated connections to the reader endpoint land on different reader instances (SELECT inet_server_addr(); returns varying IPs).

Step 3: Validate lag under representative load

bash
# Aurora
aws cloudwatch get-metric-statistics --namespace AWS/RDS \
  --metric-name AuroraReplicaLag \
  --dimensions Name=DBInstanceIdentifier,Value=appdb-aurora-reader-2 \
  --period 60 --statistics Maximum \
  --start-time "$(date -u -d '15 min ago' +%FT%TZ)" --end-time "$(date -u +%FT%TZ)"

Inline verification: Under load, AuroraReplicaLag should stay in the low tens of milliseconds; RDS ReplicaLag should stay within your freshness budget. If it does not, the reader instance class is undersized for the read CPU demand.


Configuration Snippet

Application-side read routing is identical regardless of which you pick — only the endpoint differs. Enforce read-only intent at the routing layer with ORM middleware for automatic query routing:

yaml
datasources:
  writer:
    url: "appdb-cluster.cluster-xxxx.us-east-1.rds.amazonaws.com:5432"
  reader:
    # Aurora reader endpoint OR RDS replica load balancer
    url: "appdb-cluster.cluster-ro-xxxx.us-east-1.rds.amazonaws.com:5432"
    read_only: true
    max_replication_lag_ms: 100   # Aurora rarely trips this; RDS may under load

Verification and Rollback

sql
-- Both platforms: confirm you are on a reader
SELECT pg_is_in_recovery();   -- t on a reader

-- Aurora: cluster-level lag view
SELECT server_id, replica_lag_in_msec
FROM aurora_replica_status();

Rollback: Reader tiers are additive and non-destructive. To back out, remove the reader from the endpoint’s rotation (drain), then delete the instance. On Aurora, deleting a reader has no effect on the shared volume or the writer; on RDS, deleting a replica stops its WAL stream and frees the source’s sender slot.


Edge Cases and Gotchas

Aurora reader endpoint balances connections, not queries

The reader endpoint distributes new connections across readers via DNS, but an established connection stays pinned to one reader. A long-lived pooled connection can concentrate load on a single reader even while the endpoint looks balanced. Recycle pooled connections periodically so the DNS rebalancing actually takes effect.

RDS replica lag spikes on bulk writes have no Aurora equivalent

Because RDS replicas replay WAL, a bulk INSERT/COPY or an un-throttled backfill on the source can push ReplicaLag into seconds while the apply worker catches up. Aurora readers do not replay, so the same bulk write barely moves AuroraReplicaLag. If your workload has bursty bulk-write phases and tight read freshness, that difference alone can decide the platform.

Failover promotion tiers only exist on Aurora

Aurora’s promotion-tier (0–15) controls which reader is promoted first on writer failure. RDS has no equivalent for read replicas — promotion is a manual or Multi-AZ-standby event. If deterministic failover ordering matters, that is an Aurora-only capability. Cross-check your promotion plan against detecting and handling replication lag in real time so you never promote a lagging node.


FAQ

Why is Aurora replica lag so much lower than RDS replica lag?

Aurora readers do not replay a WAL stream. They attach to the same distributed storage volume the writer commits to, so a reader only has to invalidate and refresh cached pages rather than apply log records. That collapses lag to single-digit to low-tens of milliseconds. RDS replicas replay a physical stream into their own independent storage, which lands in the tens-to-hundreds of milliseconds range.

Can RDS read replicas do things Aurora replicas cannot?

Yes. RDS physical replicas have independent storage, so they can be a cross-engine or cross-region replica, be promoted to a fully independent instance, and chain as a replica-of-a-replica. Aurora readers are bound to the shared Aurora storage volume and are a scaling and failover tier, not independent databases, so cross-region reads use Aurora Global Database instead.

Does adding Aurora readers slow down the writer?

Far less than adding RDS streaming replicas does. Because Aurora readers share storage, the writer does not ship a separate WAL stream to each reader, so adding readers up to the limit of 15 has minimal write-path impact. Each additional RDS streaming replica adds a WAL sender and network egress on the source.


← Back to Managed vs Self-Managed Read Replicas