# Auto-Scaling AI Infrastructure

**Last updated:** 2026-02
**Status:** GA
**Category:** Performance & Scalability

---

## Introduksjon

Auto-scaling er en fundamental kapabilitet for AI-infrastruktur i Azure, der arbeidslaster kan variere dramatisk basert pa brukertrafikk, batch-prosessering og hendelsesdrevne triggere. For norsk offentlig sektor er auto-scaling spesielt viktig fordi trafikkmonstre er svart forutsigbare (arbeidstid, sesongvariasjon) men ogsaa kan ha uforutsigbare topper (hoeringsfrister, mediadekning).

Azure tilbyr auto-scaling pa flere nivaer: fra Azure Container Apps med KEDA for mikrotjenester, via Azure Kubernetes Service for komplekse orkestreringer, til VM Scale Sets for GPU-tunge arbeidslaster. Valget avhenger av arbeidslastens natur, latenskrav og kostnadsbudsjett.

Denne referansen dekker skaleringsstrategier for AI-infrastruktur med fokus pa Azure-tjenester som er relevante for norsk offentlig sektor, inkludert metrikkvalg, cooldown-perioder, kapasitetsplanlegging og kostnadsoptimalisering gjennom intelligent skalering.

## Grunnleggende skaleringstyper

### Horisontal vs. vertikal skalering

| Aspekt | Horisontal (scale out/in) | Vertikal (scale up/down) |
|--------|--------------------------|--------------------------|
| Metode | Legge til/fjerne instanser | Endre storrelse pa instans |
| Nedetid | Ingen | Ofte nodvendig |
| Grense | Tilnaermet ubegrenset | Storste tilgjengelige VM |
| Automatisering | Fullt automatisert | Vanskelig a automatisere |
| Anbefalt for AI | Ja (foretrekkes) | Kun initiell sizing |

**Anbefaling:** Bruk horisontal skalering for alle AI-arbeidslaster. Vertikal skalering bor kun brukes for initial sizing eller der applikasjonen ikke stotter flere instanser.

### Azure-tjenester med auto-scaling

| Tjeneste | Skaleringsmekanisme | Skaler til null | Maks instanser |
|----------|---------------------|-----------------|----------------|
| Azure Container Apps | KEDA (hendelsesdrevet) | Ja | 1000 |
| Azure Kubernetes Service | HPA/KEDA + Cluster Autoscaler | Nei (min 1 node) | 5000 noder |
| Azure Functions | Innebygd auto-scale | Ja (Consumption) | 200 (Consumption) |
| Azure App Service | Azure Monitor autoscale | Nei | 30 (Standard) |
| VM Scale Sets | Azure Monitor autoscale | Nei | 1000 |

## Azure Container Apps for AI-arbeidslaster

### KEDA-basert skalering

Azure Container Apps bruker KEDA (Kubernetes Event-driven Autoscaling) for deklarativ, hendelsesdrevet skalering:

```json
{
  "properties": {
    "template": {
      "containers": [
        {
          "name": "ai-inference-service",
          "image": "myregistry.azurecr.io/ai-inference:latest",
          "resources": {
            "cpu": 2.0,
            "memory": "4Gi"
          }
        }
      ],
      "scale": {
        "minReplicas": 1,
        "maxReplicas": 50,
        "rules": [
          {
            "name": "http-scaling",
            "http": {
              "metadata": {
                "concurrentRequests": "10"
              }
            }
          },
          {
            "name": "queue-scaling",
            "custom": {
              "type": "azure-servicebus",
              "metadata": {
                "queueName": "ai-processing-queue",
                "namespace": "ddt-ai-servicebus",
                "messageCount": "5"
              }
            }
          }
        ]
      }
    }
  }
}
```

### Skaleringsoppforsel

Container Apps folger disse standardverdiene:

