RDS is a managed wrapper around ordinary EC2 compute and EBS storage, not a serverless abstraction - and every sizing, availability, and scaling decision you make with it inherits the operational realities of those two underlying services.
Overview
- RDS runs a real, unmodified database engine (MySQL, PostgreSQL, MariaDB, Oracle, SQL Server) on top of an actual EC2 instance and EBS volume(s), so instance class and storage type are real performance levers, not defaults to ignore.
- RDS is tuned for OLTP (many small, fast transactional operations) - pushing OLAP-style analytical queries onto the same instance competes for the same shared CPU/memory/I/O budget as live traffic.
- High availability (Multi-AZ) and read scaling (read replicas) are separate features solving separate problems; there is no configuration that is both instantly consistent and independently readable.
- Storage behavior (IOPS, throughput, autoscaling) is a direct function of the underlying EBS volume type and size, gated further by what the instance class can drive.
- Aurora is a related but architecturally distinct service with its own storage layer - it is not "RDS with extra features."
Key Concepts
DB Instance = EC2 + EBS
- One DB instance = one EC2 instance (compute) + one primary EBS volume or small set of volumes (storage), running one database engine process.
- Instance class families mirror EC2:
db.m(general-purpose, balanced),db.r/db.x(memory-optimized, large working sets/caching),db.t(burstable, dev/staging/spiky traffic). - Undersizing causes CPU credit exhaustion (burstable) or memory pressure/slow query plans; oversizing wastes budget. Resizing often requires a reboot.
- One instance can host multiple independent databases (MySQL/MariaDB) or multiple databases within an instance (PostgreSQL) - they share the same compute/storage, creating real noisy-neighbor risk if workload profiles diverge.
Multi-AZ Deployment (Availability, Not Scaling)
- Provisions a standby in a different AZ, synced via synchronous, physical-level replication.
- On primary failure, RDS updates the DNS endpoint automatically - typically ~1-2 minutes depending on engine/workload state.
- The standby is not readable. It exists purely for failover - a frequent point of confusion.
Read Replicas (Scaling, Not Availability)
- Use asynchronous, engine-native replication (e.g., binlog for MySQL/MariaDB) - fundamentally different mechanism from Multi-AZ.
- Readable, and can offload read-heavy traffic from the primary, but can lag behind it.
- Can be promoted to standalone instances (DR pattern); in supported engine/region combos, can be created cross-region.
- Naive "write then immediately read from replica" patterns will hit stale/missing data due to lag.
Storage Types and Autoscaling
gp2/gp3(General Purpose SSD): balanced cost/performance. Caveat:gp2IOPS scales with volume size - a common under-provisioning trap.io1/io2(Provisioned IOPS SSD): consistent high throughput for latency-sensitive workloads.- Storage autoscaling grows the volume automatically below a free-space threshold - removes manual disk-full incidents, but is not a substitute for capacity planning.
Credential and Encryption Hygiene
ManageMasterUserPassword=Truedelegates secrets to AWS Secrets Manager instead of passing plaintext.StorageEncrypted=TrueandDeletionProtection=Trueare cheap at creation, expensive later - encryption cannot be enabled on an existing unencrypted instance without a full snapshot-and-restore cycle.
RDS Proxy + IAM Database Authentication
- RDS Proxy pools connections between application code and the instance - critical for Lambda/serverless, where each invocation opening a direct connection can exhaust the connection limit.
- Pairing with IAM database authentication (short-lived tokens instead of static passwords) solves two problems at once: connection exhaustion and long-lived-credential risk.
Trade-offs / Caveats
- Burstable instances (
db.t) fail under sustained load: they accumulate CPU credits when idle and exhaust them under continuous traffic, falling back to baseline performance exactly when load is highest - a common "worked fine in POC, throttles in prod" story. - Multi-AZ ≠ read scaling, and read replicas ≠ automated failover. Assuming either is a widespread architectural mistake with real cost (paying for unused standby capacity, or having no real failover).
- Replication is always one trade-off or the other: synchronous-but-not-readable (Multi-AZ) or readable-but-asynchronous (replicas). No option is both instant and independently readable.
- OLAP queries against a live OLTP primary degrade transactional latency - there's no built-in query isolation on a shared instance.
- Failover testing is frequently skipped. A fast (1-2 min) Multi-AZ failover can still cause a much longer application-level outage if connection pools/drivers don't handle the DNS endpoint change or lack retry logic. RDS's
reboot-db-instancewith a force-failover option exists specifically to test this in lower environments.
Example in Practice
Provisioning a production-ready Multi-AZ PostgreSQL instance via boto3, applying the encryption/credential defaults discussed above:
response = rds.create_db_instance(
DBInstanceIdentifier="orders-service-prod",
DBInstanceClass="db.r6g.large", # memory-optimized, ARM Graviton
Engine="postgres",
EngineVersion="16.3",
MasterUsername="app_admin",
ManageMasterUserPassword=True, # secret in Secrets Manager
AllocatedStorage=100,
StorageType="gp3",
Iops=6000,
MultiAZ=True,
BackupRetentionPeriod=7,
DeletionProtection=True,
StorageEncrypted=True,
)
A Lambda function then connects through the RDS Proxy endpoint (not the instance endpoint), authenticating with an IAM-generated token rather than a static password - avoiding both connection exhaustion under concurrent invocations and long-lived credentials in the environment.
Related topics
- Amazon Aurora's distinct storage architecture (mentioned but explicitly out of scope)
- CloudWatch metrics (CPU utilization,
FreeableMemory,ReadIOPS/WriteIOPS,DiskQueueDepth) and Performance Insights for ongoing sizing decisions - CDC/ETL pipelines and dedicated data warehouses as the fix for analytical workloads that outgrow a read replica