Azure Cosmos DB Provisioned Throughput Rightsizing
What does ZopNight detect here?
Cosmos DB accounts on manual provisioned throughput are right-sized when normalized RU consumption averages under 10% across 30 days. Target RU/s adds 20% burst headroom over the derived peak, snaps to the 100-RU grid, and floors at 400; savings scale linearly with the RU reduction. Autoscale accounts are skipped.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-247 |
| Category | rightsizing |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | cosmos_throughput.go |
Where it applies
Manual-throughput accounts under 10% normalized RU
- MetricsAware: name-keyed CosmosNormalizedRU series (read via uid:CosmosNormalizedRU, not bare-UID, since cosmosdb harvests ~10 metrics). Fires when windowed avg < 10%. CosmosTotalRequests corroborates in the evidence panel.
- metadata: provisioned_ru (provider-authoritative current RU/s, stamped by the discoverer’s applyCosmosLookupSets). Absent → abstain (producer gap).
- metadata: cosmos_throughput_mode (manual | autoscale), co-stamped with provisioned_ru from the same throughputSettings rows (fetchCosmosThroughput, one ARG query). The rule fires only when mode == manual, and abstains on autoscale and on an absent/unknown mode (fail-closed). See the manual-vs-autoscale note below.
- peakRU is derived: NormalizedRU is a percent-of-provisioned series, so peakRU = currRU × m.Maximum/100, gated on HasSufficientMaxCoverage (≥7d true-max) so a smoothed peak can’t under-size and risk throttling. (NormalizedRU is the max across partition key ranges, so under partition skew this over-estimates aggregate peak, a safe and conservative direction that errs toward abstaining.)
- suggestSmallerCosmosRU(currRU, peakRU) sizes the target (peak + 20% burst, snapped to the 100-RU grid, floored at 400); refuses (→ abstain) when no safe smaller RU exists.
Why RU cuts translate linearly into dollars
The ratio is the real RU reduction: Cosmos bills linearly per 100 RU/s, so SavingsUSD = cost × (currRU − targetRU)/currRU. The hardcoded azureRightsizingSavingsFraction was removed from both paths; this cost-driven rightsizing rec abstains (returns nil) whenever the saving cannot be quantified (no metric, no provisioned_ru, non-manual/unknown throughput mode, insufficient max coverage, or no safe smaller RU). There is no $0 advisory and no fabricated fraction (2026-06-27).
Checking RU consumption before resizing
- Review RU consumption metrics in Azure Monitor (Normalized RU Consumption)
Normalized RU with total requests alongside
CosmosNormalizedRU + CosmosTotalRequests (30d)