| Parameter | Verdi | Beskrivelse |
|-----------|-------|-------------|
| Polling interval | 30 sekunder | Hvor ofte KEDA spoerrer hendelseskilder |
| Cool down period | 300 sekunder | Ventetid for nedskalering til minimum etter siste hendelse |
| Scale up stabilization | 0 sekunder | Ingen ventetid for oppskalering |
| Scale down stabilization | 300 sekunder | Ventetid for nedskalering |
| Scale up step | 1, 4, 8, 16, 32... | Eksponentiell oppskalering |
| Scale down step | 100% | Alle unodvendige replikaer fjernes |
| Skaleringsalgoritme | `ceil(currentMetric / targetMetric)` | Beregner onskede replikaer |

### Skaleringseksempel

Med regelen `messageCount: 5` og 20 meldinger i ko:

```
desiredReplicas = ceil(20 / 5) = 4 replikaer
```

Tidslinje for oppskalering:
```
T+0s:    0 replikaer (idle)
T+30s:   KEDA oppdager 20 meldinger -> starter 1 replika
T+60s:   Fortsatt meldinger -> skalerer til 4
T+90s:   Flere meldinger -> skalerer til 8
T+120s:  Ytterligere -> skalerer til 16 (om nodvendig)
...
T+N:     Koen er tom
T+N+300s: Cool down utloper -> skalerer ned til minReplicas
```

### HTTP-basert skalering for AI API

```json
{
  "scale": {
    "minReplicas": 2,
    "maxReplicas": 100,
    "rules": [
      {
        "name": "ai-api-http",
        "http": {
          "metadata": {
            "concurrentRequests": "5"
          }
        }
      }
    ]
  }
}
```

**Viktig for AI-tjenester:** Sett `concurrentRequests` lavt (3-10) fordi AI-inferens er CPU/GPU-intensivt. Standard web-applikasjoner taler 50-100 samtidige requests, men AI-endepunkter overbelastes raskt.

### Bicep-mal for AI Container App

```bicep
resource aiService 'Microsoft.App/containerApps@2023-05-01' = {
  name: 'ai-inference-service'
  location: 'swedencentral'
  properties: {
    environmentId: containerAppEnv.id
    configuration: {
      ingress: {
        external: true
        targetPort: 8000
        transport: 'http'
      }
    }
    template: {
      containers: [
        {
          name: 'inference'
          image: '${acrName}.azurecr.io/ai-inference:latest'
          resources: {
            cpu: json('2.0')
            memory: '4Gi'
          }
          probes: [
            {
              type: 'Readiness'
              httpGet: {
                path: '/health'
                port: 8000
              }
              initialDelaySeconds: 10
              periodSeconds: 5
            }
          ]
        }
      ]
      scale: {
        minReplicas: 2  // Alltid minst 2 for HA
        maxReplicas: 50
        rules: [
          {
            name: 'http-rule'
            http: {
              metadata: {
                concurrentRequests: '8'
              }
            }
          }
        ]
      }
    }
  }
}
```

## Skaleringsmetrikker og triggere

### Valg av riktige metrikker

| Metrikk | Best for | Fordeler | Ulemper |
|---------|---------|----------|---------|
| HTTP concurrent requests | API-endepunkter | Direkte relatert til last | Skalerer ikke for bakgrunnsoppgaver |
| Ko-lengde (Service Bus) | Asynkron prosessering | Presist for batch | Kan ikke fange CPU-belastning |
| CPU-bruk | Generelt | Universelt | Reaktivt, ikke proaktivt |
| Minne-bruk | ML-modeller | Fanger OOM-risiko | Sent signal |
| Tilpasset metrikk | Spesifikke behov | Presist for brukstilfelle | Krever instrumentering |

### Hendelsesdrevne triggere for AI

