RDS Instance Right-sizing
What does ZopNight detect here?
Downsizing an RDS instance is recommended when 30-day CPU averages under the 10% threshold. ZopNight guards on FreeableMemory (abstains below a 512 MiB minimum) and on connection load near 80% of the target class's ceiling, pricing savings as the compute-rate delta times 730 hours times measured uptime, because storage never shrinks.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-030 |
| Category | rightsizing |
| Severity | high |
| Metric | none — pure configuration read |
| Source | rds_rightsizing.go |
Where it applies
The memory, idle, and connection guards
- resource.Status: statusAvailable
- MetricsAware: rdsCPUMetricName over rdsMetricLookbackDays days
- Memory guard (D3, 2026-06-26 production audit): now reads the native FreeableMemory metric (bytes), not the never-populated freeable_memory_pct tag (which made the old guard inert). Fail-closed: when the series is present and its full-window Minimum is below rdsFreeableMemoryFloorBytes (512 MiB) the DB is memory-constrained → abstain. RDS exposes free memory but not total, so the recommender uses this absolute floor (a future total-memory signal would let it gate on %-free). DatabaseConnections feeds the description and two guards: an idle-DB guard (window peak == 0 with the series present => abstain; an unused DB is a stop/decommission candidate, not a downsize) and a connection-limit guard (abstain when avg or peak ≥ 80% of the target class’s RAM-derived default max_connections ceiling, PostgreSQL/MySQL/MariaDB only; fails open for unmapped classes/engines or an absent series).
The CPU threshold and lookback window
rdsCPUThresholdPercent=10.0, rdsMetricLookbackDays=30, rdsFreeableMemoryFloorBytes=512 MiBWhy only the compute rate delta counts
the original math (RealDeltaSavings → fullCost × (1 − dst/src)) multiplied the compute-rate fraction by the full cost incl. allocated storage/backup/IOPS, line items billed independently of instance class and so unchanged by a tier downsize, overstating savings ~50–65% (audit finding). Savings is now the compute-rate delta scaled by measured uptime: (srcRate − dstRate) × 730 × uptime (uptime via UptimeForUID, fail-open to 24×7 when unknown, matching CommitmentBreakEven’s hourlyRate × 730 × uptime basis). A first cut that used (src−dst) × 730 without the uptime factor was a v1.28.1 regression: on part-time test DBs (sit2/uat/pp) whose currentCost is already uptime-discounted, the 24×7 delta overstated and even capped at full cost; caught on the 2026-06-26 fleet re-verify. The result is upper-bounded at cost × (1 − dst/src) (compute can’t exceed the resource’s own spend; also guards an anomalous SKU-rate delta and is never larger than the legacy ratio) and abstains on uptime 0 / missing rates / non-reduction. Never a fraction of full cost. PricingAware: compute-only rate delta savings = (srcRate − dstRate) × 730 × measured uptime (fail-open to 24×7 when uptime unknown), capped at cost × (1 − dst/src); abstains on missing/non-reducing SKU rates, no nameable target class, or savings ≤ 0 (rdsDownsizeSavingsFraction = 0.50 is a retained legacy const, no longer multiplied)
Downsizing during a maintenance window
- Review 30-day CloudWatch CPU, FreeableMemory, and connections metrics
- Check RDS Performance Insights for query patterns
- Modify instance → change to smaller class (e.g., db.m5.xlarge → db.m5.large)
- Apply during maintenance window
- Monitor performance for 48 hours after change
CPU, freeable memory, and connections
CPUUtilization + FreeableMemory + DatabaseConnections (all in RequiredMetrics; rdsMetricLookbackDays lookback)