Lesson 5-2 explained why a database belongs in a private subnet.
Its only clients are the app servers inside the VPC, so no internet path should exist to it at all. No route from the internet means no attack path, and nothing legitimate is lost, because only in-VPC machines ever query it.
That settles where the database sits. This unit turns to what it actually runs on, and whether you should be the one running it.
You could run this yourself. Should you?
You know how to run PostgreSQL in a Docker container, so you could launch an EC2 instance and do exactly that. Now you own the 3 a.m. problems: applying security patches, taking backups and testing they restore, growing the disk before it fills, and failing over to a replica when the AZ has a bad night.
RDS (Relational Database Service) is AWS running that database for you. You pick an engine (PostgreSQL, MySQL, MariaDB, and others), an instance size (the same t3/m5 types from lesson 3-1, prefixed db.), and RDS handles:
- Automated backups: daily snapshots plus a continuous change log, so you can restore to any minute within the retention window (up to 35 days).
- Patching during a maintenance window you choose.
- Multi-AZ failover: a hot standby copy in another AZ, promoted automatically if the primary dies, usually within a minute or two.
The trade: it costs more than raw EC2 (roughly $13/month for the smallest instance versus $7.50), and you give up root access to the box. For nearly every team, that is a bargain.
Estimating billable backup storage
Backup storage is free up to the size of your database, and anything beyond that is billed. Here a 20 GB database changes 2 GB per day and keeps 7 days of backups.
db_gb=20 growth_gb_per_day=2 retention=7 backup_gb=$((db_gb + growth_gb_per_day * retention)) echo "newest backup size: ${backup_gb} GB" echo "free backup allowance: ${db_gb} GB" echo "billable backup storage: $((backup_gb - db_gb)) GB"
Output
newest backup size: 34 GB free backup allowance: 20 GB billable backup storage: 14 GB
The total is the database itself plus the accumulated change log, so 20 + 2 × 7 = 34 GB. Subtracting the free allowance leaves 14 GB billable.
Two things drive that number, and retention is the one people forget. Doubling the retention window roughly doubles the billable portion, which is why compliance requirements have a direct and often surprising line on the bill.
The same estimate for a production database
A production database of 50 GB changes 3 GB per day, and compliance requires 14 days of retention.
db_gb=50 growth_gb_per_day=3 retention=14 backup_gb=$((db_gb + growth_gb_per_day * retention)) echo "newest backup size: ${backup_gb} GB" echo "free backup allowance: ${db_gb} GB" echo "billable backup storage: $((backup_gb - db_gb)) GB"
Output
newest backup size: 92 GB free backup allowance: 50 GB billable backup storage: 42 GB
Reading the numbers
- Only the three variables at the top change: 50, 3, and 14. The formula is unchanged.
- 50 + 3 × 14 = 92 GB of backups against a 50 GB free allowance, so 42 GB is billed.
- Notice that the billable amount is now close to the size of the database itself. At long retention windows the change log dominates, and the cost of backups stops being a rounding error on the bill.
What Multi-AZ failover builds on
Multi-AZ RDS is the payoff of lesson 1-2's availability zones, with their independent failures and millisecond distance.
AZs were designed for exactly this pairing. They are close enough that the standby stays in sync in real time, since a synchronous write has to reach the second AZ before the primary confirms it, and a millisecond of extra latency is acceptable for that.
They are also separate enough that whatever killed the primary probably did not touch the standby. Independent power, cooling, and network mean a building-level failure stays a building-level failure.
RDS supplies only the automation on top: noticing the primary is gone, promoting the standby, and repointing the endpoint. The property that makes it work was already in the physical design of the region.