```json
{
  "scale": {
    "minReplicas": 0,
    "maxReplicas": 100,
    "rules": [
      {
        "name": "servicebus-trigger",
        "custom": {
          "type": "azure-servicebus",
          "metadata": {
            "queueName": "document-analysis",
            "namespace": "ddt-ai-bus",
            "messageCount": "3"
          },
          "auth": [
            {
              "secretRef": "servicebus-connection",
              "triggerParameter": "connection"
            }
          ]
        }
      },
      {
        "name": "storage-queue-trigger",
        "custom": {
          "type": "azure-queue",
          "metadata": {
            "queueName": "image-processing",
            "accountName": "svvaistorage",
            "queueLength": "5"
          }
        }
      }
    ]
  }
}
```

### Azure Monitor Autoscale for VM Scale Sets

For GPU-baserte AI-arbeidslaster pa VM Scale Sets:

```json
{
  "properties": {
    "profiles": [
      {
        "name": "AI-Inference-Profile",
        "capacity": {
          "minimum": "2",
          "maximum": "20",
          "default": "2"
        },
        "rules": [
          {
            "metricTrigger": {
              "metricName": "Percentage CPU",
              "metricResourceUri": "/subscriptions/.../vmScaleSets/ai-gpu-cluster",
              "timeGrain": "PT1M",
              "statistic": "Average",
              "timeWindow": "PT5M",
              "timeAggregation": "Average",
              "operator": "GreaterThan",
              "threshold": 70
            },
            "scaleAction": {
              "direction": "Increase",
              "type": "ChangeCount",
              "value": "2",
              "cooldown": "PT5M"
            }
          },
          {
            "metricTrigger": {
              "metricName": "Percentage CPU",
              "metricResourceUri": "/subscriptions/.../vmScaleSets/ai-gpu-cluster",
              "timeGrain": "PT1M",
              "statistic": "Average",
              "timeWindow": "PT10M",
              "timeAggregation": "Average",
              "operator": "LessThan",
              "threshold": 30
            },
            "scaleAction": {
              "direction": "Decrease",
              "type": "ChangeCount",
              "value": "1",
              "cooldown": "PT10M"
            }
          }
        ]
      }
    ]
  }
}
```

## Cooldown-perioder og stabilisering

### Forstaa cooldown

Cooldown-perioder forhindrer "flapping" (rask opp- og nedskalering):

| Scenario | Anbefalt cooldown | Begrunnelse |
|----------|-------------------|-------------|
| AI-chatbot API | 3-5 min oppskalering, 10 min nedskalering | Rask respons pa trafikk, langsom nedtrapping |
| Batch-prosessering | 1 min oppskalering, 5 min nedskalering | Rask oppskalering for koproseering |
| GPU-inferens | 5-10 min oppskalering, 15-30 min nedskalering | VM-oppstart tar tid |
| RAG-pipeline | 3 min oppskalering, 10 min nedskalering | Balanse mellom respons og kostnad |

### Tidsbasert skalering (schedule)

For forutsigbare trafikkmonstre i offentlig sektor:

```json
{
  "profiles": [
    {
      "name": "Arbeidstid",
      "capacity": {
        "minimum": "5",
        "maximum": "50",
        "default": "10"
      },
      "recurrence": {
        "frequency": "Week",
        "schedule": {
          "timeZone": "W. Europe Standard Time",
          "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
          "hours": [7],
          "minutes": [0]
        }
      }
    },
    {
      "name": "Kveld-og-helg",
      "capacity": {
        "minimum": "1",
        "maximum": "10",
        "default": "2"
      },
      "recurrence": {
        "frequency": "Week",
        "schedule": {
          "timeZone": "W. Europe Standard Time",
          "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
          "hours": [17],
          "minutes": [0]
        }
      }
    }
  ]
}
```

### Kombinert tidsbasert + reaktiv skalering

Den mest effektive strategien kombinerer begge:

```
Arbeidstid (07-17):
  Baseline: 10 instanser (schedule)
  Reaktiv: Skaler til 50 ved CPU > 70% (auto)

Kveld (17-07):
  Baseline: 2 instanser (schedule)
  Reaktiv: Skaler til 10 ved CPU > 70% (auto)

Spesielle perioder (hoeringsfrister, arsoppgjor):
  Baseline: 20 instanser (manuelt justert schedule)
  Reaktiv: Skaler til 100 ved behov (auto)
```

