Filter concepts by levelShowing all levels.

AWS · Section 22

Databases — RDS

Level
intermediate
Read
25 min
Concepts
4

RDS runs a managed relational database — AWS handles patching, backups, and failure detection/recovery, while query tuning and schema design remain the customer's responsibility. This section covers that core vocabulary (including the automated-backup-vs-manual-snapshot distinction), the genuine difference between Multi-AZ (availability, and only a DB cluster deployment's standbys serve reads) and read replicas (read scaling, not an automatic failover target), diagnosing connection exhaustion versus slow queries, and designing applications to reconnect and retry cleanly through a DNS-based failover.

What is true here

  1. Automated backups give continuous point-in-time recovery within a retention window; a manual snapshot is a deliberate, independently-retained copy — take one before risky changes.
  2. A single-standby Multi-AZ deployment provides availability only and never serves reads; read replicas provide read scaling and are not automatically promoted on failure.
  3. Connection exhaustion (needs pooling) and slow queries (need indexing/tuning) are different problems — Performance Insights helps diagnose the latter.
  4. Failover re-points the DB endpoint's DNS to a new IP — applications must reconnect via hostname and retry with backoff, never cache the IP.

What you will be able to do

  • Explain the RDS vocabulary and take a manual snapshot before a risky operation
  • Choose correctly between Multi-AZ and read replicas for a given availability or scaling requirement
  • Diagnose whether a database performance problem is connection exhaustion or a slow query
  • Design application connection logic that survives a Multi-AZ failover without manual intervention
From the RDS vocabulary to a failover-aware application
extended byoperated viainforms

Engine, instance class, backups

Multi-AZ vs read replicas

Connections, pooling, Performance Insights

Reconnect + retry on failover

  • Engine, instance class, backups
    • leads to Multi-AZ vs read replicas (extended by)
  • Multi-AZ vs read replicas
    • leads to Connections, pooling, Performance Insights (operated via)
  • Connections, pooling, Performance Insights
    • leads to Reconnect + retry on failover (informs)
  • Reconnect + retry on failover

Databases — RDS

The core RDS vocabulary, Multi-AZ vs read replicas, connections/pooling/monitoring, and failover-aware application design.

RDS Core Vocabulary

coreintermediate

RDS runs a managed relational database (MySQL, PostgreSQL, MariaDB, SQL Server, Oracle, Db2) — AWS handles patching, backups, and failure detection/recovery, while you own query tuning and schema design. A DB instance class sets compute/memory; storage is separate, EBS-backed. Automated backups happen continuously (point-in-time recovery); a snapshot is a manually-triggered, durable point-in-time copy you control the lifecycle of.

Think of it as

RDS is a serviced apartment for your database — AWS handles the building maintenance (patching, backups, failure detection), you still decide how to arrange the furniture (schema, queries, indexes). An automated backup is the building's continuous security-camera footage (rolling window, point-in-time recovery); a snapshot is a photo you deliberately took and kept.

What we're doing: See the difference between relying on automated backups and taking a manual snapshot before a risky change.

backup-vs-snapshot.shbash
# Automated backups: already running, retained for the configured window (e.g. 7 days)
aws rds create-db-snapshot --db-instance-identifier prod-db --db-snapshot-identifier pre-migration-snapshot
1
Automated backups exist continuously in the background once enabled — nothing needs to be triggered for ordinary point-in-time recovery within the retention window.
2
A manual snapshot is explicitly triggered right before a risky operation (like a schema migration), and persists independently of the automated backup retention window until deliberately deleted.

Why this works: Automated backups protect against "restore to any point in the last N days," while a manual snapshot protects a specific, deliberate moment in time that you may want to keep far longer than the automated retention window allows.

Assuming automated backups alone cover a risky migration

Wrong

text
# "We have automated backups enabled, so we don't need to do anything
# special before this schema migration."

Better

text
# Take an explicit manual snapshot immediately before the migration —
# a known-good, independently-retained restore point

What you see: A failed migration needs to be rolled back, but the automated backup retention window has already rotated past the pre-migration state by the time the problem is discovered days later.

Why: Automated backups are bounded by a retention window and rotate over time — a manual snapshot taken at a specific known-good moment persists independently of that window, which is exactly the guarantee a risky, deliberate change needs.

What RDS manages vs what stays yours

