Azure AI Search Over-provisioned
What does ZopNight detect here?
Azure AI Search services running more replica-partition units than their SLA floor are flagged when average query volume stays below 0.1 QPS over 30 days with at least 7 days of coverage and throttling under 1%. Savings equal the per-unit monthly cost times the excess units above the 1, 2, or 3-unit floor.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1396 |
| Category | rightsizing |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | search_overprovisioned.go |
Where it applies
Which search units sit above the SLA floor
- resource.UnitCount: replicas × partitions (search units). Rule skips services at the 1-unit floor (UnitCount <= 1).
- resource.Type must equal ai-search.
- availability-SLA tag zopnight:search-read-sla (ParsedTags): value-dependent scale-down floor per Azure’s documented replica requirements (searchSLATargetUnits): “read” or generic truthy (“true”/“1”/“yes”) → hold 2 units (searchReadSLAUnits, the query/read SLA); “read-write”/“readwrite” → hold 3 units (searchReadWriteSLAUnits, the index-update/read-write SLA, which requires 3+ replicas, not 2); absent/unrecognized → 1×1 floor. If UnitCount <= targetUnits there is nothing to reclaim => abstain.
- SearchQueriesPerSecond.Average: average QPS over 30 days. Fires only when present and Average < 0.1.
- SearchQueriesPerSecond.MaxCoverageDays >= 7 (MinMaxCoverageDays): guards freshly provisioned near-zero traffic.
- ThrottledSearchQueriesPercentage.Average: throttling guard; present and Average >= 1.0% => do not fire (capacity is in use).
Gates that must align before flagging
fires when all gates align: UnitCount > targetUnits (1, 2 with the read-SLA tag, or 3 with the read-write-SLA tag) AND SearchQueriesPerSecond present AND Average < 0.1 QPS AND MaxCoverageDays >= 7 AND (ThrottledSearchQueriesPercentage absent OR Average < 1.0%) AND cost > 0.Why per-unit cost is the bill split by units
Every search unit bills at the same per-search-unit-hour rate, so per-unit cost is the service’s own monthly cost split across its units: perSU = cost / UnitCount; scaling to the target floor reclaims savings = perSU × (UnitCount − targetUnits), defensively capped at cost. With UnitCount ≤ target floor or unknown cost the rule abstains (returns nil) rather than emit $0. The scale-down stays recommendation-only (Azure AI Search cannot be stopped, replica/partition scaling is slow and affects the SLA), but the dollar figure is now concrete (no fabricated fraction, no $0 advisory).
Scaling replicas and partitions back down
- Azure Portal → your Search service → Settings → Scale
- Review query volume (Monitoring → Metrics → Search Queries Per Second) and latency before changing capacity
- Reduce replicas and/or partitions (floor is 1 replica × 1 partition)
- Note: scaling is not instantaneous and 2+ replicas are required for the read SLA (3+ for read-write), so keep enough for your availability target
Query rate paired with a throttling guard
SearchQueriesPerSecond + ThrottledSearchQueriesPercentage (30d lookback each)