## Kapasitetsplanlegging

### Dimensjonering av AI-arbeidslaster

For a dimensjonere riktig, kartlegg disse parameterne:

| Parameter | Metode | Eksempel |
|-----------|--------|---------|
| Gjennomsnittlig requests/sek | Historisk data, Azure Monitor | 50 req/s i arbeidstid |
| Topp-requests/sek | P99 fra historisk data | 200 req/s (4x gjennomsnitt) |
| Request-varighet | Application Insights | 2-5 sek per AI-kall |
| Concurrent users | Estimat basert pa ansatte/innbyggere | 500 samtidige |
| Token throughput | Azure OpenAI-metrikker | 100K TPM |

### Kapasitetsformel

```
Nodvendige instanser = ceil(
    (topp_requests_per_sekund * gjennomsnittlig_request_tid) /
    concurrent_capacity_per_instans
)

Eksempel:
  200 req/s * 3 sek = 600 samtidige requests
  Hver instans handterer 10 samtidige = 60 instanser
  + 20% buffer = 72 instanser (maks)
  Baseline: 20 instanser (gjennomsnittlig last)
```

### Azure Load Testing for AI-endepunkter

```yaml
# Azure Load Testing konfigurasjon
version: v0.1
testId: ai-endpoint-load-test
testPlan: ai-load-test.jmx
engineInstances: 5
configuration:
  env:
    - name: ENDPOINT_URL
      value: https://ai-service.swedencentral.azurecontainerapps.io
    - name: CONCURRENT_USERS
      value: "100"
    - name: RAMP_UP_SECONDS
      value: "60"
    - name: TEST_DURATION_SECONDS
      value: "300"
failureCriteria:
  - avg(response_time_ms) > 5000
  - percentage(error) > 5
  - p99(response_time_ms) > 15000
```

## Kostnadsoptimalisering gjennom skalering

### Strategier for kostnadskontroll

| Strategi | Beskrivelse | Besparelse |
|----------|-------------|-----------|
| Scale to zero | Sett minReplicas=0 for ikke-kritiske tjenester | 100% i tomgangstid |
| Spot/Preemptible VMs | Bruk for batch-prosessering og trening | 60-90% |
| Reserved Instances | 1- eller 3-ars commitment for baseline | 30-60% |
| Scheduling | Reduser kapasitet utenfor arbeidstid | 40-60% |
| Right-sizing | Bruk minste nodvendige VM-storrelse | 20-40% |
| GPU-deling | Dele GPU mellom flere tjenester | 50-70% |

### Container Apps kostnadskontroll

```json
{
  "scale": {
    "minReplicas": 0,
    "maxReplicas": 20,
    "rules": [
      {
        "name": "cost-optimized-http",
        "http": {
          "metadata": {
            "concurrentRequests": "15"
          }
        }
      }
    ]
  }
}
```

**Faktureringsregler for Container Apps:**
- **0 replikaer:** Ingen fakturering
- **Idle replikaer (i minne, ingen prosessering):** Lavere "idle"-sats
- **Aktive replikaer:** Full fakturering

### Azure Savings Plans

For forutsigbar baseline-bruk:

```
Eksempel: AI-tjeneste med 10 instanser baseline
- Pay-as-you-go: 10 * $0.50/time = $120/dag
- 1-ars Savings Plan: 10 * $0.35/time = $84/dag (30% besparelse)
- 3-ars Savings Plan: 10 * $0.25/time = $60/dag (50% besparelse)
```

## Azure OpenAI-spesifikk skalering

### PTU vs. Standard for variabel last

For Azure OpenAI er skaleringsmodellen annerledes enn tradisjonell infrastruktur:

| Lastprofil | Anbefalt deployment | Begrunnelse |
|-----------|-------------------|-------------|
| Stabil, forutsigbar | PTU (100% baseline) | Lavest kostnad og latens |
| Variabel med kjent baseline | PTU + Standard spillover | PTU for baseline, Standard for topper |
| Svart variabel | Standard | Betal kun for bruk |
| Batch-prosessering | Global Batch | 50% rabatt, separat kvote |