Your responsibility

query tuning, schema design, indexes

DB instance

engine + instance class + storage

AWS-managed

patching, backups, failure detection/recovery

  1. Your responsibility — query tuning, schema design, indexes
  2. DB instance — engine + instance class + storage
  3. AWS-managed — patching, backups, failure detection/recovery

Remember: RDS manages patching, backups, and failure detection/recovery; query tuning and schema design stay yours. Automated backups give continuous point-in-time recovery within a retention window; a manual snapshot is a deliberately-triggered, independently-retained point-in-time copy — take one before risky changes.

See also: multi az vs read replicas · postgresql as rdbms

Multi-AZ vs Read Replicas

coreintermediate

Multi-AZ is for availability — a synchronous standby RDS automatically fails over to. Read replicas are for read scaling — asynchronous copies you query directly to offload read traffic. A Multi-AZ **DB instance** deployment (one standby) does NOT serve reads at all; a Multi-AZ **DB cluster** deployment (two standbys, a newer option) can serve reads from its readers.

Think of it as

Multi-AZ is a synchronized backup driver sitting in the passenger seat, ready to take the wheel instantly if the primary driver has a problem — not there to help carry extra passengers day to day. A read replica is a second, independent car following the same route, genuinely available to carry its own passengers (read queries) the whole time.

What we're doing: See why adding Multi-AZ to a read-heavy workload does not reduce load on the primary.

multi-az-misconception.txttext
Read-heavy app, primary DB instance CPU consistently at 85%
Team enables Multi-AZ (single-standby) expecting read load to spread
→ CPU on the primary stays at 85% — the standby never serves any reads at all
1
The actual bottleneck is read query volume against a single instance.
3
A Multi-AZ DB instance standby is purely a synchronous failover target — it never serves application traffic, so this change does nothing for the CPU problem it was meant to fix.

Why this works: Multi-AZ (single standby) and read replicas solve genuinely different problems — conflating them is a common, costly mistake, since enabling Multi-AZ for a read-scaling problem adds cost and complexity while leaving the actual bottleneck untouched.

Enabling Multi-AZ (single standby) to solve a read-scaling problem

Wrong

text
# "Our database is under heavy read load — let's turn on Multi-AZ."

Better

text
# Add one or more read replicas to actually offload read traffic —
# Multi-AZ (single-standby) solves availability, not read capacity

What you see: Read latency and CPU utilization on the primary stay unchanged after enabling Multi-AZ, because the new standby was never in the query path to begin with.

Why: A single-standby Multi-AZ deployment exists purely to provide a synchronous failover target for availability — it is not a query target for the application, so it cannot relieve read load no matter how the workload is shaped.

Multi-AZ DB instance vs read replica

Multi-AZ (single standby)

  • +Synchronous replication
  • +Automatic failover target
  • +Standby does NOT serve reads
  • +Purpose: availability

Read replica

  • Asynchronous replication
  • Not an automatic failover target
  • Serves read queries directly
  • Purpose: read scaling
  • Multi-AZ (single standby)
    • Synchronous replication
    • Automatic failover target
    • Standby does NOT serve reads
    • Purpose: availability
  • Read replica
    • Asynchronous replication
    • Not an automatic failover target
    • Serves read queries directly
    • Purpose: read scaling

Remember: Multi-AZ (single standby) = availability only, standby never serves reads. Multi-AZ DB cluster (two standbys, newer) CAN serve reads. Read replicas = read scaling via asynchronous copies, not an automatic failover target — promotion is a separate action.

See also: rds core vocabulary · resilience vocabulary

Connections, Pooling, and Database Monitoring

standardintermediate

A DB instance has a hard connection limit tied to its instance class — an app opening a new connection per request (rather than pooling) can exhaust it under load, unrelated to any query performance problem. RDS Performance Insights and Enhanced Monitoring surface slow queries and OS-level metrics AWS does not expose by default; query tuning and index design remain the customer's job.

Think of it as

Connection limits are the number of phone lines a call center has installed — no amount of skill on individual calls prevents a busy signal if too many lines are simultaneously held open. Pooling is putting callers on a shared queue of a fixed set of lines instead of trying to add a new line per caller.

text
Connection exhaustion: too many open connections, unrelated to query speed
Slow query: query itself is expensive — needs an index/rewrite, not more connections