### Smart load balancing med prioriteter

```python
# Arkitektur: PTU som primar, Standard som fallback
BACKENDS = [
    {
        "name": "ptu-sweden",
        "url": "https://aoai-ptu-sweden.openai.azure.com/",
        "priority": 1,  # Forst: Bruk PTU-kapasitet
        "type": "ptu"
    },
    {
        "name": "standard-sweden",
        "url": "https://aoai-std-sweden.openai.azure.com/",
        "priority": 2,  # Fallback: Standard i samme region
        "type": "standard"
    },
    {
        "name": "standard-northeurope",
        "url": "https://aoai-std-ne.openai.azure.com/",
        "priority": 3,  # Siste utvei: Annen region
        "type": "standard"
    }
]
```

## Overvaking av skalering

### Viktige metrikker

| Metrikk | Kilde | Terskel |
|---------|-------|---------|
| Replica count | Container Apps metrics | Varsle ved >80% av maks |
| CPU utilization per replica | Container Apps metrics | Varsle ved >80% |
| Request queue length | Service Bus metrics | Varsle ved >100 meldinger |
| Scale events | Activity Log | Spoer frekvens |
| Failed scale operations | Activity Log | Varsle umiddelbart |
| Cost per day | Cost Management | Varsle ved budsjettgrense |

### KQL for skaleringsanalyse

```kusto
// Analyse av skaleringsaktivitet
ContainerAppSystemLogs
| where RevisionName contains "ai-inference"
| where Log contains "Scaling"
| summarize
    scale_up_events = countif(Log contains "scaling up"),
    scale_down_events = countif(Log contains "scaling down"),
    max_replicas = max(toint(extract("replicas=(\\d+)", 1, Log)))
    by bin(TimeGenerated, 1h)
| order by TimeGenerated desc
```

## Sjekkliste for auto-scaling

| Nr | Tiltak | Prioritet |
|----|--------|-----------|
| 1 | Definer SLA/SLO for responstid | Kritisk |
| 2 | Velg riktig skaleringsmetrikk for arbeidslast | Kritisk |
| 3 | Sett fornuftig minReplicas (0 for ikke-kritisk, 2+ for HA) | Hoy |
| 4 | Konfigurer cooldown-perioder for a unnga flapping | Hoy |
| 5 | Implementer tidsbasert skalering for kjente monstre | Medium |
| 6 | Last-test for a validere skaleringsparametere | Medium |
| 7 | Sett opp kostnadsalarmer for a fange runaway-skalering | Medium |
| 8 | Bruk readiness probes for a sikre healthy instanser | Medium |
| 9 | Implementer graceful shutdown for lange AI-operasjoner | Medium |
| 10 | Dokumenter skaleringslogikk i ADR | Anbefalt |

## For Cosmo

- **Horisontal skalering er standard** for AI-arbeidslaster. Azure Container Apps med KEDA er forstevalgdet for mikrotjenester og API-lag. VM Scale Sets for GPU-tunge arbeidslaster.
- **Kombinert schedule + reaktiv skalering** gir best resultat for offentlig sektor: forutsigbar baseline i arbeidstid, lav kapasitet pa kveld/helg, med reaktiv oppskalering for uforutsette topper.
- **Scale to zero reduserer kostnader dramatisk** for utviklings- og testmiljoer. I produksjon, hold minimum 2 replikaer for hoy tilgjengelighet.
- **AI-endepunkter krever lavere concurrency-terskel** enn vanlige web-APIer. Sett concurrentRequests til 3-10, ikke 50-100 som for tradisjonelle tjenester.
- **PTU + Standard spillover** er den mest kostnadseffektive arkitekturen for Azure OpenAI med variabel last. PTU for baseline, Standard for topper, Global Batch for asynkron prosessering.