What we're doing: Distinguish a connection-exhaustion failure from a slow-query failure by their symptoms.

symptom-comparison.txttext
Symptom: "too many connections" errors under load, individual queries are fast
→ Connection exhaustion — add a connection pooler, not an index

Symptom: connections available, but requests hang and CPU is high on a specific query
→ Slow query — use Performance Insights to find it, then index/rewrite it
1
A "too many connections" error is a capacity/pooling problem — individual queries being fast rules out query performance as the cause.
3
High CPU concentrated on a specific query, with connections still available, points at query performance — the fix here is indexing or rewriting the query, not adding more connections.

Why this works: These two failure modes have genuinely different root causes and fixes — treating a connection-exhaustion problem with query tuning (or a slow-query problem by raising connection limits) wastes effort without addressing the actual bottleneck.

Raising the connection limit to fix an application that never pools connections

Wrong

text
# Increase max_connections repeatedly as traffic grows, without ever
# adding connection pooling to the application

Better

text
# Add a connection pooler (e.g. RDS Proxy, PgBouncer) so the app reuses
# a bounded connection set instead of scaling connections linearly with traffic

What you see: Connection limits keep needing to be raised as traffic grows, memory pressure on the instance increases, and the underlying problem (one connection opened per request) never actually goes away.

Why: Raising the connection limit treats the symptom, not the cause — an application that opens a new connection per request will keep needing more connections indefinitely as traffic grows, while pooling caps connection count independent of request volume.

Remember: Connection exhaustion (too many open connections) and slow queries (an expensive query itself) are different problems with different fixes — pooling for the former, indexing/query tuning (informed by Performance Insights) for the latter. RDS manages the infrastructure; query tuning stays the customer's job.

See also: rds core vocabulary · failover and maintenance design

Designing for Failover and Maintenance

standardintermediate

A Multi-AZ failover (automatic or maintenance-triggered) changes which endpoint IP the DB instance's DNS name resolves to — the application must reconnect rather than hold a single cached connection or IP forever. A maintenance window is when RDS applies patches that may require a brief outage or failover; scheduling it deliberately, and retrying transient connection failures, is what keeps it a non-event.

Think of it as

The RDS endpoint hostname is a phone number that gets silently rerouted to a new office during failover — an application that memorized the old office's street address instead of redialing the number will keep knocking on an empty building.

text
Application: use the DB endpoint hostname, retry transient connection errors with backoff — never cache the resolved IP indefinitely

What we're doing: See why caching a database's resolved IP address breaks failover recovery.

dns-caching-failure.txttext
App resolves prod-db.xxxxx.rds.amazonaws.com once at startup, caches the IP forever
Multi-AZ failover occurs — DNS now points the same hostname at the new primary's IP
→ App keeps connecting to the OLD IP, which may now be unreachable or stale
1
The application resolved the hostname once and never looked it up again for the lifetime of the process.
3
The failover changed what the hostname resolves to, but the app never re-resolves it — leaving it connected to (or repeatedly failing against) an address that is no longer the live primary.

Why this works: RDS deliberately makes failover work through DNS re-pointing rather than IP preservation — an application that bypasses DNS by caching the IP defeats the exact mechanism failover relies on to redirect traffic to the new primary.

No retry/backoff logic around database connections, treating any failure as fatal

Wrong

python
conn = db.connect(host=DB_HOST)  # fails once during failover, app crashes/exits

Better

python
for attempt in range(5):
    try:
        conn = db.connect(host=DB_HOST)
        break
    except ConnectionError:
        time.sleep(2 ** attempt)  # backoff, then retry — DNS has likely repointed by now

What you see: A routine, planned maintenance-window failover (typically seconds to low tens of seconds) causes a full application outage or crash loop instead of a brief, transparent blip.

Why: RDS failover is designed to be brief precisely so that a well-behaved application with retry/backoff logic experiences a short connection interruption rather than a hard failure — an application with no retry logic turns an expected, bounded event into an unnecessary outage.

Remember: Failover repoints the DB endpoint's DNS to a new IP — never cache that IP indefinitely. Retry transient connection failures with backoff so a brief, expected failover (or maintenance-window patch) stays invisible to users instead of becoming an outage.

See also: multi az vs read replicas · rds core vocabulary

Advertisement