feat(ms-ai-architect): add plugin to open marketplace (v1.5.0 baseline)

Initial addition of ms-ai-architect plugin to the open-source marketplace.
Private content excluded: orchestrator/ (Linear tooling), docs/utredning/
(client investigation), generated test reports and PDF export script.
skill-gen tooling moved from orchestrator/ to scripts/skill-gen/.

Security scan: WARNING (risk 20/100) — no secrets, no injection found.
False positive fixed: added gitleaks:allow to Python variable reference
in output-validation-grounding-verification.md line 109.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-07 17:17:17 +02:00
commit 6a7632146e
490 changed files with 213249 additions and 2 deletions

View file

@ -0,0 +1,498 @@
# AI Foundry Disaster Recovery Planning
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Azure AI Foundry (tidligere Azure AI Studio / Azure Machine Learning) er Microsofts sentrale plattform for utvikling, evaluering og deployering av AI-modeller og agenter. Plattformen tilbyr imidlertid ikke automatisk failover eller disaster recovery ut av boksen -- dette er eksplisitt dokumentert av Microsoft. Det betyr at organisasjoner i norsk offentlig sektor som bygger forretningskritiske AI-loesninger pa AI Foundry, ma planlegge og implementere sin egen DR-strategi.
Disaster recovery for AI Foundry-prosjekter er mer kompleks enn for tradisjonelle webapplikasjoner. Et AI-prosjekt bestar av mange sammenkoblede komponenter: modelldeployeringer, datasett, pipeline-konfigurasjoner, agentdefinisjoner, tilkoblinger til eksterne tjenester, og tilhoerende infrastruktur som Azure Cosmos DB, Azure AI Search og Azure Storage. Tap av en enkelt komponent kan gjore hele AI-loesningen uoperativ. Saerlig for Foundry Agent Service er tilstandsdata (samtalehistorikk, agent-definisjoner, trad-kontekst) fordelt pa tvers av flere lagringstjenester, og det finnes per i dag ingen innebygd en-klikks eksport/import-funksjon for komplett gjenoppretting.
Denne referansen dekker prosjektdata-backup og replikering, modellversjonskontroll og gjenoppretting, configuration as code for reproduserbarhet, RTO/RPO-definisjoner for AI-prosjekter, og testing og validering av DR-prosedyrer. Alt er forankret i Microsofts offisielle veiledning for high availability og disaster recovery for AI Foundry.
## Prosjektdata-backup og replikering
### Komponentoversikt for AI Foundry-prosjekter
| Komponent | Lagringssted | Backup-ansvar | Replikeringsmetode |
|-----------|-------------|---------------|---------------------|
| Prosjektkonfigurasjon | AI Foundry control plane | Kunde (IaC) | Bicep/Terraform redeploy |
| Modelldeployeringer | Azure OpenAI / AI Foundry | Kunde (IaC) | Redeploy fra kildekontroll |
| Agentdefinisjoner | Cosmos DB (Standard mode) | Kunde | Cosmos DB continuous backup |
| Samtalehistorikk (traader) | Cosmos DB (`enterprise_memory`) | Kunde | Cosmos DB PITR |
| Kunnskapsfiler (agent) | Azure Storage | Kunde | GRS/GZRS replikering |
| Soekeindekser (agent) | Azure AI Search | Kunde | Manuell gjenskapning |
| Datasett og artefakter | Azure Storage (prosjekt) | Kunde | GRS/GZRS replikering |
| Notebook-filer og kode | Azure Storage | Kunde | Git + Azure Storage |
| Tilkoblinger og secrets | Azure Key Vault | Microsoft | Auto-failover til sekundaer region |
| Container images | Azure Container Registry | Microsoft* | Geo-replikering (konfigurer) |
| Application Insights | Log Analytics workspace | Kunde | Opprett i begge regioner |
> *Azure Container Registry ma konfigureres for geo-replikering av kunden, men Microsoft haandterer selve replikeringsmekanismen.
### Ressurskonfigurering for gjenoppretting
Microsoft anbefaler foelgende konfigurasjon **foer** en hendelse inntreffer:
```
+------------------------------------------------------------------+
| Ressurs | Anbefalt konfigurasjon |
+------------------------------------------------------------------+
| Foundry account | Purview-integrasjon for compliance |
| Foundry project | User-assigned managed identity |
| Agent Service | Standard deployment mode |
| Cosmos DB | Continuous backup med PITR |
| | Service-managed failover |
| | Read replication til failover-reg. |
| AI Search | Unikt navn (unnga kollisjon) |
| Storage account | GZRS (geo-zone-redundant) |
+------------------------------------------------------------------+
```
### Cosmos DB-konfigurasjon for agentdata
Cosmos DB er kritisk for Foundry Agent Service da all agent-tilstand lagres her:
```bash
# Aktiver continuous backup med 30-dagers PITR
az cosmosdb create \
--name svv-ai-cosmos-prod \
--resource-group rg-ai-foundry-prod \
--locations regionName="norwayeast" failoverPriority=0 \
--locations regionName="swedencentral" failoverPriority=1 \
--backup-policy-type Continuous \
--continuous-tier Continuous30Days \
--enable-automatic-failover true \
--default-consistency-level Session
```
> **Viktig:** Aktiver `Service-Managed Failover` slik at Cosmos DB automatisk kan bytte skriveregion fra primaerregion til sekundaerregion ved et langvarig regionalt utfall.
### Azure Storage-konfigurasjon
```bash
# Opprett GZRS storage account for prosjektdata
az storage account create \
--name svvaiprodstorage \
--resource-group rg-ai-foundry-prod \
--location norwayeast \
--sku Standard_GZRS \
--kind StorageV2 \
--min-tls-version TLS1_2 \
--allow-blob-public-access false
```
| Redundanstype | Beskrivelse | Anbefaling |
|---------------|-------------|------------|
| LRS | 3 kopier i en region | Kun for utvikling |
| ZRS | 3 kopier pa tvers av soner | Produksjon uten DR-krav |
| GRS | LRS + asynkron kopi til sekundaer region | Standard DR |
| GZRS | ZRS + asynkron kopi til sekundaer region | **Anbefalt for produksjon** |
| RA-GZRS | GZRS + lesetilgang til sekundaer region | Hoeyest tilgjengelighet |
## Modellversjonskontroll og gjenoppretting
### Versjonskontroll-strategi
AI-modeller gjennomgar kontinuerlig endring -- nye versjoner, fine-tuning, evaluering og deployering. En robust DR-plan krever sporbarhet og reproduserbarhet for alle modellversjoner.
```
Git Repository (kildekontroll)
|
+-- /models/
| +-- model-config.yaml # Modellkonfigurasjon
| +-- deployment-params.json # Deployment-parametere
| +-- evaluation-results/ # Evalueringsresultater per versjon
|
+-- /agents/
| +-- agent-definitions/ # JSON-definisjoner for agenter
| +-- knowledge-sources/ # Referanser til kunnskapsfiler
| +-- tool-bindings/ # Tool-konfigurasjoner
|
+-- /infrastructure/
| +-- bicep/ # IaC for alle ressurser
| +-- pipelines/ # CI/CD pipeline-definisjoner
|
+-- /prompts/
+-- system-prompts/ # System-prompter per agent/modell
+-- evaluation-datasets/ # Testdata for evaluering
```
### Modellregistrering og sporing
```yaml
# model-config.yaml -- Eksempel
model:
name: gpt-4o
version: "2024-11-20"
deployment_type: data_zone_standard
regions:
primary: norwayeast
secondary: swedencentral
quota:
primary_tpm: 120000
secondary_tpm: 120000
fine_tuning:
enabled: false
base_model: null
training_data: null
evaluation:
last_evaluated: "2026-01-15"
accuracy_score: 0.94
dataset: "eval-dataset-v3"
```
### Fine-tuned modeller
For fine-tuned modeller er det spesielt viktig med backup:
| Artefakt | Lagringssted | Backup-metode |
|----------|-------------|---------------|
| Treningsdata | Azure Storage | GZRS + versjonering |
| Modellvekter | AI Foundry model registry | Eksporter + lagre i Storage |
| Hyperparametere | Git (kildekontroll) | Standard Git-backup |
| Evalueringsresultater | AI Foundry + Git | Eksporter til Git |
| Deployment-konfig | Git (Bicep/Terraform) | Standard Git-backup |
> **Merk:** Global training (Public Preview) tilbyr rimeligere fine-tuning, men gir ikke datasuverenitet. For norsk offentlig sektor med strenge krav, bruk regional training i Norway East eller Sweden Central.
## Configuration as Code for reproduserbarhet
### Infrastruktur som kode (IaC)
Microsoft anbefaler eksplisitt a definere account, projects, capability host og avhengigheter i IaC (Bicep eller Terraform). IaC er kilden til sannhet for raskt a reprodusere konfigurasjon og rolletildelinger.
```bicep
// main.bicep -- AI Foundry prosjekt med DR-konfigurasjon
param primaryLocation string = 'norwayeast'
param secondaryLocation string = 'swedencentral'
param projectName string = 'svv-ai-project'
// Cosmos DB med continuous backup og failover
resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = {
name: '${projectName}-cosmos'
location: primaryLocation
properties: {
databaseAccountOfferType: 'Standard'
consistencyPolicy: {
defaultConsistencyLevel: 'Session'
}
locations: [
{
locationName: primaryLocation
failoverPriority: 0
isZoneRedundant: true
}
{
locationName: secondaryLocation
failoverPriority: 1
isZoneRedundant: true
}
]
backupPolicy: {
type: 'Continuous'
continuousModeProperties: {
tier: 'Continuous30Days'
}
}
enableAutomaticFailover: true
}
}
// Storage med GZRS
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: '${projectName}storage'
location: primaryLocation
sku: {
name: 'Standard_GZRS'
}
kind: 'StorageV2'
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
supportsHttpsTrafficOnly: true
}
}
// AI Foundry project (primary region)
resource aiProject 'Microsoft.MachineLearningServices/workspaces@2024-04-01' = {
name: projectName
location: primaryLocation
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
properties: {
friendlyName: 'SVV AI Project'
storageAccount: storageAccount.id
keyVault: keyVault.id
applicationInsights: appInsights.id
}
}
```
### CI/CD Pipeline for dual-region deployment
```yaml
# azure-pipelines.yml
trigger:
branches:
include:
- main
stages:
- stage: DeployPrimary
displayName: 'Deploy to Norway East'
jobs:
- job: DeployInfra
steps:
- task: AzureCLI@2
inputs:
azureSubscription: 'svv-ai-prod'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az deployment group create \
--resource-group rg-ai-foundry-norwayeast \
--template-file infrastructure/bicep/main.bicep \
--parameters location=norwayeast
- stage: DeploySecondary
displayName: 'Deploy to Sweden Central'
dependsOn: DeployPrimary
jobs:
- job: DeployInfra
steps:
- task: AzureCLI@2
inputs:
azureSubscription: 'svv-ai-prod'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az deployment group create \
--resource-group rg-ai-foundry-swedencentral \
--template-file infrastructure/bicep/main.bicep \
--parameters location=swedencentral
- stage: DeployAgents
displayName: 'Deploy Agent Definitions'
dependsOn:
- DeployPrimary
- DeploySecondary
jobs:
- job: DeployAgentDefs
steps:
- script: |
python scripts/deploy-agents.py \
--config agents/agent-definitions/ \
--regions norwayeast swedencentral
```
### Viktige IaC-prinsipper for DR
1. **Bruk user-assigned managed identity** -- ved gjenskapning av ressurser forblir rolletildelinger gyldige
2. **Unnga usporede endringer i portalen** -- alle endringer gjennom IaC/pipeline
3. **Bygg IaC modulaert** -- uavhengig deployment per prosjekt
4. **Opprett rolletildelinger i IaC** -- ikke manuelt i portalen
5. **Deploy til begge regioner i samme pipeline** -- unnga drift
## RTO og RPO-definisjoner for AI-prosjekter
### Begrepsforklaring
| Begrep | Definisjon | Relevans for AI |
|--------|-----------|-----------------|
| **RTO** | Recovery Time Objective -- maks akseptabel tid for a gjenopprette | Hvor lenge kan AI-tjenesten vaere nede? |
| **RPO** | Recovery Point Objective -- maks akseptabelt datatap malt i tid | Hvor mye samtalehistorikk/data kan vi miste? |
| **MTTR** | Mean Time To Recovery -- gjennomsnittlig gjenopprettingstid | Faktisk maalt gjenopprettingstid |
| **MTBF** | Mean Time Between Failures -- gjennomsnittlig tid mellom feil | Paalitelighetsmal for AI-tjenesten |
### Anbefalte RTO/RPO per komponent
| Komponent | RTO-mal | RPO-mal | Gjenopprettingsmetode |
|-----------|---------|---------|----------------------|
| **Azure OpenAI inference** | < 5 min | N/A (stateless) | Automatisk failover via gateway |
| **Agent Service** | < 30 min | < 1 time | Redeploy fra IaC + Cosmos PITR |
| **Samtalehistorikk** | < 2 timer | < 5 min | Cosmos DB continuous backup |
| **Kunnskapsbaser (RAG)** | < 1 time | < 24 timer | Reindeksering fra kilde |
| **Fine-tuned modeller** | < 4 timer | < 24 timer | Redeploy fra model registry |
| **Pipeline/evaluering** | < 8 timer | < 24 timer | Redeploy fra Git |
### Tier-basert DR-strategi
```
Tier 1 -- Virksomhetskritisk (RTO < 5 min, RPO ~0)
- Azure OpenAI inference med multi-region gateway
- Automatisk failover via APIM backend pool
- Eksempel: Innbyggertjenester, sanntids beslutningsstotte
Tier 2 -- Forretningsviktig (RTO < 30 min, RPO < 1 time)
- Agent Service med Cosmos DB failover
- Forhands-deployert sekundaer region (warm standby)
- Eksempel: Intern chatbot, saksbehandlingsassistent
Tier 3 -- Stottende (RTO < 4 timer, RPO < 24 timer)
- Manuell gjenskapning fra IaC
- Cold standby i sekundaer region
- Eksempel: Batch-analysejobber, treningspipelines
```
## Testing og validering av DR-prosedyrer
### DR-testrammeverk
| Testtype | Frekvens | Omfang | Ansvarlig |
|----------|----------|--------|-----------|
| **Tabletop exercise** | Kvartalsvis | Gjennomgang av prosedyrer | Arkitekturteam |
| **Komponent-failover** | Manedlig | Enkeltkomponent (f.eks. Cosmos DB) | Driftsteam |
| **Full DR-drill** | Halvaarlig | Komplett failover til sekundaer region | Hele teamet |
| **Chaos engineering** | Lopende | Automatisert feilinjeksjon | CI/CD pipeline |
### DR-testprosedyre
```
Fase 1: Forberedelse (1 dag foer)
[ ] Verifiser at IaC er oppdatert og synkronisert
[ ] Bekreft at Cosmos DB backup er aktiv og fungerer
[ ] Sjekk at sekundaer region har tilstrekkelig kvote
[ ] Varsle relevante interessenter
Fase 2: Simulert utfall (testdag)
[ ] Deaktiver primaer region i gateway (APIM policy-endring)
[ ] Verifiser at trafikk rutes til sekundaer region
[ ] Kjoer funksjonelle tester mot sekundaer region
[ ] Mal faktisk RTO og RPO
Fase 3: Validering (under test)
[ ] Verifiser AI-inferens fungerer korrekt
[ ] Sjekk at agentsamtaler kan fortsette
[ ] Kontroller at data-konsistens er ivaretatt
[ ] Verifiser overvaking og varsling
Fase 4: Tilbakeforing (etter test)
[ ] Reaktiver primaer region
[ ] Verifiser at trafikk returnerer til normalt moenster
[ ] Dokumenter resultater og avvik
[ ] Oppdater DR-plan basert pa laerdommer
```
### Azure Chaos Studio-integrasjon
Bruk Azure Chaos Studio for automatisert feilinjeksjon:
```json
{
"type": "Microsoft.Chaos/experiments",
"name": "ai-foundry-dr-test",
"properties": {
"steps": [
{
"name": "CosmosDB-failover",
"branches": [
{
"name": "main",
"actions": [
{
"type": "continuous",
"name": "urn:csci:microsoft:cosmosDB:failover/1.0",
"duration": "PT10M",
"parameters": [
{
"key": "readRegion",
"value": "Norway East"
}
],
"selectorId": "cosmos-selector"
}
]
}
]
}
],
"selectors": [
{
"id": "cosmos-selector",
"type": "List",
"targets": [
{
"id": "/subscriptions/.../cosmosdb-account",
"type": "ChaosTarget"
}
]
}
]
}
}
```
### Dokumentasjon av DR-tester
| Felt | Beskrivelse |
|------|-------------|
| **Testdato** | Dato og tidspunkt for testen |
| **Testtype** | Tabletop / Komponent / Full DR |
| **Deltakere** | Navn og roller |
| **Scenario** | Hva ble simulert |
| **Faktisk RTO** | Malt gjenopprettingstid |
| **Faktisk RPO** | Malt datatap |
| **Avvik fra mal** | Var det gap mellom mal og resultat? |
| **Funn og laerdommer** | Hva fungerte, hva ma forbedres? |
| **Tiltak** | Konkrete forbedringspunkter med eier og frist |
## Gjenopprettingsprosedyre ved regionalt utfall
### Steg-for-steg gjenoppretting
```
1. DETEKSJON (automatisk)
- Azure Monitor-varsling om regionalt utfall
- Health check-feil fra APIM gateway
2. VURDERING (5-10 min)
- Er utfallet midlertidig eller vedvarende?
- Hvilke tjenester er pavirket?
- Utloes DR-plan hvis utfall > 15 min
3. FAILOVER (15-30 min)
- Oppdater APIM til a rute all trafikk til sekundaer region
- Verifiser Cosmos DB automatisk failover
- Deploy manglende agentdefinisjoner fra kildekontroll
- Oppdater DNS hvis relevant
4. VALIDERING (15 min)
- Kjoer smoke tests mot sekundaer region
- Verifiser at alle endepunkter responderer
- Kontroller data-tilgjengelighet
5. KOMMUNIKASJON
- Varsle interne brukere om situasjonen
- Oppdater statusside
6. FAILBACK (nar primaer region er tilbake)
- Verifiser primaer region er stabil
- Gradvis ruter trafikk tilbake
- Synkroniser eventuelle endringer fra sekundaer region
```
## Referanser
- [High availability and resiliency for Microsoft Foundry projects and Agent Services](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/high-availability-resiliency)
- [Foundry Agent Service disaster recovery](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/agent-service-disaster-recovery)
- [Foundry Agent Service resource and data loss recovery](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/agent-service-operator-disaster-recovery)
- [High availability and disaster recovery for hub projects](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/hub-disaster-recovery)
- [Azure security baseline for Azure AI Foundry - Backup and recovery](https://learn.microsoft.com/en-us/security/benchmark/azure/baselines/azure-ai-foundry-security-baseline#backup-and-recovery)
- [Continuous backup with point-in-time restore in Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/continuous-backup-restore-introduction)
## For Cosmo
- **Bruk denne referansen** nar kunden planlegger disaster recovery for AI Foundry-prosjekter, spesielt nar det gjelder Agent Service, fine-tuned modeller, eller komplekse AI-pipelines som ma overleve regionalt utfall.
- **Fremhev at AI Foundry IKKE tilbyr automatisk failover** -- dette er kundens ansvar. Krav til IaC, dual-region deployment og Cosmos DB continuous backup ma kommuniseres tydelig.
- **Anbefal user-assigned managed identity** som standard -- dette forenkler gjenoppretting dramatisk ved a eliminere behovet for a gjenskape rolletildelinger.
- **Tilpass RTO/RPO-maler til organisasjonens faktiske behov** -- ikke alle AI-tjenester er virksomhetskritiske. Bruk tier-modellen for a differensiere innsats og kostnad.
- **Undersstrek viktigheten av regelmessig DR-testing** -- en DR-plan som ikke er testet er ingen plan. Anbefal kvartalsvis tabletop og halvaarlig full DR-drill som minimum.

View file

@ -0,0 +1,477 @@
# Backup and Recovery Strategies for AI Workloads
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Backup- og gjenopprettingsstrategier for AI-arbeidsbelastninger skiller seg vesentlig fra tradisjonelle applikasjoner. En AI-loesning bestar ikke bare av applikasjonskode og databaser, men ogsaa av trenede modeller, datasett, fine-tuning-artefakter, embedding-indekser, agentdefinisjoner, samtalelogger og pipeline-konfigurasjoner. Hvert av disse elementene har ulike krav til backup-frekvens, retensjonstid og gjenopprettingsmetode. Et tap av treningsdata kan bety uker med tapt arbeid, mens et tap av embedding-indekser kan gjenopprettes ved reindeksering fra kildedata.
For norsk offentlig sektor er backup-strategien ogsaa underlagt regulatoriske krav. Arkivloven, Forvaltningsloven og GDPR stiller krav til datalagring, personvern og etterproevbarhet. AI-systemer som prosesserer personopplysninger ma ha backup-rutiner som baade ivaretar gjenopprettingsbehovet og dataminimeringsprinsippet -- man skal ikke oppbevare mer data enn noedvendig, men man ma kunne gjenopprette det som er paakrevd. Azure Backup, Azure Storage-redundans og tjenestespesifikke backup-mekanismer gir et robust verktoeysett for dette.
Denne referansen dekker inkrementell versus full backup, point-in-time recovery for datasett, snapshot-administrasjon og retensjonsregler, off-region backup-lagring, og automatisering og planlegging av backups. Fokus er pa Azure-tjenester som er relevante for AI-arbeidsbelastninger, med konkrete konfigurasjonseksempler og kostnadsoverveielser.
## Inkrementell versus full backup
### Backup-typer for AI-arbeidsbelastninger
| Backup-type | Beskrivelse | Fordeler | Ulemper | Best for |
|-------------|-------------|---------|---------|----------|
| **Full backup** | Komplett kopi av alle data | Enklest gjenoppretting | Stoerst lagringsbehov, lengst tid | Ukentlig baseline |
| **Inkrementell** | Kun endringer siden forrige backup | Minst lagring, raskest | Krever alle inkrementelle + siste fulle | Daglig / flere ganger daglig |
| **Differensiell** | Endringer siden siste fulle backup | Raskere gjenoppretting enn inkrementell | Stoerre enn inkrementell | Daglig supplement til ukentlig full |
| **Continuous** | Lopende replikering av endringer | Lavest RPO (naer sanntid) | Hoeyest kostnad | Virksomhetskritiske data |
### Anbefalt backup-strategi per AI-komponent
| Komponent | Backup-type | Frekvens | Begrunnelse |
|-----------|------------|----------|-------------|
| **Azure OpenAI konfig** | IaC (Git) | Ved endring | Stateless tjeneste, konfig er alt |
| **Cosmos DB (agentdata)** | Continuous | Lopende | Forretningskritisk tilstandsdata |
| **Azure Storage (datasett)** | Inkrementell | Daglig | Store datamengder, lavt endringsvolum |
| **Azure SQL (strukturerte data)** | Full + diff | Full ukentlig, diff daglig | Relasjonelle data med transaksjonslogg |
| **Azure AI Search indekser** | Ingen backup* | Ved behov | Gjenskap fra kildedata |
| **Fine-tuned modellvekter** | Full | Ved ny versjon | Ikke inkrementelt mulig |
| **Treningsdata** | Inkrementell + versjonering | Daglig | Storrelse og endringshastighet |
| **System-prompter** | Git | Ved endring | Tekst, versjonskontroll er nok |
| **Evalueringsresultater** | Full | Etter hver evaluering | Relativt sma data |
> *Azure AI Search-indekser kan ikke backes opp direkte. Gjenopprett ved reindeksering fra originale kildedata i Azure Storage eller Cosmos DB.
### Azure Backup for AI-relaterte ressurser
Azure Backup stoetter foelgende ressurser relevant for AI-arbeidsbelastninger:
```
+------------------------------------------+------------------+------------------+
| Ressurs | Azure Backup | Nativ backup |
+------------------------------------------+------------------+------------------+
| Azure Virtual Machines (GPU/compute) | Ja | Nei |
| Azure Managed Disks | Ja | Snapshots |
| Azure Files (SMB/NFS) | Ja | Snapshots |
| Azure Blob Storage | Ja (operational) | Versjonering |
| Azure SQL Database | Ja | Auto-backup |
| Azure Database for PostgreSQL | Ja | Auto-backup |
| Azure Cosmos DB | Nei* | Continuous/PITR |
| Azure AI Foundry | Nei | Nei |
| Azure AI Search | Nei | Nei |
+------------------------------------------+------------------+------------------+
```
> *Cosmos DB har sin egen continuous backup-mekanisme og bruker ikke Azure Backup.
## Point-in-time Recovery for datasett
### Azure Blob Storage -- Versjonering og Soft Delete
For datasett lagret i Azure Blob Storage er versjonering og soft delete de viktigste mekanismene for point-in-time recovery:
```bash
# Aktiver blob-versjonering pa storage account
az storage account blob-service-properties update \
--account-name svvaistorage \
--resource-group rg-ai-prod \
--enable-versioning true
# Aktiver soft delete for blobs (30 dagers retensjonstid)
az storage account blob-service-properties update \
--account-name svvaistorage \
--resource-group rg-ai-prod \
--delete-retention-days 30 \
--enable-delete-retention true
# Aktiver soft delete for containere
az storage account blob-service-properties update \
--account-name svvaistorage \
--resource-group rg-ai-prod \
--container-delete-retention-days 30 \
--enable-container-delete-retention true
```
### Azure Blob -- Operational Backup med Azure Backup
Operational backup for Azure Blobs gir point-in-time restore:
```bash
# Opprett backup vault
az dataprotection backup-vault create \
--vault-name svv-ai-backup-vault \
--resource-group rg-ai-prod \
--location norwayeast \
--type SystemAssigned \
--storage-setting "DataStoreType=VaultStore;Type=LocallyRedundant"
# Opprett backup-policy for blobs (30 dagers retensjon)
az dataprotection backup-policy create \
--vault-name svv-ai-backup-vault \
--resource-group rg-ai-prod \
--name blob-backup-policy-30d \
--policy '{
"policyRules": [{
"name": "Default",
"objectType": "AzureRetentionRule",
"lifecycles": [{
"deleteAfter": {
"objectType": "AbsoluteDeleteOption",
"duration": "P30D"
},
"sourceDataStore": {
"objectType": "DataStoreInfoBase",
"dataStoreType": "OperationalStore"
}
}],
"isDefault": true
}],
"datasourceTypes": ["Microsoft.Storage/storageAccounts/blobServices"]
}'
```
### Cosmos DB -- Continuous Backup med PITR
Cosmos DB tilbyr to nivaaer av continuous backup:
| Egenskap | Continuous 7-day | Continuous 30-day |
|----------|-----------------|-------------------|
| Retensjonsperiode | 7 dager | 30 dager |
| Backup-lagringskostnad | Gratis | $0.20/GB * antall regioner |
| Restore-kostnad | $0.15/GB | $0.15/GB |
| Granularitet | Vilkaarlig tidspunkt innenfor retensjon | Vilkaarlig tidspunkt innenfor retensjon |
| Restore-mal | Ny konto eller eksisterende konto | Ny konto eller eksisterende konto |
```bash
# Gjenopprett Cosmos DB til et bestemt tidspunkt
az cosmosdb restore \
--account-name svv-ai-cosmos-prod \
--resource-group rg-ai-prod \
--target-database-account-name svv-ai-cosmos-restored \
--restore-timestamp "2026-02-10T14:30:00Z" \
--location norwayeast
```
> **Viktig:** Ved gjenoppretting opprettes alltid en ny konto. Foelgende konfigurasjoner gjenopprettes IKKE automatisk og ma rekonfigureres: brannmurregler, VNet-innstillinger, RBAC-tildelinger, private endpoints, lagrede prosedyrer, triggere og UDF-er.
### Azure SQL Database -- Point-in-time Restore
For AI-loesninger som bruker Azure SQL for strukturerte data:
```bash
# Gjenopprett Azure SQL til et bestemt tidspunkt
az sql db restore \
--resource-group rg-ai-prod \
--server svv-ai-sqlserver \
--name ai-metadata-db \
--dest-name ai-metadata-db-restored \
--time "2026-02-10T14:30:00Z"
```
| Retensjonsperiode | Standard | Konfigurerbar |
|-------------------|----------|---------------|
| Korttidsretensjon (PITR) | 7 dager | 1-35 dager |
| Langtidsretensjon (LTR) | Ikke aktivert | Opptil 10 aar |
## Snapshot-administrasjon og retensjon
### Snapshot-strategi for AI-infrastruktur
Snapshots er raske, kostnadseffektive kopier av data pa et bestemt tidspunkt. For AI-arbeidsbelastninger er de spesielt nyttige for VM-baserte compute-noder og managed disks.
| Ressurs | Snapshot-type | Maks snapshots | Anbefalt retensjon |
|---------|--------------|----------------|-------------------|
| Azure Managed Disks | Inkrementell | 500 per disk | 30-90 dager |
| Azure Files | Share snapshot | 200 per share | 30 dager |
| Azure Blob | Blob versjon | Ubegrenset* | 30-365 dager |
| VM (via Azure Backup) | App-consistent | Avhenger av policy | 30-90 dager |
> *Ubegrenset antall versjoner, men lagringskostnader oeker. Bruk lifecycle management for a haandtere retensjon.
### Azure Managed Disk Backup
For GPU-VM-er og compute-intensive AI-arbeidsbelastninger:
```bash
# Opprett backup-policy for managed disks
# Daglig backup med 30 dagers retensjon
az dataprotection backup-policy create \
--vault-name svv-ai-backup-vault \
--resource-group rg-ai-prod \
--name disk-backup-daily-30d \
--policy '{
"policyRules": [
{
"name": "BackupDaily",
"objectType": "AzureBackupRule",
"trigger": {
"objectType": "ScheduleBasedTriggerContext",
"schedule": {
"repeatingTimeIntervals": ["R/2026-01-01T02:00:00+00:00/P1D"]
}
},
"dataStore": {
"objectType": "DataStoreInfoBase",
"dataStoreType": "OperationalStore"
}
},
{
"name": "Default",
"objectType": "AzureRetentionRule",
"lifecycles": [{
"deleteAfter": {
"objectType": "AbsoluteDeleteOption",
"duration": "P30D"
},
"sourceDataStore": {
"objectType": "DataStoreInfoBase",
"dataStoreType": "OperationalStore"
}
}],
"isDefault": true
}
],
"datasourceTypes": ["Microsoft.Compute/disks"]
}'
```
> **Merk:** Azure Disk Backup bruker inkrementelle snapshots som er begrenset til 500 per disk. Med daglig backup betyr dette maks ~450 dagers retensjon (50 reservert for on-demand backups).
### Lifecycle Management for Azure Blob Storage
Automatisk haandtering av eldre datasett og backup-data:
```json
{
"rules": [
{
"name": "dataset-lifecycle",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["datasets/", "training-data/"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterModificationGreaterThan": 30
},
"tierToArchive": {
"daysAfterModificationGreaterThan": 90
},
"delete": {
"daysAfterModificationGreaterThan": 365
}
},
"snapshot": {
"tierToCool": {
"daysAfterCreationGreaterThan": 30
},
"delete": {
"daysAfterCreationGreaterThan": 90
}
},
"version": {
"tierToCool": {
"daysAfterCreationGreaterThan": 30
},
"delete": {
"daysAfterCreationGreaterThan": 90
}
}
}
}
}
]
}
```
## Off-region backup-lagring
### Azure Storage-redundans for backup
| Redundanstype | Regioner | Tilgjengelighet | Kostnad (relativ) | Anbefaling |
|---------------|---------|-----------------|-------------------|------------|
| **LRS** | 1 region, 3 kopier | 99.999999999% (11 niere) | 1x | Kun utvikling |
| **ZRS** | 1 region, 3 soner | 99.9999999999% (12 niere) | ~1.25x | Produksjon uten DR |
| **GRS** | 2 regioner, 6 kopier | 99.99999999999999% (16 niere) | ~2x | Standard DR |
| **GZRS** | 2 regioner, 6 kopier (3 soner + 3) | Hoeyest | ~2.5x | **Anbefalt for AI prod** |
| **RA-GRS/RA-GZRS** | Som GRS/GZRS + lesetilgang | Hoeyest + lestilgang | ~2.5-3x | Lese-intensiv DR |
### Konfigurering av geo-redundant backup
```bash
# Opprett Recovery Services vault med GRS for VM-backup
az backup vault create \
--name svv-ai-recovery-vault \
--resource-group rg-ai-prod \
--location norwayeast
# Sett storage-redundans til geo-redundant
az backup vault backup-properties set \
--name svv-ai-recovery-vault \
--resource-group rg-ai-prod \
--backup-storage-redundancy GeoRedundant
# Aktiver Cross Region Restore
az backup vault backup-properties set \
--name svv-ai-recovery-vault \
--resource-group rg-ai-prod \
--cross-region-restore-flag Enabled
```
### Off-region backup-arkitektur for AI-data
```
Norway East (primaer) Sweden Central (sekundaer)
+---------------------------+ +---------------------------+
| AI Foundry Project | | (Replikert data) |
| +---------------------+ | async | +---------------------+ |
| | Storage (GZRS) |------copy--->| | Storage (read) | |
| +---------------------+ | | +---------------------+ |
| +---------------------+ | auto | +---------------------+ |
| | Cosmos DB |---failover->| | Cosmos DB (replica) | |
| +---------------------+ | | +---------------------+ |
| +---------------------+ | geo-rep | +---------------------+ |
| | Container Registry |------copy--->| | Container Registry | |
| +---------------------+ | | +---------------------+ |
| +---------------------+ | auto | +---------------------+ |
| | Key Vault |---failover->| | Key Vault (replica) | |
| +---------------------+ | | +---------------------+ |
+---------------------------+ +---------------------------+
```
### Datasuverenitetshensyn
For norsk offentlig sektor er det viktig at off-region backup forblir innenfor EU/EOeS:
| Primaer region | Anbefalt sekundaer | Paringstype | Datasuverenitet |
|----------------|-------------------|-------------|-----------------|
| Norway East | Norway West* | Paret region | Norge |
| Norway East | Sweden Central | Manuell | EU/EOeS |
| Sweden Central | Norway East | Manuell | EU/EOeS |
> *Norway West har begrenset tjenestestotte. Bruk Sweden Central som alternativ sekundaer region.
## Automatisering og planlegging av backups
### Azure Policy for automatisk backup
```json
{
"type": "Microsoft.Authorization/policyAssignments",
"properties": {
"displayName": "Automatisk backup for AI VM-er",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/013e242c-8828-4970-87b3-ab247555486d",
"parameters": {
"vaultLocation": { "value": "norwayeast" },
"backupPolicyId": {
"value": "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.RecoveryServices/vaults/svv-ai-recovery-vault/backupPolicies/DefaultPolicy"
}
}
}
}
```
### Backup-planlegging for AI-arbeidsbelastninger
| Komponent | Planlagt tid | Frekvens | Vindu | Automatisert |
|-----------|-------------|----------|-------|-------------|
| VM-snapshots (GPU) | 02:00 UTC | Daglig | 2 timer | Azure Backup Policy |
| Blob Storage operational | Kontinuerlig | Lopende | N/A | Azure Backup |
| Cosmos DB | Kontinuerlig | Lopende | N/A | Nativ (innebygd) |
| Azure SQL | 00:00 UTC (full) | Full ukentlig, diff daglig | 4 timer | Automatisk |
| Azure Files | 03:00 UTC | Daglig | 1 time | Azure Backup Policy |
| IaC + kode (Git) | Ved push | Hendelsesbasert | N/A | Git + pipeline |
| Modelleksport | Etter deploy | Ved ny versjon | 1 time | CI/CD pipeline |
### Automatisert backup-overvaking
```kusto
// KQL-query for Azure Monitor -- Sjekk backup-status for siste 24 timer
AzureDiagnostics
| where Category == "AzureBackupReport"
| where TimeGenerated > ago(24h)
| where OperationName == "Job"
| summarize
SuccessCount = countif(ResultType == "Succeeded"),
FailedCount = countif(ResultType == "Failed"),
InProgressCount = countif(ResultType == "InProgress")
| extend HealthStatus = iff(FailedCount > 0, "UNHEALTHY", "HEALTHY")
```
### Varsling ved backup-feil
```json
{
"type": "Microsoft.Insights/scheduledQueryRules",
"properties": {
"displayName": "AI Backup Failure Alert",
"description": "Varsler ved feil i backup for AI-arbeidsbelastninger",
"severity": 1,
"enabled": true,
"evaluationFrequency": "PT1H",
"windowSize": "PT1H",
"criteria": {
"allOf": [{
"query": "AzureDiagnostics | where Category == 'AzureBackupReport' | where OperationName == 'Job' | where ResultType == 'Failed' | where TimeGenerated > ago(1h)",
"threshold": 0,
"operator": "GreaterThan",
"timeAggregation": "Count"
}]
},
"actions": {
"actionGroups": ["/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Insights/actionGroups/ai-ops-team"]
}
}
}
```
## Kostnadsstyring for backup
### Estimert backup-kostnad per komponent
| Komponent | Datavolum | Backup-type | Estimert kostnad (NOK/maned) |
|-----------|-----------|------------|------------------------------|
| Cosmos DB (30-day continuous) | 50 GB, 2 regioner | Continuous | ~210 |
| Azure Blob (operational) | 500 GB | PITR | ~250 |
| Azure Managed Disk | 1 TB (GPU VM) | Daglig snapshot | ~400 |
| Azure SQL (PITR + LTR) | 100 GB | Auto + LTR | ~150 |
| Azure Files | 200 GB | Daglig snapshot | ~100 |
| Recovery Services vault | N/A | GRS | ~80 |
| **Totalt estimat** | | | **~1 190** |
> **Tips:** Bruk Azure Cost Management for a overvake faktiske backup-kostnader. Sett budsjettvarslinger for a unnga overraskelser.
## Sjekkliste for backup-strategi
- [ ] Kartlegg alle AI-komponenter og deres backup-behov
- [ ] Definer RPO for hver komponent basert pa forretningskritikalitet
- [ ] Aktiver Cosmos DB continuous backup med PITR
- [ ] Konfigurer Azure Blob Storage med versjonering og soft delete
- [ ] Sett opp Azure Backup for VM-er og managed disks
- [ ] Implementer lifecycle management for kostnadsoptimalisering
- [ ] Konfigurer geo-redundant lagring (GZRS) for produksjonsdata
- [ ] Automatiser backup gjennom Azure Policy
- [ ] Sett opp overvaking og varsling for backup-feil
- [ ] Dokumenter og test gjenopprettingsprosedyrer kvartalsvis
- [ ] Verifiser at backup-strategi er i samsvar med regulatoriske krav
## Referanser
- [Azure Backup Overview](https://learn.microsoft.com/en-us/azure/backup/backup-overview)
- [Azure Blob operational backup](https://learn.microsoft.com/en-us/azure/backup/blob-backup-overview)
- [Azure Storage redundancy](https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy)
- [Continuous backup with point-in-time restore in Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/continuous-backup-restore-introduction)
- [Azure Disk Backup overview](https://learn.microsoft.com/en-us/azure/backup/disk-backup-overview)
- [Management recommendations for AI workloads on Azure infrastructure](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/infrastructure/management)
- [Azure security baseline for Azure AI Foundry - Backup and recovery](https://learn.microsoft.com/en-us/security/benchmark/azure/baselines/azure-ai-foundry-security-baseline#backup-and-recovery)
- [Manage AI business continuity](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/manage#manage-ai-business-continuity)
## For Cosmo
- **Bruk denne referansen** nar kunden trenger en helhetlig backup-strategi for AI-arbeidsbelastninger -- fra datasett og modeller til infrastruktur og agentdata.
- **Start med a kartlegge komponentene** -- mange kunder tenker bare pa "backup av modellen" men glemmer Cosmos DB, AI Search-indekser, og pipeline-konfigurasjoner som ogsaa er kritiske.
- **Anbefal Cosmos DB Continuous 30-day** for agentdata og Azure Blob GZRS for datasett som standardkonfigurasjon for norsk offentlig sektor.
- **Bruk kostnadstabellene** for a vise at backup for AI-arbeidsbelastninger er relativt rimelig sammenlignet med konsekvensene av datatap -- dette hjelper med a bygge business case.
- **Paapek regulatoriske krav** -- Arkivloven og Forvaltningsloven kan kreve lengre retensjon enn teknisk noedvendig, og dette ma fanges opp tidlig i planleggingen.

View file

@ -0,0 +1,342 @@
# Capacity Planning for DR Configurations
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Kapasitetsplanlegging for Disaster Recovery-konfigurasjoner handler om å dimensjonere reserveressurser riktig slik at AI-systemer kan gjenopprettes innenfor definerte RTO- og RPO-mål. For AI-arbeidsbelastninger er dette spesielt utfordrende fordi ressurskravene er høye (GPU-compute, store indekser, høy throughput) og kostnadene eskalerer raskt ved full duplisering.
Azure tilbyr flere strategier for å balansere kapasitet, kostnad og gjenopprettingstid: fra alltid-aktive active-active konfigurasjoner til minimalt provisionerte warm/cold standby-oppsett med auto-scaling. Valget avhenger av kritikalitetstier og budsjett.
Norske offentlige organisasjoner må gjøre en avveining mellom tilgjengelighetskrav (NSMs grunnprinsipper) og kostnadseffektivitet (krav om forsvarlig bruk av offentlige midler). Kapasitetsplanlegging bør dokumenteres som del av organisasjonens BCDR-plan og revideres minst årlig.
## Dimensjonering av DR-miljø for toppbelastning
### AI-komponent dimensjoneringsmatrise
| AI-komponent | Primær region | DR (Active-Active) | DR (Warm Standby) | DR (Cold Standby) |
|--------------|--------------|--------------------|--------------------|-------------------|
| Azure OpenAI | 120K TPM | 120K TPM | 60K TPM + autoscale | 0 (redeploy) |
| AI Search (replikaer) | 3 | 3 | 2 | 0 (rebuild) |
| AI Search (partisjoner) | 4 | 4 | 4 | 0 (rebuild) |
| App Service | P3v3 x 3 | P3v3 x 3 | P2v3 x 1 | 0 (deploy) |
| Cosmos DB (RU/s) | 10,000 | 10,000 | 4,000 (autoscale) | 0 (restore) |
### Beregning av DR-kapasitetsbehov
```python
# Kapasitetsberegningsmodell for AI DR-miljø
def calculate_dr_capacity(primary_config, dr_strategy, peak_multiplier=1.2):
"""
Beregn nødvendig DR-kapasitet basert på primær konfigurasjon.
Args:
primary_config: Dict med primær region ressurser
dr_strategy: 'active-active', 'warm-standby', 'cold-standby'
peak_multiplier: Faktor for toppbelastning (default 1.2x)
"""
dr_config = {}
if dr_strategy == "active-active":
# Full kapasitet i begge regioner
for resource, capacity in primary_config.items():
dr_config[resource] = capacity * peak_multiplier
elif dr_strategy == "warm-standby":
# Redusert kapasitet, skaleres opp ved failover
scaling_factors = {
"openai_tpm": 0.5, # 50% av primær
"search_replicas": 0.67, # 2 av 3 replikaer
"search_partitions": 1.0, # Full (kan ikke skalere raskt)
"app_service_instances": 0.33, # 1 av 3 instanser
"cosmos_ru": 0.4, # 40% med autoscale til 100%
}
for resource, capacity in primary_config.items():
factor = scaling_factors.get(resource, 0.5)
dr_config[resource] = int(capacity * factor)
elif dr_strategy == "cold-standby":
# Ingen kjørende ressurser, kun IaC-maler
for resource, capacity in primary_config.items():
dr_config[resource] = 0
dr_config["iac_templates"] = True
dr_config["estimated_deploy_time_minutes"] = 30
return dr_config
# Eksempel
primary = {
"openai_tpm": 120000,
"search_replicas": 3,
"search_partitions": 4,
"app_service_instances": 3,
"cosmos_ru": 10000
}
warm = calculate_dr_capacity(primary, "warm-standby")
print(f"Warm standby config: {warm}")
# Output: {'openai_tpm': 60000, 'search_replicas': 2, ...}
```
## Surge capacity og burst-håndtering
### Azure OpenAI Token Rate Limiting
Azure OpenAI har regionalt baserte kvoter. Ved failover til sekundær region kan eksisterende kvoter være utilstrekkelige.
```bash
# Sjekk nåværende kvote i sekundær region
az cognitiveservices account list-usage \
--name "aoai-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--output table
# Pre-provisioner kapasitet med Provisioned Throughput Units (PTU)
az cognitiveservices account deployment create \
--name "aoai-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--deployment-name "gpt-4o-ptu" \
--model-name "gpt-4o" \
--model-version "2024-08-06" \
--model-format "OpenAI" \
--sku-capacity 50 \
--sku-name "ProvisionedManaged"
```
### Auto-scaling for App Service
```bash
# Konfigurer autoscale i DR-region
az monitor autoscale create \
--resource-group "rg-ai-dr" \
--name "autoscale-ai-app-dr" \
--resource "/subscriptions/{sub}/resourceGroups/rg-ai-dr/providers/Microsoft.Web/serverFarms/asp-ai-dr" \
--min-count 1 \
--max-count 5 \
--count 1
# Scale-up regel basert på CPU
az monitor autoscale rule create \
--resource-group "rg-ai-dr" \
--autoscale-name "autoscale-ai-app-dr" \
--condition "Percentage CPU > 70 avg 5m" \
--scale out 2
# Scale-down regel
az monitor autoscale rule create \
--resource-group "rg-ai-dr" \
--autoscale-name "autoscale-ai-app-dr" \
--condition "Percentage CPU < 30 avg 10m" \
--scale in 1
```
### Cosmos DB Autoscale
```bash
# Konfigurer autoscale for Cosmos DB i DR-region
# Baseline: 4000 RU/s, maks: 10000 RU/s
az cosmosdb sql container throughput migrate \
--account-name "cosmos-ai-dr" \
--resource-group "rg-ai-dr" \
--database-name "chatbot-state" \
--name "conversations" \
--throughput-type "autoscale"
az cosmosdb sql container throughput update \
--account-name "cosmos-ai-dr" \
--resource-group "rg-ai-dr" \
--database-name "chatbot-state" \
--name "conversations" \
--max-throughput 10000
```
## Kostnadsoptimalisering for standby-ressurser
### Kostnadsprofiler per DR-strategi
| Strategi | Kostnad vs. primær | RTO | Best for |
|----------|-------------------|-----|----------|
| Active-Active (full) | 100% | ~0 | Tier 0: Mission Critical |
| Active-Active (optimized autoscale) | 5070% | Sekunder | Tier 0/1 |
| Warm Standby (partial) | 2540% | 515 min | Tier 1: Business Critical |
| Cold Standby (IaC only) | 510% | 3060 min | Tier 2: Business Operational |
| Backup & Restore | 25% | TimerDager | Tier 3: Administrative |
### Spesifikke kostnadsbesparelser
```markdown
## Kostnadsbesparelser for Warm Standby
1. **Azure OpenAI**: Bruk pay-per-token (ikke PTU) i DR-region
- Besparelse: 6080% vs. PTU
- Tradeoff: Ingen garantert kapasitet ved failover
2. **AI Search**: 2 replikaer i stedet for 3 i DR
- Besparelse: ~33% på search-kostnaden
- Tradeoff: 99.9% SLA i stedet for 99.99%
3. **App Service**: P2v3 i stedet for P3v3, med autoscale
- Besparelse: ~50% på compute
- Tradeoff: 12 min skaleringstid ved failover
4. **Cosmos DB**: Autoscale med lav baseline
- Besparelse: 4060% ved lavt normalbruk
- Tradeoff: Opptil 10s oppskaleringsforsinkelse
```
### Azure Cost Management for DR
```bash
# Tag alle DR-ressurser for kostnadssporing
az tag create --name "Environment" --value "DR"
# Sett budsjett-alert for DR-ressursgruppe
az consumption budget create \
--budget-name "dr-monthly-budget" \
--amount 50000 \
--category "Cost" \
--time-grain "Monthly" \
--time-period '{"Start": "2026-01-01", "End": "2026-12-31"}' \
--resource-groups "rg-ai-dr" \
--notifications '{
"Warning80": {
"enabled": true,
"operator": "GreaterThan",
"threshold": 80,
"contactEmails": ["platform-team@org.no"]
},
"Critical100": {
"enabled": true,
"operator": "GreaterThan",
"threshold": 100,
"contactEmails": ["platform-team@org.no", "management@org.no"]
}
}'
```
## Skaleringsregler og auto-scaling
### DR Activation Scaling Pipeline
```yaml
# Azure DevOps Pipeline: DR Activation Scale-Up
trigger: none # Manuelt eller via alert webhook
parameters:
- name: activationType
type: string
values:
- failover
- failover-drill
- scale-test
stages:
- stage: ScaleUpDR
displayName: 'Scale Up DR Environment'
jobs:
- job: ScaleSearchService
steps:
- task: AzureCLI@2
displayName: 'Scale AI Search to 3 replicas'
inputs:
azureSubscription: 'dr-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az search service update \
--name "search-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--replica-count 3
- job: ScaleAppService
steps:
- task: AzureCLI@2
displayName: 'Scale App Service to P3v3'
inputs:
azureSubscription: 'dr-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az appservice plan update \
--name "asp-ai-dr" \
--resource-group "rg-ai-dr" \
--sku P3v3
- job: VerifyCapacity
dependsOn:
- ScaleSearchService
- ScaleAppService
steps:
- task: AzureCLI@2
displayName: 'Verify DR capacity'
inputs:
azureSubscription: 'dr-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "=== Search Service ==="
az search service show \
--name "search-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--query "{replicas:replicaCount, partitions:partitionCount, status:status}"
echo "=== App Service Plan ==="
az appservice plan show \
--name "asp-ai-dr" \
--resource-group "rg-ai-dr" \
--query "{sku:sku.name, workers:numberOfWorkers}"
```
## Kapasitetsreservasjonsstrategier
### Azure Reserved Instances for DR
| Ressurstype | Reservasjonsanbefaling | Besparelse | Merknad |
|-------------|----------------------|------------|---------|
| App Service P2v3 | 1-år RI for baseline | ~35% | For warm standby baseline |
| Cosmos DB (autoscale) | Ingen RI | N/A | Autoscale er per-bruk |
| Azure OpenAI PTU | RI kun for primær | ~30% | DR bruker pay-per-token |
| AI Search Standard | RI for begge regioner | ~35% | Partisjoner kjører alltid |
| Storage (GZRS) | Reservert kapasitet | ~25% | For store datasett |
### Capacity Reservation Groups
```bash
# Opprett kapasitetsreservasjon for VM-baserte workloads i DR-region
az capacity reservation group create \
--name "crg-ai-dr-swedencentral" \
--resource-group "rg-ai-dr" \
--location "swedencentral" \
--zones 1 2 3
# Reserver spesifikk VM-størrelse
az capacity reservation create \
--capacity-reservation-group "crg-ai-dr-swedencentral" \
--resource-group "rg-ai-dr" \
--name "cr-gpu-nc24ads" \
--location "swedencentral" \
--sku "Standard_NC24ads_A100_v4" \
--capacity 2 \
--zone 1
```
## Referanser
- [Develop a disaster recovery plan — Optimize your recovery costs](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#optimize-your-recovery-costs) — Kostnadsoptimalisering per tier
- [Recovery strategy for active-passive (warm standby)](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#recovery-strategy-for-active-passive-warm-standby) — Warm standby konfigurasjon
- [Recovery strategy for active-active deployments](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#recovery-strategy-for-active-active-deployments) — Active-active konfigurasjon
- [BCDR considerations with Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/business-continuity-disaster-recovery) — OpenAI-spesifikk kapasitetsplanlegging
- [Management recommendations for AI workloads on Azure IaaS](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/infrastructure/management) — AI-workload management
- [Azure Site Recovery — Plan capacity and scaling](https://learn.microsoft.com/en-us/azure/site-recovery/site-recovery-plan-capacity-vmware) — Kapasitetsplanlegging
## For Cosmo
- **Bruk denne referansen** når kunden trenger hjelp med å dimensjonere og kostnadsoptimalisere sine DR-miljøer for AI-workloads.
- Warm standby med autoscale er den mest kostnadseffektive strategien for Tier 1 (Business Critical) AI-systemer — typisk 2540% av full dupliseringskostnad.
- Påminn om at Azure OpenAI-kvoter er regionsspesifikke — kunden MÅ pre-allokere kapasitet i DR-regionen, ellers risikerer de at failover feiler pga. kvotebegrensninger.
- For AI Search: Partisjoner kan ikke skaleres ned uten å gjenopprette tjenesten, så dimensjonér partisjoner identisk i begge regioner.
- Anbefal Azure Cost Management med tags og budsjetter for å overvåke DR-kostnader separat fra produksjonskostnader.

View file

@ -0,0 +1,437 @@
# Chaos Engineering for AI Systems
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Chaos engineering er praksisen med å bevisst injisere feil i et system for å teste dets resiliens og avdekke svakheter før de forårsaker produksjonshendelser. For AI-systemer er dette spesielt verdifullt fordi AI-workloads har komplekse avhengighetskjeder (modell-endpoints, search-indekser, embedding-pipelines, datastores) der en feil i ett komponent kan kaskadere uforutsigbart.
Azure Chaos Studio er Azures native plattform for chaos engineering, og tilbyr både agentbasert og tjenestenivå feilinjeksjon. For AI-systemer kan Chaos Studio simulere alt fra nettverkspartisjonering til CPU-press og DNS-feil, noe som lar team validere at circuit breakers, retry-logikk og graceful degradation fungerer som forventet.
For norsk offentlig sektor er chaos engineering en viktig del av NSMs krav om regelmessig testing av sikkerhetstiltak (grunnprinsipp 4.3). Det anbefales at organisasjoner gjennomfører strukturerte feilinjeksjonstester minst kvartalsvis, og etter alle større endringer i AI-arkitekturen.
## Feilinjeksjonsstrategier for AI-tjenester
### Feilkatalog for AI-workloads
| Feiltype | Simulering | Påvirket komponent | Forventet respons |
|----------|-----------|-------------------|-------------------|
| Regional outage | DNS-feil eller nettverksblokk | Azure OpenAI | Failover til sekundær region |
| API throttling | Kunstig 429-respons | Azure OpenAI | Retry med backoff, graceful degradation |
| Search unavailable | Nettverksblokk til search | AI Search | Fallback til keyword search |
| High latency | Nettverksforsinkelse | Alle API-kall | Timeout → circuit breaker |
| Data corruption | Feil embedding-verdier | Cosmos DB / Search | Validering og rebuild |
| Memory pressure | VM memory stress | App Service | Auto-restart, scaling |
| Dependency failure | DNS poisoning | Key Vault, App Config | Cached config, graceful degradation |
### Azure Chaos Studio eksperimenter
```bash
# Aktiver Chaos Studio for ressurser
# Steg 1: Registrer target
az rest --method PUT \
--url "https://management.azure.com/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Web/sites/ai-app-prod/providers/Microsoft.Chaos/targets/Microsoft-AppService?api-version=2024-01-01" \
--body '{"properties":{}}'
# Steg 2: Aktiver capability (App Service Stop)
az rest --method PUT \
--url "https://management.azure.com/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Web/sites/ai-app-prod/providers/Microsoft.Chaos/targets/Microsoft-AppService/capabilities/Stop-1.0?api-version=2024-01-01" \
--body '{"properties":{}}'
```
### Chaos Experiment: Simuler Azure OpenAI Regional Outage
```json
{
"identity": {
"type": "SystemAssigned"
},
"location": "norwayeast",
"properties": {
"selectors": [
{
"id": "selector-nsg-block-openai",
"type": "List",
"targets": [
{
"id": "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Network/networkSecurityGroups/nsg-ai-app/providers/Microsoft.Chaos/targets/Microsoft-NetworkSecurityGroup",
"type": "ChaosTarget"
}
]
}
],
"steps": [
{
"name": "Block-OpenAI-Traffic",
"branches": [
{
"name": "branch-1",
"actions": [
{
"name": "urn:csci:microsoft:networkSecurityGroup:securityRule/1.1",
"type": "continuous",
"selectorId": "selector-nsg-block-openai",
"duration": "PT10M",
"parameters": [
{ "key": "name", "value": "chaos-block-openai" },
{ "key": "protocol", "value": "*" },
{ "key": "sourceAddresses", "value": "[\"*\"]" },
{ "key": "destinationAddresses", "value": "[\"CognitiveServicesManagement\"]" },
{ "key": "destinationPortRanges", "value": "[\"443\"]" },
{ "key": "access", "value": "Deny" },
{ "key": "priority", "value": "100" },
{ "key": "direction", "value": "Outbound" }
]
}
]
}
]
}
]
}
}
```
## Nettverkspartisjonssimulering
### Simuler cross-region nettverkspartisjon
```bash
# Chaos experiment: Simuler nettverkspartisjon mellom regioner
# Blokkerer VNet peering-trafikk for å teste failover
# Metode 1: NSG-basert blokkering
az network nsg rule create \
--resource-group "rg-networking" \
--nsg-name "nsg-ai-app" \
--name "chaos-block-cross-region" \
--priority 50 \
--direction Outbound \
--access Deny \
--protocol "*" \
--destination-address-prefixes "10.2.0.0/16" \
--description "CHAOS TEST: Block cross-region traffic"
# Vent og observer (10 minutter)
sleep 600
# Fjern blokkeringen
az network nsg rule delete \
--resource-group "rg-networking" \
--nsg-name "nsg-ai-app" \
--name "chaos-block-cross-region"
```
### DNS-feil simulering
```python
# Python: Simuler DNS-feil for testing
# Bruk Azure Private DNS zone override for å simulere DNS-feil
import subprocess
def simulate_dns_failure(target_fqdn: str, duration_minutes: int = 10):
"""Simulate DNS failure by overriding DNS resolution."""
print(f"Simulating DNS failure for {target_fqdn} for {duration_minutes} min")
# Opprett en DNS record som peker til en ikke-eksisterende IP
subprocess.run([
"az", "network", "private-dns", "record-set", "a", "add-record",
"--resource-group", "rg-networking",
"--zone-name", "privatelink.openai.azure.com",
"--record-set-name", "chaos-test",
"--ipv4-address", "10.255.255.255" # Ikke-ruterbar IP
])
print(f"DNS poisoned. Observing for {duration_minutes} minutes...")
import time
time.sleep(duration_minutes * 60)
# Rydd opp
subprocess.run([
"az", "network", "private-dns", "record-set", "a", "remove-record",
"--resource-group", "rg-networking",
"--zone-name", "privatelink.openai.azure.com",
"--record-set-name", "chaos-test",
"--ipv4-address", "10.255.255.255"
])
print("DNS restored.")
```
## Last- og stresstesting
### Load testing med Azure Load Testing
```yaml
# JMeter test plan for AI API stress testing
# azure-load-test-config.yaml
version: v0.1
testId: ai-stress-test
testPlan: ai-load-test.jmx
engineInstances: 5
configurationFiles:
- ai-load-test.jmx
failureCriteria:
- avg(response_time_ms) > 5000
- percentage(error) > 5
env:
- name: AOAI_ENDPOINT
value: https://aoai-prod.openai.azure.com
- name: SEARCH_ENDPOINT
value: https://search-prod.search.windows.net
```
```bash
# Opprett og kjør load test
az load test create \
--name "ai-stress-test" \
--resource-group "rg-ai-test" \
--load-test-resource "lt-ai-prod" \
--test-plan "ai-load-test.jmx" \
--engine-instances 5
# Kjør test med failover-scenario
az load test-run create \
--name "failover-stress-run" \
--resource-group "rg-ai-test" \
--load-test-resource "lt-ai-prod" \
--test-id "ai-stress-test" \
--description "Stress test during simulated failover"
```
### Gradvis belastningsøkning
```python
# Gradvis belastningsøkning for å finne breaking point
import asyncio
import aiohttp
import time
async def ramp_up_test(
endpoint: str,
start_rps: int = 10,
end_rps: int = 500,
step_rps: int = 10,
step_duration_seconds: int = 60
):
"""Gradually increase load to find service breaking point."""
current_rps = start_rps
results = []
while current_rps <= end_rps:
print(f"Testing at {current_rps} RPS for {step_duration_seconds}s...")
interval = 1.0 / current_rps
success_count = 0
error_count = 0
total_latency = 0
start = time.time()
while time.time() - start < step_duration_seconds:
try:
req_start = time.time()
async with aiohttp.ClientSession() as session:
async with session.post(endpoint, json={"query": "test"}) as resp:
if resp.status < 400:
success_count += 1
else:
error_count += 1
total_latency += (time.time() - req_start) * 1000
except Exception:
error_count += 1
await asyncio.sleep(interval)
total = success_count + error_count
error_rate = error_count / max(total, 1) * 100
avg_latency = total_latency / max(total, 1)
results.append({
"rps": current_rps,
"success": success_count,
"errors": error_count,
"error_rate": round(error_rate, 2),
"avg_latency_ms": round(avg_latency, 1)
})
print(f" Results: {error_rate:.1f}% errors, {avg_latency:.0f}ms avg latency")
# Stop hvis error rate er for høy
if error_rate > 20:
print(f"Breaking point found at {current_rps} RPS")
break
current_rps += step_rps
return results
```
## Recovery time-måling og validering
### RTO-måling under chaos testing
```python
# Automatisk RTO-måling under failover-test
import time
import requests
from datetime import datetime
class RTOMeasurement:
"""Measure actual RTO during failover tests."""
def __init__(self, health_endpoint: str, check_interval_seconds: float = 1.0):
self.health_endpoint = health_endpoint
self.check_interval = check_interval_seconds
self.measurements = []
def measure_rto(self, max_wait_seconds: int = 600) -> dict:
"""Continuously check health and measure recovery time."""
failure_detected = None
recovery_detected = None
was_healthy = True
checks = []
start = time.time()
while time.time() - start < max_wait_seconds:
try:
resp = requests.get(self.health_endpoint, timeout=5)
is_healthy = resp.status_code == 200
except Exception:
is_healthy = False
check = {
"timestamp": datetime.utcnow().isoformat(),
"elapsed_seconds": round(time.time() - start, 1),
"healthy": is_healthy
}
checks.append(check)
if was_healthy and not is_healthy and failure_detected is None:
failure_detected = time.time()
print(f"Failure detected at {check['elapsed_seconds']}s")
if not was_healthy and is_healthy and failure_detected and recovery_detected is None:
recovery_detected = time.time()
rto = recovery_detected - failure_detected
print(f"Recovery detected at {check['elapsed_seconds']}s — RTO: {rto:.1f}s")
was_healthy = is_healthy
time.sleep(self.check_interval)
result = {
"failure_detected": failure_detected is not None,
"recovery_detected": recovery_detected is not None,
"rto_seconds": round(recovery_detected - failure_detected, 1) if recovery_detected and failure_detected else None,
"total_checks": len(checks),
"healthy_checks": sum(1 for c in checks if c["healthy"]),
"unhealthy_checks": sum(1 for c in checks if not c["healthy"]),
"availability_pct": round(
sum(1 for c in checks if c["healthy"]) / max(len(checks), 1) * 100, 2
)
}
self.measurements.append(result)
return result
# Bruk
rto_meter = RTOMeasurement("https://ai-app-prod.azurewebsites.net/health")
result = rto_meter.measure_rto(max_wait_seconds=600)
print(f"Measured RTO: {result['rto_seconds']}s")
```
## Verktøy og plattformer for chaos engineering
### Azure Chaos Studio
| Funksjon | Beskrivelse | Støttede ressurser |
|----------|-------------|-------------------|
| Service-direct faults | Feil injisert via Azure API | App Service, AKS, Cosmos DB, NSG |
| Agent-based faults | Feil injisert via VM-agent | CPU/memory stress, network faults |
| Experiments | Strukturerte feilsekvenser | Alle støttede resurser |
| Permissions | RBAC-basert tilgangskontroll | Dedicated Chaos role |
### Komplementære verktøy
| Verktøy | Bruksområde | Integrasjon med Azure |
|---------|-------------|----------------------|
| Azure Chaos Studio | Native Azure fault injection | Innebygd |
| Azure Load Testing | Lasttesting | Innebygd, JMeter-basert |
| Litmus Chaos | Kubernetes chaos testing | AKS-kompatibel |
| Toxiproxy | Nettverksfeil for utvikling | Manuell oppsett |
| PYRIT | AI-spesifikk red teaming | Azure AI |
### Chaos Testing CI/CD-integrasjon
```yaml
# Azure DevOps Pipeline: Chaos testing som del av release
trigger: none
stages:
- stage: DeployToStaging
displayName: 'Deploy to Staging'
jobs:
- job: Deploy
steps:
- task: AzureWebApp@1
inputs:
appName: 'ai-app-staging'
- stage: ChaosTests
displayName: 'Run Chaos Experiments'
dependsOn: DeployToStaging
jobs:
- job: RunChaosExperiment
steps:
- task: AzureCLI@2
displayName: 'Start chaos experiment'
inputs:
azureSubscription: 'chaos-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
# Start chaos experiment
EXPERIMENT_ID=$(az rest --method POST \
--url "https://management.azure.com/subscriptions/{sub}/resourceGroups/rg-ai-test/providers/Microsoft.Chaos/experiments/openai-failover-test/start?api-version=2024-01-01" \
--query "statusUrl" -o tsv)
echo "Experiment started: $EXPERIMENT_ID"
# Vent og mål RTO
python measure_rto.py \
--endpoint "https://ai-app-staging.azurewebsites.net/health" \
--max-wait 300
- task: AzureCLI@2
displayName: 'Validate results'
inputs:
azureSubscription: 'chaos-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
# Sjekk at RTO er innenfor mål
RTO=$(python -c "import json; print(json.load(open('rto_result.json'))['rto_seconds'])")
if [ $(echo "$RTO > 900" | bc) -eq 1 ]; then
echo "##vso[task.logissue type=error]RTO exceeded 15 minutes: ${RTO}s"
exit 1
fi
echo "RTO within target: ${RTO}s"
```
## Referanser
- [What is Azure Chaos Studio?](https://learn.microsoft.com/en-us/azure/chaos-studio/chaos-studio-overview) — Chaos Studio oversikt
- [Understand chaos engineering and resilience](https://learn.microsoft.com/en-us/azure/chaos-studio/chaos-studio-chaos-engineering-overview) — Chaos engineering konsepter
- [Architecture strategies for designing a reliability testing strategy](https://learn.microsoft.com/en-us/azure/well-architected/reliability/testing-strategy) — WAF testing-strategi
- [Continuous validation with Azure Load Testing and Chaos Studio](https://learn.microsoft.com/en-us/azure/architecture/guide/testing/mission-critical-deployment-testing) — Kombinert testing
- [Shift right to test in production](https://learn.microsoft.com/en-us/devops/deliver/shift-right-test-production) — Fault injection i produksjon
- [Chaos Agent overview](https://learn.microsoft.com/en-us/azure/chaos-studio/chaos-agent-overview) — Agent-basert feilinjeksjon
## For Cosmo
- **Bruk denne referansen** når kunden ønsker å implementere chaos engineering for AI-systemer, eller når de trenger å validere sine DR-prosedyrer.
- Start med tabletop-øvelser før reelle feilinjeksjoner — forstå forventet oppførsel før du bryter ting.
- Bruk Azure Chaos Studio i staging-miljøer først, deretter gradvis i produksjon med begrenset blast radius.
- Integrer chaos testing i CI/CD — automatiserte failover-tester bør kjøres etter hver infrastrukturendring.
- RTO-måling er den viktigste outputen — dokumenter faktisk vs. planlagt RTO for å identifisere gap.

View file

@ -0,0 +1,285 @@
# Compliance Requirements for BCDR in Norwegian Public Sector
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Norske offentlige organisasjoner som bruker AI-tjenester i Azure er underlagt et komplekst regulatorisk landskap for Business Continuity and Disaster Recovery. Kravene kommer fra nasjonale lover (Forvaltningsloven, Sikkerhetsloven), EU-forordninger (GDPR, AI Act), sektorkrav (NSM, Digdir) og internasjonale standarder (ISO 22301, ISO 27001).
BCDR for AI-systemer i offentlig sektor har særlige utfordringer: data residency-krav begrenser hvilke Azure-regioner som kan brukes for DR, taushetsplikt stiller krav til kryptering og tilgangskontroll også i DR-scenarier, og Utredningsinstruksens krav til konsekvensanalyse påvirker hvordan DR-strategier velges og dokumenteres.
Denne referansen sammenfatter de viktigste regulatoriske kravene og gir praktisk veiledning for hvordan de påvirker BCDR-design for AI-løsninger i Azure.
## Forvaltningslovens krav til kontinuitet
### Relevant lovgivning
| Lov/forskrift | Krav | Påvirkning på BCDR |
|---------------|------|-------------------|
| Forvaltningsloven §11a | Forsvarlig saksbehandlingstid | AI-systemer som støtter saksbehandling må ha definert RTO |
| Forvaltningsloven §13 | Taushetsplikt | DR-data må krypteres, tilgang begrenses |
| eForvaltningsforskriften §15 | Tilgang til elektroniske tjenester | Digitale tjenester skal være tilgjengelige |
| Arkivlova §6 | Bevaring av arkivmateriale | AI-generert innhold kan være arkivverdig |
| Offentleglova §6 | Innsynskrav | AI-systemer må kunne levere data for innsyn |
### Krav til konsekvensanalyse
Utredningsinstruksen (KMD 2016) krever at statlige tiltak utredes før beslutning. For BCDR betyr dette:
```markdown
## Konsekvensutredning for BCDR-strategi
### 1. Problem og mål
- Hva er risikoen ved manglende DR for AI-systemet?
- Hva er målet med DR-strategien (RTO/RPO)?
### 2. Alternativer
| Alternativ | RTO | RPO | Årlig kostnad | Risiko |
|-----------|-----|-----|---------------|--------|
| 0: Ingen DR | N/A | N/A | 0 kr | Høy — fullstendig tjenestebortfall |
| 1: Backup & Restore | 24t | 24t | 50,000 kr | Middels — lang nedetid |
| 2: Warm Standby | 15 min | 5 min | 300,000 kr | Lav — kort nedetid |
| 3: Active-Active | ~0 | ~0 | 600,000 kr | Svært lav — nær null nedetid |
### 3. Konsekvenser
- Økonomiske: Kostnad ved nedetid vs. DR-kostnad
- Administrative: Krav til bemanning og prosedyrer
- Samfunnsmessige: Påvirkning på brukere av offentlige tjenester
### 4. Anbefaling
[Anbefalt alternativ med begrunnelse]
```
## GDPR og data residency-krav
### GDPR Artikkel 32 — Sikkerhet ved behandling
GDPR krever "evnen til å sikre vedvarende konfidensialitet, integritet, tilgjengelighet og robusthet" for behandlingssystemer. For BCDR betyr dette:
| GDPR-krav | BCDR-implikasjon | Azure-tiltak |
|-----------|-----------------|--------------|
| Art. 32(1)(b) | Tilgjengelighet og robusthet | Multi-region DR |
| Art. 32(1)(c) | Evne til å gjenopprette tilgang | Definerte RTO/RPO |
| Art. 32(1)(d) | Regelmessig testing av sikkerhetstiltak | DR-drills |
| Art. 32(2) | Risikobasert tilnærming | BIA som grunnlag for DR |
### Data Residency og geo-replikering
```markdown
## Godkjente Azure-regioner for norsk offentlig sektor
### Primærregioner (anbefalt)
- Norway East (Oslo) — Norsk datasuverenitetsregion
- Norway West (Stavanger) — Sekundær norsk region
### Sekundærregioner (DR, godkjent EU/EØS)
- Sweden Central (Gävle) — Typisk DR-region for Norway East
- North Europe (Dublin) — Alternativ EU-region
- West Europe (Amsterdam) — Alternativ EU-region
### Ikke godkjent uten tilleggsanalyse
- UK-regioner — Etter Brexit, krever separat vurdering
- US-regioner — Schrems II-problematikk
- APAC-regioner — Ikke relevant for offentlig sektor
```
### Overføringsmekanismer for DR-data
| Scenario | Overføringsmekanisme | Krav |
|----------|---------------------|------|
| Norway East → Sweden Central | EU/EØS intern | Ingen tilleggstiltak |
| Norway East → UK | SCCs + TIA | Tilleggsanalyse |
| Azure GRS (automatisk) | Avhenger av region-par | Verifiser at sekundær er EU/EØS |
| Backup til annen region | GDPR Art. 46 | Dokumentér overføringsgrunnlag |
### DPIA for BCDR
```markdown
## DPIA — BCDR-spesifikke vurderinger
### Tilgjengelighetsvurdering
- Hva er konsekvensen for registrerte ved tap av tilgang til AI-systemet?
- Kan vedtak fattes manuelt som fallback?
- Finnes det risiko for diskriminering ved degradert AI-funksjonalitet?
### Data i transit
- Er all DR-replikering kryptert (TLS 1.2+)?
- Går data gjennom tredjeland under replikering?
- Finnes det logger over alle dataoverføringer?
### Tredjepartstilgang
- Har Microsoft tilgang til data i DR-regionen?
→ Ja, men begrenset av Customer Lockbox og JIT
- Er det andre behandlere involvert i DR-prosessen?
→ Dokumentér i databehandleravtale
### Tiltak
| Risiko | Tiltak | Ansvarlig |
|--------|--------|-----------|
| Data i feil region | Verifiser GRS-konfiguration | Platform team |
| Ukryptert replikering | Enforce TLS i transit | Security team |
| Tap av tilgangskontroll | RBAC i DR-region | IAM team |
```
## NSMs sikkerhetsveiledninger for kritisk infrastruktur
### NSMs grunnprinsipper relevante for BCDR
| Prinsipp | Krav | BCDR-tiltak |
|----------|------|-------------|
| 2.1 Kartlegg leveranser, systemer og avhengigheter | Forstå AI-systemets avhengigheter | Avhengighetskartlegging for alle AI-komponenter |
| 2.2 Klassifiser virksomhetens verdier | Vurder kritikalitet av AI-data | BIA med klassifisering |
| 2.3 Risikovurder virksomhetens digitale verdier | ROS-analyse | Inkluder tilgjengelighetstrusler |
| 3.1 Beskytt virksomhetens verdier | Sikkerhet i DR-miljø | Identisk sikkerhetskonfigurasjon |
| 4.1 Logg og overvåk | Loggføring også under DR | Sentralisert logging cross-region |
| 4.3 Planlegg for å håndtere hendelser | Hendelseshåndtering | Runbooks og kommunikasjonsplaner |
### NSMs krav til beredskapsplanlegging
```markdown
## Beredskapskrav for AI-systemer (NSM)
1. **Risikovurdering (ROS)**
- Identifiser trusler mot AI-systemets tilgjengelighet
- Vurder sannsynlighet og konsekvens
- Definer akseptabelt risikonivå
2. **Beredskapsplan**
- Dokumenterte gjenopprettingsprosedyrer
- Definerte roller og ansvar
- Kommunikasjonsprosedyrer
- Eskaleringsrutiner
3. **Øvelser**
- Minimum årlig fullskala DR-øvelse
- Kvartalsvis tabletop-øvelse
- Dokumentasjon av resultater og forbedringstiltak
4. **Rapportering**
- Avviksrapportering til leder
- Sikkerhetshendelsesrapportering til NSM/NCSC
- Årlig statusrapport til ledelsen
```
## Sektorspesifikke reguleringer
### Helse (Normen)
| Krav | Beskrivelse | BCDR-implikasjon |
|------|-------------|-----------------|
| Tilgjengelighet | Kritiske systemer: 99.5% uptime | Multi-AZ minimum |
| Gjenoppretting | RTO < 4 timer for kritiske | Warm standby |
| Personvern | Helseopplysninger er sensitive | Kryptering i alle regioner |
| Logging | All tilgang til pasientdata logges | Cross-region logging |
### Finans (Finanstilsynet)
| Krav | Beskrivelse | BCDR-implikasjon |
|------|-------------|-----------------|
| IKT-forskriften §4 | Adekvat IKT-beredskap | Dokumentert DR-plan |
| IKT-forskriften §7 | Drift og overvåking | 24/7 monitoring |
| DORA (EU) | Digital Operational Resilience | Regelmessig DR-testing |
### Kommunal sektor
| Krav | Beskrivelse | BCDR-implikasjon |
|------|-------------|-----------------|
| Kommuneloven §25-1 | Internkontroll | BCDR som del av IK |
| Digitaliseringsrundskrivet | Digital tilgjengelighet | Definerte SLA |
| KS anbefalinger | IKT-sikkerhet i kommuner | Praktisk veiledning |
## Audit og dokumentasjonskrav
### Påkrevd dokumentasjon
```markdown
## BCDR Dokumentasjonspakke for Audit
### 1. Strategidokument
- [ ] BCDR-policy godkjent av ledelsen
- [ ] Kritikalitetsklassifisering av AI-systemer
- [ ] RTO/RPO-mål per system/komponent
- [ ] Valgt DR-strategi med begrunnelse
### 2. Teknisk dokumentasjon
- [ ] Arkitekturtegning med DR-konfigurasjon
- [ ] Nettverksdiagram inkl. failover-ruter
- [ ] Data flow diagram med replikering
- [ ] Konfigurasjonsdetaljer per Azure-tjeneste
### 3. Operasjonell dokumentasjon
- [ ] DR-runbooks (failover og failback)
- [ ] Eskaleringsmatrise
- [ ] Kommunikasjonsplan
- [ ] Kontaktliste (primær og backup)
### 4. Test og verifisering
- [ ] DR-testplan med frekvens og omfang
- [ ] Testrapporter fra gjennomførte DR-drills
- [ ] Avvikslogg med korrigerende tiltak
- [ ] Måloppnåelse (faktisk vs. planlagt RTO/RPO)
### 5. Compliance-dokumentasjon
- [ ] DPIA med BCDR-vurderinger
- [ ] Databehandleravtale som dekker DR
- [ ] Overføringsgrunnlag for cross-region data
- [ ] Årlig compliance-rapport
```
### Revisjons-sjekkliste
```markdown
## Årlig BCDR Revisjons-sjekkliste
### Governance
| # | Kontrollpunkt | Status | Kommentar |
|---|---------------|--------|-----------|
| 1 | BCDR-policy er oppdatert og godkjent | ☐ | |
| 2 | Roller og ansvar er dokumentert | ☐ | |
| 3 | Ledelsen er informert om DR-status | ☐ | |
### Teknisk
| # | Kontrollpunkt | Status | Kommentar |
|---|---------------|--------|-----------|
| 4 | DR-konfigurasjon matcher dokumentasjon | ☐ | |
| 5 | Replikering fungerer korrekt | ☐ | |
| 6 | Backup er verifisert | ☐ | |
| 7 | IaC-maler er oppdatert | ☐ | |
### Testing
| # | Kontrollpunkt | Status | Kommentar |
|---|---------------|--------|-----------|
| 8 | Fullskala DR-test gjennomført siste 12 mnd | ☐ | |
| 9 | RTO-mål oppnådd i test | ☐ | |
| 10 | RPO-mål oppnådd i test | ☐ | |
| 11 | Forbedringstiltak implementert | ☐ | |
### Compliance
| # | Kontrollpunkt | Status | Kommentar |
|---|---------------|--------|-----------|
| 12 | GDPR-krav ivaretatt i DR | ☐ | |
| 13 | Data residency verifisert | ☐ | |
| 14 | NSM-krav etterlevd | ☐ | |
| 15 | Sektorspesifikke krav dekket | ☐ | |
```
## Referanser
- [Azure for secure worldwide public sector cloud adoption](https://learn.microsoft.com/en-us/azure/azure-government/documentation-government-overview-wwps) — Data residency og compliance
- [Support your GDPR program with Accountability Readiness Checklists](https://learn.microsoft.com/en-us/compliance/regulatory/gdpr-arc) — GDPR compliance
- [Geographic data residency in Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/geo-data-residency) — Data residency for Copilot
- [Recommendations for defining reliability targets](https://learn.microsoft.com/en-us/azure/well-architected/reliability/metrics) — SLO/RTO/RPO-definisjoner
- [Azure compliance offerings](https://learn.microsoft.com/en-us/azure/compliance/) — Azure compliance-dokumentasjon
- [NSM — Grunnprinsipper for IKT-sikkerhet](https://nsm.no/grunnprinsipper-ikt) — Norske sikkerhetskrav
## For Cosmo
- **Bruk denne referansen** når kunden er en norsk offentlig organisasjon og trenger veiledning om regulatoriske krav til BCDR for AI-systemer.
- Start alltid med å identifisere hvilke sektorkrav som gjelder (helse, finans, kommunal, statlig) — dette påvirker RTO/RPO-krav direkte.
- Data residency er en showstopper: ALDRI foreslå DR-regioner utenfor EU/EØS for norsk offentlig sektor uten eksplisitt juridisk vurdering.
- Påminn om at GDPR Art. 32 eksplisitt nevner tilgjengelighet — mangelfull BCDR kan være et GDPR-brudd.
- Utredningsinstruksens krav til alternativanalyse betyr at kunden bør evaluere minst 3 BCDR-alternativer med kost/nytte-vurdering.

View file

@ -0,0 +1,335 @@
# Cost Analysis and Optimization for DR Configurations
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Kostnadsanalyse av BCDR-løsninger for AI-systemer er avgjørende for å sikre at organisasjonen investerer riktig i resiliens. DR-kostnader kan utgjøre alt fra 2% til 100% av primære driftskostnader, avhengig av valgt strategi. For AI-workloads er kostnadene spesielt høye fordi tjenester som Azure OpenAI (Provisioned Throughput), AI Search og GPU-compute er dyre.
Azure Well-Architected Framework anbefaler at DR-kostnad skal stå i proporsjonal sammenheng med forretningsverdien av systemet og konsekvensene av nedetid. Tier 0 (Mission Critical) systemer rettferdiggjør høye DR-kostnader, mens Tier 3 (Administrative) systemer bør minimere kostnadene.
For norsk offentlig sektor krever Utredningsinstruksen at alternative løsninger evalueres med kost/nytte-analyse. BCDR-valg bør dokumenteres med tydelig kostnadssammenligning og forretningsbegrunnelse.
## Total Cost of Ownership-beregning
### TCO-modell for AI BCDR
```python
# TCO-kalkulator for AI DR-konfigurasjon
from dataclasses import dataclass
from typing import Dict
@dataclass
class AIDRCostModel:
"""Calculate Total Cost of Ownership for AI DR configuration."""
# Primær region kostnader (monthly NOK)
openai_primary_monthly: float = 0
search_primary_monthly: float = 0
cosmos_primary_monthly: float = 0
app_service_primary_monthly: float = 0
storage_primary_monthly: float = 0
networking_primary_monthly: float = 0
def calculate_dr_cost(self, strategy: str) -> Dict:
"""Calculate DR cost for given strategy."""
primary_total = sum([
self.openai_primary_monthly,
self.search_primary_monthly,
self.cosmos_primary_monthly,
self.app_service_primary_monthly,
self.storage_primary_monthly,
self.networking_primary_monthly
])
if strategy == "active-active":
dr_costs = {
"openai": self.openai_primary_monthly * 1.0,
"search": self.search_primary_monthly * 1.0,
"cosmos": self.cosmos_primary_monthly * 0.5, # Multi-region included
"app_service": self.app_service_primary_monthly * 1.0,
"storage": self.storage_primary_monthly * 0.3, # GRS overhead
"networking": self.networking_primary_monthly * 0.5, # Cross-region
"bandwidth": primary_total * 0.02 # ~2% for replication
}
elif strategy == "warm-standby":
dr_costs = {
"openai": self.openai_primary_monthly * 0.3, # Pay-per-token, lower usage
"search": self.search_primary_monthly * 0.67, # 2/3 replicas
"cosmos": self.cosmos_primary_monthly * 0.3, # Autoscale baseline
"app_service": self.app_service_primary_monthly * 0.33, # 1 instance
"storage": self.storage_primary_monthly * 0.3,
"networking": self.networking_primary_monthly * 0.2,
"bandwidth": primary_total * 0.01
}
elif strategy == "cold-standby":
dr_costs = {
"openai": 0, # Redeploy on demand
"search": 0, # Rebuild on demand
"cosmos": self.cosmos_primary_monthly * 0.1, # Backup only
"app_service": 0, # Deploy on demand
"storage": self.storage_primary_monthly * 0.3, # GRS for data
"networking": self.networking_primary_monthly * 0.05,
"bandwidth": primary_total * 0.005
}
elif strategy == "backup-restore":
dr_costs = {
"openai": 0,
"search": 0,
"cosmos": self.cosmos_primary_monthly * 0.05,
"app_service": 0,
"storage": self.storage_primary_monthly * 0.15, # Backup storage
"networking": 0,
"bandwidth": 0
}
dr_total = sum(dr_costs.values())
return {
"strategy": strategy,
"primary_monthly_nok": round(primary_total),
"dr_monthly_nok": round(dr_total),
"total_monthly_nok": round(primary_total + dr_total),
"dr_percentage": round(dr_total / primary_total * 100, 1),
"dr_annual_nok": round(dr_total * 12),
"breakdown": {k: round(v) for k, v in dr_costs.items()}
}
# Eksempel for typisk norsk offentlig AI-løsning
model = AIDRCostModel(
openai_primary_monthly=25000, # GPT-4o, ~500K tokens/dag
search_primary_monthly=15000, # Standard S1, 3 replicas
cosmos_primary_monthly=8000, # Multi-region, 10K RU/s
app_service_primary_monthly=12000, # P3v3 x 3
storage_primary_monthly=3000, # 1 TB GZRS
networking_primary_monthly=5000 # Front Door + VNet
)
for strategy in ["active-active", "warm-standby", "cold-standby", "backup-restore"]:
result = model.calculate_dr_cost(strategy)
print(f"\n{strategy.upper()}")
print(f" DR kostnad: {result['dr_monthly_nok']:,} NOK/mnd ({result['dr_percentage']}%)")
print(f" Total: {result['total_monthly_nok']:,} NOK/mnd")
print(f" Årlig DR: {result['dr_annual_nok']:,} NOK")
```
### Kostnadsoversikt per strategi
| Komponent | Primær | Active-Active | Warm Standby | Cold Standby | Backup Only |
|-----------|--------|---------------|-------------|-------------|-------------|
| Azure OpenAI | 25,000 | 25,000 | 7,500 | 0 | 0 |
| AI Search | 15,000 | 15,000 | 10,000 | 0 | 0 |
| Cosmos DB | 8,000 | 4,000 | 2,400 | 800 | 400 |
| App Service | 12,000 | 12,000 | 4,000 | 0 | 0 |
| Storage | 3,000 | 900 | 900 | 900 | 450 |
| Networking | 5,000 | 2,500 | 1,000 | 250 | 0 |
| Bandwidth | — | 1,360 | 680 | 340 | 0 |
| **DR total/mnd** | — | **60,760** | **26,480** | **2,290** | **850** |
| **% av primær** | — | **89%** | **39%** | **3%** | **1%** |
| **RTO** | — | ~0 | 515 min | 3060 min | Timer |
| **RPO** | — | ~0 | Minutter | Timer | 24 timer |
*Alle beløp i NOK, estimat for typisk offentlig sektor AI-løsning.*
## RTO/RPO vs. kostnads trade-off analyse
### Beslutningsmatrise
```
Kostnad (NOK/mnd)
│ Active-Active
│ ■ (60K)
│ Warm Standby
│ ■ (26K)
│ Cold Standby
│ ■ (2.3K)
│ Backup/Restore
│ ■ (850)
└─────────────────────────────────────────────────── RTO
0 5min 15min 30min 1h 4h 24h
```
### Break-even analyse
```markdown
## Når er Active-Active verdt det?
Merkostnad Active-Active vs. Warm Standby:
60,760 - 26,480 = 34,280 NOK/mnd = 411,360 NOK/år
For at Active-Active skal være verdt det, må kostnaden
av nedetid overstige denne merkostnaden:
Nedetid-kostnad per hendelse = (RTO_warm - RTO_active) × Kostnad per minutt
Forventet besparelse = Nedetid-kostnad × Antall hendelser per år
Eksempel:
- RTO forskjell: 15 min vs. ~0 = 15 min
- Kostnad per minutt nedetid: 5,000 NOK (tapt produktivitet, omdømme)
- Antall hendelser per år: 2
Besparelse = 15 min × 5,000 NOK × 2 = 150,000 NOK/år
Merkostnad 411,360 > Besparelse 150,000 → Warm Standby er bedre valg
Break-even: 411,360 / (15 × 5,000) = 5.5 hendelser/år
→ Trenger 6+ hendelser/år for at Active-Active lønner seg
```
## Reserved Capacity vs. On-Demand prising
### Besparelser med Reserved Instances
| Tjeneste | On-Demand/mnd | 1-år RI/mnd | 3-år RI/mnd | Besparelse 1-år | Besparelse 3-år |
|----------|-------------|-------------|-------------|----------------|----------------|
| App Service P3v3 | 12,000 | 7,800 | 5,400 | 35% | 55% |
| AI Search S1 (3 rep) | 15,000 | 9,750 | 6,750 | 35% | 55% |
| Azure OpenAI PTU (50) | 50,000 | 35,000 | — | 30% | — |
| Redis Premium P1 | 4,500 | 3,150 | 2,250 | 30% | 50% |
### RI-strategi for DR
```markdown
## Anbefalte reservasjoner for DR
### Active-Active DR
- RI for ALLE tjenester i begge regioner (full besparelse)
- Anbefaling: 1-år RI minimum, 3-år for stabile workloads
### Warm Standby DR
- RI for baseline-kapasitet i DR-region (lavere tier)
- On-demand for burst/scale-up kapasitet
- Anbefaling: 1-år RI for baseline, on-demand for topper
### Cold Standby DR
- INGEN RI for DR-region (ressurser kjører ikke)
- RI kun for primær region
- Anbefaling: Bruk Azure Savings Plans for fleksibilitet
### Savings Plans alternativ
Azure Savings Plans gir 1-år eller 3-år commitment
med fleksibilitet til å bruke kapasiteten i hvilken som helst
region — ideelt for DR der regionen kan endres.
```
## Cross-region bandwidth-kostnader
### Bandwidth-prising mellom Azure-regioner
| Datatype | Volume/mnd | Pris/GB | Kostnad/mnd |
|----------|-----------|---------|-------------|
| Cosmos DB replikering | 50 GB | Inkludert | 0 |
| Blob Storage GRS | 100 GB | ~0.70 NOK | 70 |
| AI Search index sync | 10 GB | ~0.70 NOK | 7 |
| Application data | 200 GB | ~0.70 NOK | 140 |
| **Total bandwidth** | **360 GB** | — | **~217 NOK** |
*Intra-Europa bandwidth er relativt rimelig. Kostnaden øker betydelig for cross-kontinent replikering.*
### Optimalisering av bandwidth-kostnader
```markdown
## Bandwidth-optimaliseringsstrategier
1. **Komprimering**: Aktiver gzip/brotli for all cross-region trafikk
- Typisk besparelse: 6080% på tekstbasert data
2. **Delta-replikering**: Synkroniser kun endringer, ikke full kopi
- Bruk Azure Blob Storage Change Feed
- Event-driven sync i stedet for full re-indeksering
3. **Batch vs. real-time**: Batchvise oppdateringer reduserer overhead
- Samle opp endringer og synkroniser hvert 5. minutt
4. **CDN for statisk innhold**: Bruk Azure CDN for dokumenter
- Reduserer cross-region trafikk for hyppig leste filer
```
## Kostnadsoptimalisering og Reserved Instances
### Azure Cost Management dashboard
```bash
# Opprett kostnadsrapport for DR-ressurser
az costmanagement export create \
--name "dr-cost-report" \
--scope "/subscriptions/{sub}/resourceGroups/rg-ai-dr" \
--type "ActualCost" \
--timeframe "MonthToDate" \
--storage-account "stacostmgmt" \
--storage-container "cost-reports" \
--recurrence "Monthly" \
--recurrence-period '{"from": "2026-01-01", "to": "2026-12-31"}'
# Sett budsjett med varsler
az consumption budget create \
--budget-name "ai-dr-budget-2026" \
--amount 400000 \
--category "Cost" \
--time-grain "Annually" \
--time-period '{"Start": "2026-01-01", "End": "2026-12-31"}' \
--resource-groups "rg-ai-dr" \
--notifications '{
"Warning50": {"enabled": true, "operator": "GreaterThan", "threshold": 50,
"contactEmails": ["platform@org.no"]},
"Warning80": {"enabled": true, "operator": "GreaterThan", "threshold": 80,
"contactEmails": ["platform@org.no", "management@org.no"]},
"Critical100": {"enabled": true, "operator": "GreaterThan", "threshold": 100,
"contactEmails": ["platform@org.no", "management@org.no", "cto@org.no"]}
}'
```
### Kvartalsvis kostnadsrapport-mal
```markdown
## BCDR Kostnadsrapport — Q[X] 2026
### Oppsummering
| Kategori | Budsjett | Faktisk | Avvik |
|----------|---------|--------|-------|
| DR infrastruktur | X NOK | X NOK | X% |
| Bandwidth | X NOK | X NOK | X% |
| DR-testing | X NOK | X NOK | X% |
| **Total** | **X NOK** | **X NOK** | **X%** |
### DR-hendelser dette kvartalet
- Antall failover-initieringer: X
- Gjennomsnittlig RTO oppnådd: X min
- Estimert verdi av DR (unngått nedetid): X NOK
### Optimaliseringsmuligheter
1. [Identifisert mulighet med estimert besparelse]
2. [...]
### Anbefalinger
- [Anbefalte endringer med kostnadspåvirkning]
```
## Referanser
- [Optimize your recovery costs](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#optimize-your-recovery-costs) — WAF kostnadsoptimalisering for DR
- [Azure Site Recovery pricing](https://azure.microsoft.com/pricing/details/site-recovery/) — Prising for Site Recovery
- [Azure bandwidth pricing](https://azure.microsoft.com/pricing/details/bandwidth/) — Bandwidth-priser mellom regioner
- [Azure pricing calculator](https://azure.microsoft.com/pricing/calculator/) — Generell priskalkulator
- [Microsoft Cost Management](https://learn.microsoft.com/en-us/azure/cost-management-billing/) — Kostnadsovervåking
- [Azure Savings Plans overview](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/) — Flexible reservasjoner
## For Cosmo
- **Bruk denne referansen** når kunden trenger kostnadsestimat for BCDR-løsninger, eller når de skal sammenligne DR-strategier.
- Warm standby er sweet spot for de fleste offentlige AI-løsninger — 2540% merkostnad for minutter RTO.
- Vis alltid break-even analyse: sammenlign DR-merkostnaden med estimert kostnad ved nedetid for å rettferdiggjøre investeringen.
- Azure OpenAI: Pay-per-token i DR-region er nesten alltid bedre enn PTU fordi DR-trafikken er lav under normal drift.
- For Utredningsinstruksen: Presenter alltid minimum 3 alternativer (f.eks. cold/warm/active-active) med kost/nytte-vurdering.

View file

@ -0,0 +1,306 @@
# Data Replication Patterns for AI Systems
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Datareplikering er fundamentet for Business Continuity i AI-systemer. AI-arbeidsbelastninger har spesielle krav til datakonsistens, latens og tilgjengelighet som gjør valg av replikasjonsmekanisme særlig viktig. En RAG-løsning må for eksempel replikere både search-indekser, embedding-vektorer, kildedokumenter og konversasjonshistorikk — hver med ulike konsistens- og latensbehov.
Azure tilbyr flere replikasjonsmønstre: synkron replikering innenfor tilgjengelighetssoner (Availability Zones), asynkron geo-replikering til sekundærregioner, og applikasjonsbasert replikering for tjenester som ikke har innebygd DR. Valget mellom disse mønstrene påvirker direkte RPO, ytelse og kostnad.
For norsk offentlig sektor er det spesielt viktig å forstå data residency-implikasjoner av geo-replikering. Replikering til en sekundærregion må skje innenfor godkjente geografiske grenser (EU/EØS), og organisasjonen må dokumentere dataflyter i sine behandlingsprotokoll iht. GDPR artikkel 30.
## Synkron vs. asynkron replikering
### Synkron replikering
Ved synkron replikering bekreftes ikke en skriveoperasjon som fullført før dataene er skrevet til alle replikaer. Dette gir null datatap (RPO = 0), men øker skrivelatens.
| Egenskap | Synkron | Asynkron |
|----------|---------|----------|
| RPO | 0 | > 0 (sekunder til minutter) |
| Skrivelatens | Høyere (avhenger av avstand) | Lavere |
| Leseytelse | Kan lese fra replikaer | Kan lese fra replikaer (eventual consistency) |
| Kostnad | Høyere (alltid aktive replikaer) | Lavere |
| Typisk bruk | Intra-region (AZ), mission critical | Cross-region DR |
### Azure Storage replikeringsalternativer
```
LRS → 3 kopier i samme datasenter
ZRS → 3 kopier på tvers av Availability Zones (synkron)
GRS → LRS + asynkron til sekundær region (LRS der)
GZRS → ZRS + asynkron til sekundær region (LRS der)
RA-GRS/RA-GZRS → Tillegg: lesetilgang til sekundær region
```
### Replikeringsvalg per AI-komponent
| AI-komponent | Anbefalt replikering | Begrunnelse |
|--------------|---------------------|-------------|
| Azure Blob Storage (dokumenter) | GZRS / RA-GZRS | Best balance mellom tilgjengelighet og DR |
| Azure Cosmos DB (state/session) | Multi-region writes | Automatisk geo-replikering med ~0 RPO |
| Azure SQL Database | Active geo-replication | Asynkron med ~5 sek RPO |
| Azure AI Search indekser | Manuell dual-indexing | Ingen innebygd replikering |
| Azure OpenAI (modell-config) | IaC-basert redeploy | Stateless tjeneste |
| Azure Key Vault | Automatisk failover | Microsoft-managed geo-replikering |
## Active-Active og Active-Passive mønstre
### Active-Active pattern
I et Active-Active oppsett er begge regioner aktive og mottar trafikk. Dette krever:
- Identisk infrastruktur i begge regioner
- Load balancer for trafikk-distribusjon
- Konflikthåndtering for samtidige skrivinger
```
┌──────────────┐ ┌────────────────┐ ┌──────────────┐
│ Brukere │────▶│ Azure Front │────▶│ Region A │
│ │ │ Door / TM │ │ (Active) │
│ │ │ Latency-based │────▶│ Region B │
│ │ │ routing │ │ (Active) │
└──────────────┘ └────────────────┘ └──────────────┘
```
**Azure Cosmos DB Active-Active eksempel:**
```bash
# Opprett Cosmos DB konto med multi-region writes
az cosmosdb create \
--name "cosmos-ai-state" \
--resource-group "rg-ai-prod" \
--locations regionName="norwayeast" failoverPriority=0 isZoneRedundant=true \
--locations regionName="swedencentral" failoverPriority=1 isZoneRedundant=true \
--enable-multiple-write-locations true \
--default-consistency-level "Session"
# Verifiser replikering
az cosmosdb show \
--name "cosmos-ai-state" \
--resource-group "rg-ai-prod" \
--query "writeLocations[].{Region:locationName, Status:failoverPriority}"
```
### Active-Passive pattern
Active-Passive er mer kostnadseffektivt og enklere å implementere. Primærregionen håndterer all trafikk; sekundærregionen overtar kun ved failover.
**Warm Standby varianter:**
| Variant | Sekundær region | RTO | Kostnad |
|---------|----------------|-----|---------|
| Hot Standby | Full kapasitet, mottar replikert data | Sekunder | Høyest |
| Warm Standby | Minimal kapasitet, auto-scales ved failover | Minutter | Middels |
| Cold Standby | Kun IaC-templates, ingen kjørende ressurser | Timer | Lavest |
```python
# Active-Passive med Azure Traffic Manager health probes
# Bicep template for Traffic Manager profil
"""
resource trafficManagerProfile 'Microsoft.Network/trafficmanagerprofiles@2022-04-01' = {
name: 'tm-ai-service'
location: 'global'
properties: {
profileStatus: 'Enabled'
trafficRoutingMethod: 'Priority'
monitorConfig: {
protocol: 'HTTPS'
port: 443
path: '/health'
intervalInSeconds: 10
timeoutInSeconds: 5
toleratedNumberOfFailures: 3
}
endpoints: [
{
name: 'primary-norwayeast'
type: 'Microsoft.Network/trafficmanagerprofiles/azureEndpoints'
properties: {
targetResourceId: primaryAppService.id
priority: 1
weight: 1
}
}
{
name: 'secondary-swedencentral'
type: 'Microsoft.Network/trafficmanagerprofiles/azureEndpoints'
properties: {
targetResourceId: secondaryAppService.id
priority: 2
weight: 1
}
}
]
}
}
"""
```
## Konsistensmodeller og eventual consistency
### CAP-teoremet og AI-systemer
AI-systemer må velge mellom konsistens (C), tilgjengelighet (A) og partisjontoleranse (P). For de fleste AI-workloads er eventual consistency akseptabelt.
### Cosmos DB konsistensmodeller
| Modell | Garanti | Latens | Anbefalt for |
|--------|---------|--------|-------------|
| Strong | Lineariserbar | Høyest | Finansielle transaksjoner |
| Bounded Staleness | K versjoner eller T tid | Høy | Leaderboard, tellere |
| Session | Konsistent innen sesjon | Middels | Chatbot state (anbefalt) |
| Consistent Prefix | Aldri out-of-order | Lav | Aktivitetslogg |
| Eventual | Ingen garanti om rekkefølge | Lavest | Analytics, rapportering |
```csharp
// C# eksempel: Session consistency for AI chatbot state
using Microsoft.Azure.Cosmos;
var cosmosClient = new CosmosClient(
connectionString,
new CosmosClientOptions
{
ConsistencyLevel = ConsistencyLevel.Session,
ApplicationPreferredRegions = new List<string>
{
Regions.NorwayEast,
Regions.SwedenCentral
}
});
// Hent session token fra response
var response = await container.ReadItemAsync<ConversationState>(
id: sessionId,
partitionKey: new PartitionKey(userId));
string sessionToken = response.Headers.Session;
// Bruk session token for konsistent lesing i neste request
var options = new ItemRequestOptions { SessionToken = sessionToken };
```
## Konfliktløsningsstrategier
### Last-Writer-Wins (LWW)
Standard konflikthåndtering i Cosmos DB. Basert på `_ts` (timestamp) feltet — siste skriving vinner.
### Custom conflict resolution
```javascript
// Cosmos DB custom conflict resolution stored procedure
function resolveConflict(incomingRecord, existingRecord, isTombstone, conflictingRecords) {
// For AI chatbot: merge conversation history
if (incomingRecord.messageHistory && existingRecord.messageHistory) {
// Kombiner meldingshistorikk fra begge regioner
var merged = existingRecord.messageHistory.concat(
incomingRecord.messageHistory.filter(
m => !existingRecord.messageHistory.some(e => e.id === m.id)
)
);
// Sorter kronologisk
merged.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
existingRecord.messageHistory = merged;
existingRecord._ts = Math.max(incomingRecord._ts, existingRecord._ts);
}
var context = getContext();
var collection = context.getCollection();
collection.replaceDocument(existingRecord._self, existingRecord);
}
```
### Konfliktmønstre for AI-data
| Datatype | Konfliktrisiko | Anbefalt strategi |
|----------|---------------|-------------------|
| Brukerpreferanser | Lav | Last-Writer-Wins |
| Konversasjonshistorikk | Middels | Merge med dedup |
| Feedback/ratings | Lav | Append-only |
| Search indeks-oppdateringer | Høy | Source-of-truth rebuild |
| Model config | Lav | Version-basert (IaC) |
## Monitoring av replikasjonsforsinkelse og helse
### Azure Monitor for replication health
```kusto
// KQL: Overvåk Cosmos DB replication lag
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.DOCUMENTDB"
| where Category == "DataPlaneRequests"
| summarize
AvgLatencyMs = avg(duration_s * 1000),
MaxLatencyMs = max(duration_s * 1000),
P99LatencyMs = percentile(duration_s * 1000, 99)
by bin(TimeGenerated, 5m), regionName_s
| order by TimeGenerated desc
```
```kusto
// KQL: Azure Storage Last Sync Time for GRS
StorageBlobLogs
| where OperationName == "GetBlobServiceProperties"
| extend lastSyncTime = tostring(parse_json(ResponseBody).GeoReplication.LastSyncTime)
| project TimeGenerated, lastSyncTime, StatusCode
| order by TimeGenerated desc
```
### Alert-regler for replication health
```bash
# Azure Monitor alert: Cosmos DB replication lag > 5 sekunder
az monitor metrics alert create \
--name "cosmosdb-replication-lag-alert" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.DocumentDB/databaseAccounts/cosmos-ai-state" \
--condition "avg ReplicationLatency > 5000" \
--window-size 5m \
--evaluation-frequency 1m \
--severity 2 \
--action-group "ag-oncall-team"
# Azure Storage: Last Sync Time alert
az monitor metrics alert create \
--name "storage-geo-lag-alert" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Storage/storageAccounts/staiprod" \
--condition "avg GeoReplicationLag > 900" \
--window-size 15m \
--evaluation-frequency 5m \
--severity 2 \
--action-group "ag-oncall-team"
```
### Dashboard-metrikker
| Metrikk | Terskel (Warning) | Terskel (Critical) | Tjeneste |
|---------|-------------------|-------------------|----------|
| Replication Latency | > 2 sek | > 10 sek | Cosmos DB |
| Geo Replication Lag | > 5 min | > 15 min | Azure Storage |
| Last Sync Time age | > 10 min | > 30 min | Azure Storage GRS |
| Active Geo-Repl lag | > 10 sek | > 60 sek | Azure SQL |
| Search index sync delta | > 100 docs | > 1000 docs | AI Search (custom) |
## Referanser
- [Azure Storage redundancy](https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy) — LRS, ZRS, GRS, GZRS-oversikt
- [Azure Storage Geo Priority Replication](https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy-priority-replication) — SLA-backed RPO
- [Active geo-replication for Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/active-geo-replication-overview) — SQL Database replikering
- [Azure Cosmos DB global distribution](https://learn.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally) — Multi-region writes og consistency
- [What are redundancy, replication, and backup?](https://learn.microsoft.com/en-us/azure/reliability/concept-redundancy-replication-backup) — Grunnleggende konsepter
- [Use geo-redundancy to design highly available applications](https://learn.microsoft.com/en-us/azure/storage/common/geo-redundant-design) — RA-GRS/RA-GZRS designmønstre
- [Multi-region deployments in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-multi-region) — AI Search multi-region
## For Cosmo
- **Bruk denne referansen** når kunden trenger hjelp med å velge replikasjonsmekanismer for AI-løsninger, eller når de designer multi-region arkitekturer.
- Anbefal alltid GZRS (ikke GRS) for AI-workloads der Availability Zones er tilgjengelig — det gir best kombinasjon av intra-region HA og cross-region DR.
- For Cosmos DB: Session consistency er nesten alltid riktig valg for AI chatbots — det gir "read-your-own-writes" uten unødvendig latenskostnad.
- Påminn om at Azure AI Search IKKE har innebygd replikering — multi-region krever manuell dual-indexing eller rebuild fra kilde.
- For data residency: Verifiser alltid at sekundærregionen er innenfor godkjente geografiske grenser (Norway East ↔ Sweden Central er typisk godkjent for norske organisasjoner).

View file

@ -0,0 +1,611 @@
# Failover Testing for AI Services
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Failover-testing er en kritisk men ofte forsoemmt del av disaster recovery for AI-tjenester. En DR-plan som ikke er testet er i praksis ingen plan -- den gir en falsk trygghet som kan forsterke konsekvensene av et reelt utfall. Microsoft anbefaler eksplisitt a gjennomfoere regelmessige failover-drills for a validere at resiliens-mekanismer fungerer som forventet, og at teamet er i stand til a haandtere en krise effektivt.
For AI-tjenester er failover-testing spesielt utfordrende av flere grunner. For det foerste er AI-inferens ofte tilstandsloest (stateless), men konteksten rundt -- samtalehistorikk, agent-tilstand, RAG-indekser -- er hoyst tilstandsfull. En vellykket failover av selve inferens-endepunktet betyr lite hvis samtalehistorikken gaar tapt eller kunnskapsbasen ikke er tilgjengelig i failover-regionen. For det andre har AI-tjenester kvotebegrensninger per region, saa en failover kan resultere i lavere kapasitet hvis sekundaerregionen har mindre kvote. For det tredje bruker mange AI-loesninger asynkrone pipelines (batch-prosessering, evaluering, fine-tuning) som har andre failover-moenstre enn sanntids-inferens.
Denne referansen dekker planlagte failover-testscenarier, validering og overvaking under failover, suksesskriterier og akseptanseterskel, dokumentasjon og laerdommer, samt regelmessig testplanlegging og frekvens. Alt er forankret i Microsofts veiledning for chaos engineering, Azure Chaos Studio, og Well-Architected Framework for reliability testing.
## Planlagte failover-testscenarier
### Scenariokatalog for AI-tjenester
Failover-tester boer dekke flere niva -- fra enkeltkomponent til fullstendig regional failover:
| Nivaa | Scenario | Beskrivelse | Kompleksitet | Risiko |
|-------|---------|-------------|-------------|--------|
| **L1** | Enkelt AOAI-endepunkt utilgjengelig | Simuler 429/503 fra ett Azure OpenAI-endepunkt | Lav | Lav |
| **L2** | Cosmos DB regional failover | Bytt skriveregion for agentdata | Middels | Middels |
| **L3** | Full gateway-failover | Ruter all trafikk via sekundaer APIM | Middels | Middels |
| **L4** | AI Search utilgjengelig | RAG-indeks nede, test fallback | Middels | Lav |
| **L5** | Komplett regional failover | All AI-infrastruktur bytter region | Hoey | Hoey |
| **L6** | Korrupt data / utilsiktet sletting | Gjenopprett fra backup | Hoey | Middels |
### Scenario L1: Azure OpenAI endepunkt-failover
**Formal:** Verifisere at APIM-gatewayen korrekt ruter trafikk til sekundaert endepunkt nar primaert returnerer feil.
**Fremgangsmate:**
```
1. Forutsetninger:
- APIM konfigurert med backend pool (Norway East primaer, Sweden Central sekundaer)
- Overvaking aktiv (Application Insights, Azure Monitor)
- Lastetest kjoerer for a generere trafikk
2. Feilinjeksjon:
- Metode A: APIM policy-endring (fjern primaer backend fra pool)
- Metode B: Azure Chaos Studio eksperiment
- Metode C: Nettverksregel som blokkerer trafikk til primaer
3. Forventet oppfoersel:
- Gateway returnerer 429/503 fra primaer backend
- Circuit breaker trigger innen < 5 sekunder
- Trafikk rutes automatisk til sekundaer backend
- Sluttbrukere opplever < 10 sekunder forsinkelse
4. Validering:
- Alle API-kall returnerer 200 innen 30 sekunder
- Latens stabiliserer seg innen 60 sekunder
- Ingen tapt kontekst for pagaende samtaler (med session affinity)
```
**APIM policy for simulert feil:**
```xml
<!-- Midlertidig policy for failover-test: simuler 503 fra primaer -->
<policies>
<inbound>
<base />
<choose>
<when condition="@(context.Request.Headers.GetValueOrDefault("X-Failover-Test","") == "active")">
<!-- Under test: fjern primaer fra backend pool -->
<set-backend-service backend-id="openai-secondary-only" />
</when>
<otherwise>
<set-backend-service backend-id="openai-backend-pool" />
</otherwise>
</choose>
</inbound>
</policies>
```
### Scenario L2: Cosmos DB failover
**Formal:** Verifisere at agentdata er tilgjengelig etter Cosmos DB regional failover.
**Fremgangsmate med Azure Chaos Studio:**
```json
{
"type": "Microsoft.Chaos/experiments",
"name": "cosmos-failover-test",
"location": "norwayeast",
"properties": {
"steps": [
{
"name": "Failover-Cosmos-DB",
"branches": [
{
"name": "cosmos-branch",
"actions": [
{
"type": "continuous",
"name": "urn:csci:microsoft:cosmosDB:failover/1.0",
"duration": "PT10M",
"parameters": [
{
"key": "readRegion",
"value": "Norway East"
}
],
"selectorId": "cosmos-target"
}
]
}
]
}
],
"selectors": [
{
"id": "cosmos-target",
"type": "List",
"targets": [
{
"id": "/subscriptions/{sub-id}/resourceGroups/rg-ai-prod/providers/Microsoft.DocumentDB/databaseAccounts/svv-ai-cosmos/providers/Microsoft.Chaos/targets/Microsoft-CosmosDB",
"type": "ChaosTarget"
}
]
}
]
}
}
```
**Forventet oppfoersel:**
- Cosmos DB bytter skriveregion fra Norway East til Sweden Central
- Lesning kan ha kortvarig hoeyre latens under failover
- Agentsamtaler kan fortsette uten datatap
- Failover fullfores innen < 5 minutter
### Scenario L3: Full gateway-failover
**Formal:** Verifisere at all AI-trafikk kan betjenes fra sekundaer gateway-region.
```
Testoppfoersel:
1. Start med normal trafikk gjennom APIM i Norway East
2. Simuler at APIM i Norway East er utilgjengelig:
- DNS-endring: Pek gateway-FQDN til Sweden Central
- Eller: Azure Front Door helsesjekk feiler for Norway East
3. Verifiser:
- Trafikk rutes til APIM i Sweden Central
- APIM i Sweden Central nar Azure OpenAI i Sweden Central
- Responstid er innenfor akseptabel terskel
- Alle funksjoner (chat, RAG, agent) fungerer
4. Failback:
- Gjenopprett APIM i Norway East
- Verifiser at trafikk returnerer til primaer
```
### Scenario L5: Komplett regional failover
**Formal:** Validere full DR-prosedyre med alle komponenter.
```
Tidsplan for full DR-drill (estimert 4-6 timer):
T+0:00 - Annonsering: "DR-drill starter"
T+0:05 - Simulert utfall av Norway East (DNS/nettverk)
T+0:10 - Deteksjon: Varsling utloeses automatisk
T+0:15 - Vurdering: Driftsteam bekrefter utfall
T+0:20 - Beslutning: Iverksett DR-plan
T+0:25 - Gateway failover: APIM rutes til Sweden Central
T+0:30 - Data failover: Verifiser Cosmos DB og Storage
T+0:45 - Agent redeploy: Deploy agentdefinisjoner i sekundaer region
T+1:00 - Validering: Funksjonelle tester
T+1:30 - Stabilisering: Overvak i 30 minutter
T+2:00 - Normal drift fra sekundaer region bekreftet
T+3:00 - Failback paabegynnes
T+3:30 - Primaer region gjenopprettet
T+4:00 - Normal drift fra primaer region bekreftet
T+4:30 - Retrospektiv og dokumentasjon
```
## Validering og overvaking under failover
### Helsesjekk-endepunkter
Implementer dedikerte helsesjekk-endepunkter for AI-tjenestene:
```python
# health_check.py -- Eksempel pa helsesjekk for AI-stack
import asyncio
from datetime import datetime
from openai import AzureOpenAI
async def check_openai_health(endpoint: str, api_key: str) -> dict:
"""Sjekk Azure OpenAI tilgjengelighet og latens."""
start = datetime.now()
try:
client = AzureOpenAI(
azure_endpoint=endpoint,
api_key=api_key,
api_version="2024-06-01"
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "ping"}],
max_tokens=5,
temperature=0
)
latency_ms = (datetime.now() - start).total_seconds() * 1000
return {
"status": "healthy",
"latency_ms": round(latency_ms),
"endpoint": endpoint,
"model": "gpt-4o",
"timestamp": datetime.now().isoformat()
}
except Exception as e:
return {
"status": "unhealthy",
"error": str(e),
"endpoint": endpoint,
"timestamp": datetime.now().isoformat()
}
async def check_cosmos_health(endpoint: str) -> dict:
"""Sjekk Cosmos DB tilgjengelighet."""
# Implementer med Azure Cosmos DB SDK
pass
async def full_health_check() -> dict:
"""Komplett helsesjekk for alle AI-komponenter."""
results = await asyncio.gather(
check_openai_health("https://svv-aoai-ne.openai.azure.com", "***"),
check_openai_health("https://svv-aoai-sc.openai.azure.com", "***"),
check_cosmos_health("https://svv-ai-cosmos.documents.azure.com"),
)
overall = "healthy" if all(r["status"] == "healthy" for r in results) else "degraded"
return {"overall": overall, "components": results}
```
### KQL-queries for failover-overvaking
```kusto
// Overvaak feilrate under failover-test
AppRequests
| where TimeGenerated > ago(1h)
| where AppRoleName == "ai-gateway"
| summarize
TotalRequests = count(),
FailedRequests = countif(ResultCode >= 500),
AvgDuration = avg(DurationMs),
P95Duration = percentile(DurationMs, 95),
P99Duration = percentile(DurationMs, 99)
by bin(TimeGenerated, 1m)
| extend FailureRate = round(todouble(FailedRequests) / TotalRequests * 100, 2)
| order by TimeGenerated desc
```
```kusto
// Sporr backend-skifte under failover
AppDependencies
| where TimeGenerated > ago(1h)
| where DependencyType == "HTTP"
| where Target contains "openai.azure.com"
| summarize
RequestCount = count(),
AvgDuration = avg(DurationMs),
FailCount = countif(ResultCode >= 400)
by bin(TimeGenerated, 1m), Target
| order by TimeGenerated desc
```
```kusto
// Cosmos DB failover-hendelser
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.DOCUMENTDB"
| where Category == "DataPlaneRequests"
| where TimeGenerated > ago(1h)
| summarize
RequestCount = count(),
AvgLatency = avg(duration_s * 1000),
ErrorCount = countif(statusCode_s >= "400")
by bin(TimeGenerated, 1m), regionName_s
| order by TimeGenerated desc
```
### Azure Monitor Dashboard for failover
Opprett et dedikert dashboard for failover-overvaking:
| Panel | Metrikk | Terskel (groen) | Terskel (roed) |
|-------|---------|-----------------|----------------|
| AOAI feilrate | % 4xx/5xx | < 1% | > 5% |
| AOAI latens (P95) | Millisekunder | < 2000 ms | > 5000 ms |
| APIM throughput | Requests/min | > 80% av baseline | < 50% av baseline |
| Cosmos DB latens | Millisekunder | < 50 ms | > 200 ms |
| Cosmos DB tilgjengelighet | % | > 99.9% | < 99% |
| Aktiv region | Region-label | Primaer | Sekundaer |
## Suksesskriterier og akseptanseterskel
### Definerte suksesskriterier per testnivaa
| Testnivaa | Kriterie | Maal | Akseptabelt | Feil |
|-----------|---------|------|-------------|------|
| **L1: Endepunkt-failover** | Gjenopprettingstid | < 10 sek | < 30 sek | > 30 sek |
| | Feilrate under failover | 0% | < 2% | > 5% |
| | Latensoekning | < 50% | < 100% | > 200% |
| **L2: Cosmos DB failover** | Gjenopprettingstid | < 2 min | < 5 min | > 10 min |
| | Datatap (RPO) | 0 sek | < 10 sek | > 60 sek |
| | Agentfunksjonalitet | Full | Degradert | Utilgjengelig |
| **L3: Gateway-failover** | Gjenopprettingstid | < 5 min | < 15 min | > 30 min |
| | Feilrate for sluttbrukere | < 1% | < 5% | > 10% |
| | Funksjonell dekning | 100% | > 90% | < 80% |
| **L5: Full regional** | Gjenopprettingstid (RTO) | < 30 min | < 60 min | > 120 min |
| | Datatap (RPO) | < 5 min | < 30 min | > 60 min |
| | Alle tjenester operative | 100% | > 95% | < 90% |
### Akseptanseprotokoll
```
FAILOVER-TEST AKSEPTANSEPROTOKOLL
==================================
Testdato: _______________
Testnivaa: [ ] L1 [ ] L2 [ ] L3 [ ] L4 [ ] L5 [ ] L6
Testleder: _______________
Deltakere: _______________
RESULTATER:
-----------
Malt RTO: _____ min/sek
Malt RPO: _____ min/sek
Maks feilrate: _____ %
Maks latensoekning: _____ %
Funksjoner tilgjengelig: _____ %
VURDERING:
----------
[ ] BESTATT -- Alle kriterier innenfor "Maal"
[ ] AKSEPTABELT -- Alle kriterier innenfor "Akseptabelt"
[ ] FEIL -- Ett eller flere kriterier i "Feil"-sonen
AVVIK OG MERKNADER:
____________________________________________________
____________________________________________________
SIGNATUR:
Testleder: _____________ Dato: __________
Godkjenner: ____________ Dato: __________
```
### Baseline-maling
Foer failover-testing ma du etablere en baseline for normal ytelse:
```bash
# Kjoer baseline-lasttest med Azure Load Testing
az load test create \
--name ai-baseline-test \
--resource-group rg-ai-prod \
--location norwayeast \
--test-plan tests/baseline-load-test.jmx \
--engine-instances 2
# Baseline-kriterier (eksempel):
# - Gjennomsnittlig responstid: < 1500 ms
# - P95 responstid: < 3000 ms
# - Feilrate: < 0.5%
# - Throughput: > 50 req/sek
```
## Dokumentasjon og laerdommer
### Testreportmal
```markdown
# Failover Test Report
## Testoversikt
- **Dato:** 2026-02-15
- **Scenario:** L3 -- Full gateway-failover
- **Varighet:** 2 timer 15 minutter
- **Deltakere:** [Navn og roller]
## Sammendrag
[2-3 setninger om hva som ble testet og hovedresultatet]
## Testforloep
| Tid | Hendelse | Status |
|-----|---------|--------|
| 10:00 | Test startet, normal trafikk | OK |
| 10:05 | Primaer gateway deaktivert | OK |
| 10:05:12 | Foerste feil detektert av monitor | OK |
| 10:05:45 | Trafikk rutes til sekundaer | OK |
| 10:06:30 | Alle helsesjekker gronne | OK |
| ... | ... | ... |
## Malte resultater
| Kriterie | Maal | Resultat | Status |
|---------|------|---------|--------|
| RTO | < 5 min | 1 min 30 sek | BESTATT |
| Feilrate | < 5% | 2.1% | BESTATT |
| Latens P95 | < 3000 ms | 2800 ms | BESTATT |
## Funn og observasjoner
1. [Funn 1: Beskrivelse og alvorlighet]
2. [Funn 2: Beskrivelse og alvorlighet]
## Forbedringstiltak
| # | Tiltak | Prioritet | Ansvarlig | Frist |
|---|--------|-----------|-----------|-------|
| 1 | [Tiltak] | Hoey | [Navn] | [Dato] |
| 2 | [Tiltak] | Middels | [Navn] | [Dato] |
## Laerdommer (Lessons Learned)
- **Hva fungerte bra:** [Beskrivelse]
- **Hva kan forbedres:** [Beskrivelse]
- **Uventede funn:** [Beskrivelse]
```
### Kunnskapsbase for failover-laerdommer
Bygg en loepende kunnskapsbase med laerdommer fra failover-tester:
| Dato | Scenario | Laerdom | Tiltak | Status |
|------|---------|---------|--------|--------|
| 2026-01-15 | L1 | Circuit breaker brukte 45 sek (for lang) | Reduser timeout til 10 sek | Implementert |
| 2026-02-01 | L2 | Cosmos DB failover tok 8 min (mal: 5 min) | Aktiver service-managed failover | Planlagt |
| 2026-02-15 | L3 | DNS-propagering tok 10 min | Reduser TTL til 60 sek | Under arbeid |
### Post-incident review-prosess
Etter hver failover-test (og spesielt etter reelle hendelser):
```
1. Samle data (innen 24 timer)
- Loggfiler fra alle komponenter
- Metrikkdata fra Azure Monitor
- Tidslinje for hendelser
- Kommunikasjonslogg
2. Gjennomfoere retrospektiv (innen 1 uke)
- Blameless post-mortem
- Identifiser rotaarsaker
- Dokumenter tidslinje
- Klassifiser funn (kritisk/hoey/middels/lav)
3. Definere tiltak (under retrospektiv)
- Konkrete tiltak med eier og frist
- Oppdater DR-plan
- Oppdater runbooks
- Planlegg oppfoelgingstest
4. Foelg opp (loepende)
- Sporr tiltak i Linear/backlog
- Verifiser implementering
- Test forbedringer i neste planlagte test
```
## Regelmessig testplanlegging og frekvens
### Anbefalt testfrekvens
| Testtype | Frekvens | Deltakere | Estimert tid |
|----------|----------|-----------|-------------|
| **L1: Endepunkt-failover** | Ukentlig (automatisert) | CI/CD pipeline | 5-10 min |
| **L2: Komponent-failover** | Manedlig | Driftsteam (2-3 personer) | 1-2 timer |
| **L3: Gateway-failover** | Kvartalsvis | Drifts- + utviklingsteam | 2-4 timer |
| **L5: Full regional drill** | Halvaarlig | Alle (inkl. ledelse) | 4-8 timer |
| **Tabletop exercise** | Kvartalsvis | Arkitektur + drift + forretning | 2 timer |
| **Chaos engineering** | Lopende i CI/CD | Automatisert | Varierer |
### Arsplan for failover-testing
```
Q1 (jan-mar):
- Uke 2: Tabletop exercise (alle scenarier)
- Uke 4: L2 komponent-test (Cosmos DB failover)
- Uke 8: L3 gateway-failover
- Uke 12: L5 FULL DR-DRILL
Q2 (apr-jun):
- Uke 14: Tabletop exercise (nye scenarier)
- Uke 17: L2 komponent-test (Storage failover)
- Uke 20: L3 gateway-failover
- Uke 24: L2 komponent-test (AI Search recovery)
Q3 (jul-sep):
- Uke 27: Tabletop exercise (oppdatert DR-plan)
- Uke 30: L2 komponent-test (Cosmos DB failover)
- Uke 33: L3 gateway-failover
- Uke 36: L5 FULL DR-DRILL
Q4 (okt-des):
- Uke 40: Tabletop exercise (arsrevisjon)
- Uke 43: L2 komponent-test (valgfritt scenario)
- Uke 46: L3 gateway-failover
- Uke 50: Arlig DR-rapportering og planrevisjon
```
### Automatisert failover-testing i CI/CD
Integrer L1-tester i CI/CD-pipeline:
```yaml
# azure-pipelines.yml -- Failover test stage
- stage: FailoverTest
displayName: 'Automated Failover Validation'
dependsOn: DeployStaging
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- job: RunChaosExperiment
steps:
- task: AzureCLI@2
displayName: 'Start Chaos Experiment'
inputs:
azureSubscription: 'svv-ai-staging'
scriptType: 'bash'
inlineScript: |
# Start chaos experiment
az chaos experiment start \
--name ai-gateway-failover-test \
--resource-group rg-ai-staging
# Vent pa at eksperimentet fullfores
az chaos experiment show \
--name ai-gateway-failover-test \
--resource-group rg-ai-staging \
--query "status" -o tsv
- task: AzureCLI@2
displayName: 'Run Load Test During Chaos'
inputs:
azureSubscription: 'svv-ai-staging'
scriptType: 'bash'
inlineScript: |
# Kjoer lasttest parallelt med chaos experiment
az load test run create \
--test-id ai-failover-load-test \
--resource-group rg-ai-staging \
--load-test-resource svv-ai-load-test
- task: AzureCLI@2
displayName: 'Validate Results'
inputs:
azureSubscription: 'svv-ai-staging'
scriptType: 'bash'
inlineScript: |
# Valider at feilrate er innenfor terskel
ERROR_RATE=$(az monitor metrics list \
--resource "/subscriptions/{sub}/..." \
--metric "FailedRequests" \
--interval PT1M \
--query "value[0].timeseries[0].data[-1].total" -o tsv)
if [ "$ERROR_RATE" -gt "5" ]; then
echo "##vso[task.logissue type=error]Failover test failed: error rate $ERROR_RATE% exceeds 5% threshold"
exit 1
fi
echo "Failover test passed: error rate $ERROR_RATE%"
```
### Azure Chaos Studio + Azure Load Testing-integrasjon
Microsoft anbefaler a kombinere Chaos Studio (feilinjeksjon) med Azure Load Testing (syntetisk last) for realistisk failover-validering:
```
+------------------+ +---------------------+
| Azure Load | | Azure Chaos Studio |
| Testing | | |
| (syntetisk last) | | (feilinjeksjon) |
+--------+---------+ +---------+-----------+
| |
| Parallelkjoering |
+------------+------------+
|
+-------v--------+
| AI Application |
| (staging) |
+-------+--------+
|
+------------+------------+
| |
+--------v---------+ +--------v---------+
| Azure OpenAI | | Azure OpenAI |
| (Norway East) | | (Sweden Central) |
+------------------+ +------------------+
```
**Viktig:** Under kombinert chaos + load testing vil man forvente hoeyere feilrate og latens enn normalt. Definer separate baseline-verdier for "normal" og "chaos"-tilstand.
## Referanser
- [What is Azure Chaos Studio?](https://learn.microsoft.com/en-us/azure/chaos-studio/chaos-studio-overview)
- [Create a chaos experiment - Cosmos DB failover](https://learn.microsoft.com/en-us/azure/chaos-studio/chaos-studio-tutorial-service-direct-portal)
- [Continuous validation with Azure Load Testing and Chaos Studio](https://learn.microsoft.com/en-us/azure/architecture/guide/testing/mission-critical-deployment-testing)
- [Architecture strategies for designing a reliability testing strategy](https://learn.microsoft.com/en-us/azure/well-architected/reliability/testing-strategy)
- [Architecture strategies for disaster recovery](https://learn.microsoft.com/en-us/azure/well-architected/reliability/disaster-recovery)
- [Shift right to test in production - Fault injection](https://learn.microsoft.com/en-us/devops/deliver/shift-right-test-production#fault-injection)
- [Deployment and testing for mission-critical workloads on Azure](https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/mission-critical-deployment-testing)
## For Cosmo
- **Bruk denne referansen** nar kunden har implementert DR-infrastruktur men mangler en testplan -- en DR-loesning uten testing er like risikabel som ingen DR-loesning.
- **Start med L1-tester (automatisert)** for a bygge erfaring og tillit foer man gradvis oeker til L3 og L5 -- dette reduserer risikoen for at tester selv forarsaker utfall.
- **Anbefal Azure Chaos Studio + Azure Load Testing-kombinasjonen** som standard verktoeysett. Chaos Studio er GA og stoetter service-direct faults mot Cosmos DB, som er den mest kritiske AI-komponenten a teste.
- **Fremhev at failover-testing ma inkludere hele AI-stakken** -- ikke bare inferens-endepunktet. Samtalehistorikk (Cosmos DB), kunnskapsbaser (AI Search), og agent-definisjoner ma alle valideres under failover.
- **Bruk akseptanseprotokollen og rapportmalen** for a gi kunden konkrete verktøy de kan ta i bruk umiddelbart. Dokumentasjon av tester er like viktig som selve testingen for kontinuerlig forbedring.

View file

@ -0,0 +1,396 @@
# Geo-Redundancy for Azure AI Search
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Azure AI Search er en regional tjeneste uten innebygd geo-replikering eller automatisk failover. Hvis regionen blir utilgjengelig, blir også search-tjenesten utilgjengelig. For AI-løsninger med RAG-arkitektur (Retrieval-Augmented Generation) er dette en kritisk svakhet fordi search-indeksen er hjørnesteinen i hele kunnskapsgjenfinningen.
For å oppnå geo-redundans for Azure AI Search må organisasjoner implementere egne løsninger: identiske search-tjenester i flere regioner, synkroniserte indekser, og load balancing med failover-logikk. Dette krever nøye planlegging av indekseringsstrategier, konsistensgarantier og trafikkstyring.
For norsk offentlig sektor med strenge tilgjengelighetskrav er multi-region AI Search en viktig komponent i BCDR-strategien. Typisk oppsett er primær i Norway East med sekundær i Sweden Central, noe som sikrer data residency innenfor EU/EØS samtidig som det gir regional redundans.
## Indeksreplikering på tvers av regioner
### Arkitekturoversikt
Azure AI Search har ingen innebygd mekanisme for indeksreplikering mellom regioner. Du må implementere en av følgende strategier:
```
Strategi 1: Dual Push Indexing
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Datakilde │────▶│ Indexer Pipeline │────▶│ Search Region A │
│ (Blob/SQL) │ │ (Azure Functions) │────▶│ Search Region B │
└──────────────┘ └──────────────────┘ └──────────────────┘
Strategi 2: Pull from Replicated Source
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Datakilde A │◀───▶│ GRS / GZRS │◀───▶│ Datakilde B │
│ (Region A) │ │ Replikering │ │ (Region B) │
└──────┬───────┘ └──────────────────┘ └──────┬───────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ AI Search A │ │ AI Search B │
│ (Indexer) │ │ (Indexer) │
└──────────────┘ └──────────────────┘
```
### Dual Push Indexing med Azure Functions
```python
# Azure Function: Push-based dual-region indexing
import azure.functions as func
from azure.search.documents import SearchClient
from azure.core.credentials import AzureKeyCredential
import json
# Konfigurer klienter for begge regioner
primary_client = SearchClient(
endpoint="https://search-primary-norwayeast.search.windows.net",
index_name="knowledge-base",
credential=AzureKeyCredential("<primary-key>")
)
secondary_client = SearchClient(
endpoint="https://search-secondary-swedencentral.search.windows.net",
index_name="knowledge-base",
credential=AzureKeyCredential("<secondary-key>")
)
def main(msg: func.QueueMessage) -> None:
"""Process document and index to both regions."""
document = json.loads(msg.get_body().decode('utf-8'))
# Indekser til primær region
try:
primary_result = primary_client.upload_documents(documents=[document])
logging.info(f"Primary indexed: {primary_result[0].key}")
except Exception as e:
logging.error(f"Primary indexing failed: {e}")
# Send til dead-letter queue for retry
raise
# Indekser til sekundær region (asynkront er OK)
try:
secondary_result = secondary_client.upload_documents(documents=[document])
logging.info(f"Secondary indexed: {secondary_result[0].key}")
except Exception as e:
logging.warning(f"Secondary indexing failed (will retry): {e}")
# Legg i retry-kø — sekundær er ikke kritisk
send_to_retry_queue(document)
```
### Pull-basert indeksering med Built-in Indexers
```bash
# Opprett identiske indexer i begge regioner
# Primær region — kobler til primær datakilde
az search indexer create \
--service-name "search-primary-norwayeast" \
--resource-group "rg-ai-prod" \
--name "blob-indexer" \
--data-source-name "blob-source-primary" \
--target-index-name "knowledge-base" \
--schedule '{"interval": "PT5M"}'
# Sekundær region — kobler til GRS-replikert datakilde
az search indexer create \
--service-name "search-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--name "blob-indexer" \
--data-source-name "blob-source-secondary" \
--target-index-name "knowledge-base" \
--schedule '{"interval": "PT5M"}'
```
## Replikatelling og dimensjonering for tilgjengelighet
### Intra-region tilgjengelighet med replikaer
Azure AI Search distribuerer automatisk replikaer på tvers av Availability Zones når du har 2+ replikaer i en region som støtter AZ.
| Replikaer | SLA | Lesbare spørringer | Skriveoperasjoner | Merknader |
|-----------|-----|-------------------|-------------------|-----------|
| 1 | 99.9% | Ja | Ja | Ingen AZ-redundans |
| 2 | 99.9% | Ja | Ja | AZ-distribuert automatisk |
| 3+ | 99.99% | Ja | Ja | Anbefalt for prod (read/write SLA) |
### Dimensjoneringsveiledning for multi-region
```
Per region (produksjon):
├── Replikaer: 3 (for 99.99% SLA og AZ-redundans)
├── Partisjoner: Basert på indeksstørrelse
│ ├── < 25 GB → 1 partisjon
│ ├── 2550 GB → 2 partisjoner
│ ├── 50150 GB → 36 partisjoner
│ └── > 150 GB → 612 partisjoner
└── SKU: Standard eller Standard S2/S3
Sekundær region (DR):
├── Replikaer: 2 (minimum for AZ, scale up ved failover)
├── Partisjoner: Identisk med primær
└── SKU: Identisk med primær
```
### Kostnadsoptimalisering for sekundær region
```bash
# Sekundær region starter med færre replikaer
# Scale up automatisk ved failover via Azure Automation
# Opprett Automation Runbook for scale-up
az automation runbook create \
--automation-account-name "aa-ai-dr" \
--resource-group "rg-ai-dr" \
--name "scale-up-search-dr" \
--type "PowerShell" \
--content '
# Scale sekundær AI Search fra 2 til 3 replikaer
$searchService = Get-AzSearchService `
-ResourceGroupName "rg-ai-dr" `
-Name "search-secondary-swedencentral"
Set-AzSearchService `
-ResourceGroupName "rg-ai-dr" `
-Name "search-secondary-swedencentral" `
-ReplicaCount 3
Write-Output "Scaled to 3 replicas for DR"
'
```
## Failover- og routingstrategier
### Azure Front Door for AI Search failover
```bicep
// Bicep: Azure Front Door med failover for AI Search
resource frontDoor 'Microsoft.Cdn/profiles@2023-05-01' = {
name: 'fd-ai-search'
location: 'global'
sku: {
name: 'Premium_AzureFrontDoor'
}
}
resource originGroup 'Microsoft.Cdn/profiles/originGroups@2023-05-01' = {
parent: frontDoor
name: 'search-origins'
properties: {
loadBalancingSettings: {
sampleSize: 4
successfulSamplesRequired: 3
}
healthProbeSettings: {
probePath: '/indexes/knowledge-base/docs?api-version=2024-07-01&search=*&$top=1'
probeRequestType: 'GET'
probeProtocol: 'Https'
probeIntervalInSeconds: 30
}
}
}
resource primaryOrigin 'Microsoft.Cdn/profiles/originGroups/origins@2023-05-01' = {
parent: originGroup
name: 'primary-norwayeast'
properties: {
hostName: 'search-primary-norwayeast.search.windows.net'
priority: 1
weight: 1000
}
}
resource secondaryOrigin 'Microsoft.Cdn/profiles/originGroups/origins@2023-05-01' = {
parent: originGroup
name: 'secondary-swedencentral'
properties: {
hostName: 'search-secondary-swedencentral.search.windows.net'
priority: 2
weight: 1000
}
}
```
### Application-level failover
```python
# Python: Application-level failover for Azure AI Search
from azure.search.documents import SearchClient
from azure.core.credentials import AzureKeyCredential
from azure.core.exceptions import ServiceResponseError, HttpResponseError
import time
class ResilientSearchClient:
"""AI Search client with automatic failover."""
def __init__(self, primary_endpoint, secondary_endpoint, index_name, api_key):
self.primary = SearchClient(
endpoint=primary_endpoint,
index_name=index_name,
credential=AzureKeyCredential(api_key)
)
self.secondary = SearchClient(
endpoint=secondary_endpoint,
index_name=index_name,
credential=AzureKeyCredential(api_key)
)
self.use_primary = True
self.failover_time = None
self.health_check_interval = 60 # sekunder
def search(self, search_text, **kwargs):
"""Search with automatic failover."""
client = self.primary if self.use_primary else self.secondary
try:
results = client.search(search_text=search_text, **kwargs)
# Sjekk om vi kan falle tilbake til primær
if not self.use_primary and self._should_check_primary():
self._try_failback()
return results
except (ServiceResponseError, HttpResponseError) as e:
if self.use_primary:
print(f"Primary search failed, failing over: {e}")
self.use_primary = False
self.failover_time = time.time()
return self.secondary.search(search_text=search_text, **kwargs)
else:
raise # Begge regioner feiler
def _should_check_primary(self):
"""Check if enough time has passed to try primary again."""
if self.failover_time is None:
return False
return time.time() - self.failover_time > self.health_check_interval
def _try_failback(self):
"""Attempt to fail back to primary region."""
try:
self.primary.search(search_text="*", top=1)
self.use_primary = True
self.failover_time = None
print("Failback to primary successful")
except Exception:
pass # Primær er fortsatt nede
```
## Holde indekser synkroniserte
### Synkroniseringstrategier
| Strategi | Forsinkelse | Kompleksitet | Anbefalt for |
|----------|-----------|-------------|-------------|
| Dual push (samtidige) | ~0 | Middels | Sanntidskritiske data |
| Event-driven sync | Sekunder | Middels | Generelt anbefalt |
| Scheduled indexer | 560 min | Lav | Batch-baserte oppdateringer |
| Full rebuild | Timer | Lav | Sjeldne endringer |
### Event-driven synkronisering med Event Grid
```bash
# Sett opp Event Grid for blob-endringer → trigger dual indexing
az eventgrid event-subscription create \
--name "blob-change-to-search-sync" \
--source-resource-id "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Storage/storageAccounts/staiprod" \
--included-event-types "Microsoft.Storage.BlobCreated" "Microsoft.Storage.BlobDeleted" \
--endpoint-type "azurefunction" \
--endpoint "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Web/sites/func-search-sync/functions/SyncToSecondary"
```
### Indeks-konsistensvalidering
```python
# Periodisk validering av indekskonsistens mellom regioner
import requests
def validate_index_consistency(primary_endpoint, secondary_endpoint, index_name, api_key):
"""Compare document counts and sample documents between regions."""
headers = {"api-key": api_key, "Content-Type": "application/json"}
# Sammenlign dokumenttellinger
primary_count = requests.get(
f"{primary_endpoint}/indexes/{index_name}/docs/$count?api-version=2024-07-01",
headers=headers
).json()
secondary_count = requests.get(
f"{secondary_endpoint}/indexes/{index_name}/docs/$count?api-version=2024-07-01",
headers=headers
).json()
drift = abs(primary_count - secondary_count)
drift_pct = (drift / max(primary_count, 1)) * 100
return {
"primary_count": primary_count,
"secondary_count": secondary_count,
"drift": drift,
"drift_percentage": round(drift_pct, 2),
"in_sync": drift_pct < 1.0 # < 1% avvik er akseptabelt
}
```
## Query-ytelse i multi-region oppsett
### Latensoptimalisering
| Strategi | Latensreduksjon | Merknad |
|----------|----------------|---------|
| Latency-based routing | 2050 ms | Brukere sendes til nærmeste region |
| Semantic caching | 8095% | Cache hyppige spørringer i APIM |
| Read replicas (intra-region) | 1030 ms | Fordel lesninger over replikaer |
| Query optimalisering | Varierer | $select, $top for å redusere payload |
### Azure API Management for caching og routing
```xml
<!-- APIM Policy: Cache og failover for AI Search queries -->
<policies>
<inbound>
<base />
<cache-lookup vary-by-query-parameter="search,filter,top,skip"
caching-type="internal" />
</inbound>
<backend>
<retry condition="@(context.Response.StatusCode >= 500)"
count="1" interval="0" first-fast-retry="true">
<choose>
<when condition="@(context.Variables.GetValueOrDefault<bool>("usePrimary", true))">
<set-backend-service
base-url="https://search-primary-norwayeast.search.windows.net" />
</when>
<otherwise>
<set-backend-service
base-url="https://search-secondary-swedencentral.search.windows.net" />
</otherwise>
</choose>
</retry>
</backend>
<outbound>
<cache-store duration="300" />
<base />
</outbound>
</policies>
```
## Referanser
- [Multi-region deployments in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-multi-region) — Offisiell multi-region guide
- [Reliability in Azure AI Search](https://learn.microsoft.com/en-us/azure/reliability/reliability-ai-search) — Tilgjengelighet, AZ og DR
- [Multi-region solutions in nonpaired regions](https://learn.microsoft.com/en-us/azure/reliability/regions-multi-region-nonpaired) — Multi-region uten parede regioner
- [Azure AI Search multi-region Bicep sample](https://github.com/Azure-Samples/azure-search-multiple-regions) — Komplett Bicep-mal
- [Azure Front Door overview](https://learn.microsoft.com/en-us/azure/frontdoor/front-door-overview) — Global load balancing
- [Azure Traffic Manager overview](https://learn.microsoft.com/en-us/azure/traffic-manager/traffic-manager-overview) — DNS-basert trafikkstyring
## For Cosmo
- **Bruk denne referansen** når kunden bygger RAG-løsninger med Azure AI Search og trenger geo-redundans for search-indeksene.
- Azure AI Search har INGEN innebygd geo-replikering — dette er en vanlig misforståelse. Kunden må implementere dual-indexing selv.
- Anbefal minimum 3 replikaer per region for 99.99% SLA og AZ-redundans — 2 replikaer gir kun 99.9%.
- For kostnadsoptimalisering: Sekundær region kan kjøre med 2 replikaer og skalere opp til 3 ved failover via Azure Automation.
- Indekskonsistens bør valideres automatisk — sett opp periodisk sjekk av dokumenttelling og samplingsbasert innholdsvalidering.

View file

@ -0,0 +1,316 @@
# Incident Response for AI Systems
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Incident response for AI-systemer krever spesialiserte prosedyrer som adresserer unike feilmodi som ikke finnes i tradisjonelle IT-systemer. AI-spesifikke hendelser inkluderer modell-degradering, prompt injection-angrep, hallusinasjonsspikes, embedding-drift, og utilgjengelige inference-endepunkter. Disse hendelsene kan ha subtile symptomer som er vanskelige å oppdage med tradisjonell overvåking.
Azure tilbyr flere verktøy for AI-spesifikk overvåking og hendelseshåndtering: Microsoft Defender for AI Services for trusseloppdaging, Azure Monitor for metrikk og alerting, Microsoft Sentinel for SIEM/SOAR-kapabiliteter, og Application Insights for applikasjonslagsovervåking. Disse verktøyene må konfigureres spesifikt for AI-arbeidsbelastninger.
For norsk offentlig sektor er hendelseshåndtering regulert gjennom NSMs grunnprinsipper, og mange organisasjoner har ITIL-baserte prosesser. AI-hendelser krever utvidelse av eksisterende incident management-prosesser med AI-spesifikke klassifiseringer, eskaleringsregler og kommunikasjonsplaner.
## AI-spesifikke hendelsesklassifiseringer
### Hendelseskategorier for AI-systemer
| Kategori | Beskrivelse | Eksempler | Alvorlighetsgrad |
|----------|-------------|-----------|-----------------|
| Modellutilgjengelighet | Inference-endepunkt svarer ikke | Azure OpenAI regional outage, quota exceeded | Kritisk |
| Modelldegraddering | Redusert kvalitet på modellresponser | Økt hallusinasjonsrate, inkonsistente svar | Høy |
| Datapipeline-feil | Indeksering eller dataflyt stoppet | Search indexer failed, embedding pipeline stoppet | Høy |
| Sikkerhetsbrudd | AI-spesifikke angrep | Prompt injection, jailbreak, data exfiltration | Kritisk |
| Ytelsesdegraddering | Økt latens eller redusert throughput | Token rate limiting, høy p99 latens | Middels |
| Kostnadsanomali | Uventet økning i AI-forbruk | Token-forbruk spike, uautoriserte API-kall | Middels |
| Datakvalitetsproblem | Korrupt eller utdatert data | Embedding drift, stale indeks, poison data | Høy |
| Compliance-brudd | Brudd på regulatoriske krav | PII i modellresponser, uautorisert datatilgang | Kritisk |
### Alvorlighetsnivåer og responstider
| Nivå | Beskrivelse | Responstid | Eskalering | Eksempel |
|------|-------------|-----------|------------|---------|
| P0 — Kritisk | Total tjenestebortfall eller sikkerhetshendelse | < 15 min | Umiddelbar til CISO/CTO | Regional outage, aktiv data breach |
| P1 — Høy | Betydelig degradering av funksjonalitet | < 1 time | Til teamlead innen 30 min | Modell gir feil svar konsistent |
| P2 — Middels | Delvis degradering, workaround eksisterer | < 4 timer | Til teamlead innen 2 timer | Økt latens på search-spørringer |
| P3 — Lav | Minimal påvirkning | Neste virkedag | Standard kanal | Ikke-kritisk indexer-feil |
## Deteksjon og alerting-strategier
### Microsoft Defender for AI Services
```bash
# Aktiver Defender for AI Services
az security pricing create \
--name "AI" \
--tier "standard"
# Se aktive sikkerhetsvarsler for AI
az security alert list \
--query "[?contains(alertType, 'AI')]" \
--output table
```
### Azure Monitor alerting for AI-metrikker
```kusto
// KQL: Detect increased error rate for Azure OpenAI
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Category == "RequestResponse"
| where TimeGenerated > ago(15m)
| summarize
TotalRequests = count(),
FailedRequests = countif(resultCode_d >= 400),
ErrorRate = round(countif(resultCode_d >= 400) * 100.0 / count(), 2)
by bin(TimeGenerated, 5m)
| where ErrorRate > 5.0
| project TimeGenerated, TotalRequests, FailedRequests, ErrorRate
```
```kusto
// KQL: Detect abnormal token consumption (potential abuse)
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Category == "RequestResponse"
| where TimeGenerated > ago(1h)
| extend
promptTokens = toint(properties_s.promptTokens),
completionTokens = toint(properties_s.completionTokens)
| summarize
TotalTokens = sum(promptTokens + completionTokens),
AvgTokensPerRequest = avg(promptTokens + completionTokens)
by bin(TimeGenerated, 5m), callerIpAddress_s
| where TotalTokens > 100000 // Anomali-terskel
```
```kusto
// KQL: AI Search indexer failure detection
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SEARCH"
| where OperationName == "Indexers.Status"
| where resultSignature_d != 200
| project TimeGenerated, resource_s, OperationName, resultSignature_d, resultDescription_s
| order by TimeGenerated desc
```
### Alert-konfigurasjoner
```bash
# Azure OpenAI error rate alert
az monitor metrics alert create \
--name "aoai-error-rate-critical" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.CognitiveServices/accounts/aoai-prod" \
--condition "avg ServerErrors > 10" \
--window-size 5m \
--evaluation-frequency 1m \
--severity 0 \
--action-group "ag-ai-oncall"
# Azure OpenAI latency alert
az monitor metrics alert create \
--name "aoai-latency-warning" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.CognitiveServices/accounts/aoai-prod" \
--condition "avg Latency > 5000" \
--window-size 5m \
--evaluation-frequency 1m \
--severity 2 \
--action-group "ag-ai-team"
# Token consumption anomaly
az monitor metrics alert create \
--name "aoai-token-anomaly" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.CognitiveServices/accounts/aoai-prod" \
--condition "total ProcessedPromptTokens > 500000" \
--window-size 1h \
--evaluation-frequency 15m \
--severity 2 \
--action-group "ag-ai-team"
```
## Eskalerings-prosedyrer og runbooks
### Eskalerings-matrise
```markdown
## Eskaleringsmatrise for AI-hendelser
### Nivå 1: AI Platform Team (L1)
- **Ansvar:** Første respons, triage, kjente problemer
- **Verktøy:** Azure Monitor dashboards, Runbook for kjente feil
- **Eskaleringstid:** 15 min (P0), 30 min (P1), 2 timer (P2)
### Nivå 2: AI Engineering Team (L2)
- **Ansvar:** Teknisk feilsøking, workaround-implementering
- **Verktøy:** Log Analytics, Application Insights, Azure CLI
- **Eskaleringstid:** 30 min (P0), 1 time (P1)
### Nivå 3: Architecture/Security Team (L3)
- **Ansvar:** Arkitekturelle beslutninger, sikkerhetsrespons
- **Verktøy:** Microsoft Sentinel, Defender for Cloud
- **Eskaleringstid:** 1 time (P0), involveres alltid for sikkerhet
### Nivå 4: Microsoft Support (L4)
- **Ansvar:** Platform-nivå feil, Azure-tjenestefeil
- **Verktøy:** Azure Support ticket (Severity A for P0)
- **Kontakt:** Azure Support portal, TAM for Enterprise
```
### Runbook: Azure OpenAI Regional Outage
```markdown
## Runbook: Azure OpenAI Regional Outage
### Trigger
- Azure Service Health alert for Cognitive Services i primær region
- Error rate > 50% vedvarende over 5 minutter
- Alle requests returnerer 5xx
### Umiddelbare handlinger (05 min)
1. Verifiser at det er en regional hendelse (sjekk Azure Status)
2. Aktiver incident i PagerDuty/Opsgenie
3. Send umiddelbar varsling til interessenter
### Failover-prosedyre (515 min)
1. Aktiver failover via Traffic Manager/APIM:
```bash
# Oppdater Traffic Manager priority
az network traffic-manager endpoint update \
--resource-group rg-networking \
--profile-name tm-aoai \
--name secondary-swedencentral \
--type azureEndpoints \
--priority 1
```
2. Verifiser at sekundært endpoint responderer
3. Sjekk at applikasjoner bruker ny rute
4. Overvåk error rate i sekundær region
### Kommunikasjon (løpende)
1. Oppdater status-side
2. Varsle forretningsbrukere via Teams/epost
3. Logg alle handlinger i incident management system
### Gjenoppretting
1. Overvåk Azure Service Health for løsning
2. Verifiser at primær region fungerer (test med syntetisk trafikk)
3. Planlegg kontrollert failback i lavtrafikkperiode
4. Utfør failback og verifiser
```
## Kommunikasjonsplaner for interessenter
### Kommunikasjonsmal
| Tidspunkt | Mottaker | Kanal | Innhold |
|-----------|---------|-------|---------|
| T+0 min | Ops-team | PagerDuty | Automatisk alert |
| T+5 min | Teamlead | Teams/Slack | Triage-oppsummering |
| T+15 min | Management | Epost | Statusoppdatering med ETA |
| T+30 min | Alle brukere | Statusside | Offentlig statusmelding |
| T+60 min | Ledelse | Epost | Oppdatert ETA, påvirkning |
| Hver time | Alle | Statusside + epost | Løpende oppdatering |
| Etter løsning | Alle | Epost | Hendelse løst, kort oppsummering |
| T+48 timer | Internt | Møte + doc | Post-mortem rapport |
### Statusmeldings-maler
```markdown
## Statusmelding — Mal
### Hendelse oppdaget
[Tidspunkt]: Vi har identifisert et problem med [tjenestenavn].
Påvirkning: [Beskrivelse av påvirkning for brukere]
Status: Vi undersøker og vil gi oppdatering innen [tid].
### Under arbeid
[Tidspunkt]: Vi har identifisert årsaken som [kort beskrivelse].
Tiltak: [Hva gjøres?]
Forventet løsning: [ETA]
Workaround: [Eventuell midlertidig løsning]
### Løst
[Tidspunkt]: Hendelsen er løst. [Tjenestenavn] fungerer normalt.
Varighet: [Fratil]
Rotårsak: [Kort beskrivelse]
Tiltak: [Hva gjøres for å forhindre gjentakelse]
```
## Post-incident review og forbedring
### Post-mortem prosess
1. **Samle data** (innen 24 timer):
- Tidslinje med alle handlinger
- Alle relevante logger og metrikker
- Kommunikasjonslogg
2. **Gjennomfør blameless post-mortem** (innen 5 virkedager):
- Tidslinje-gjennomgang
- Rotårsaksanalyse (5 Whys eller Fishbone)
- Identifiser forbedringstiltak
- Definer action items med eiere og tidsfrister
3. **Dokumenter og distribuer** (innen 7 virkedager):
- Post-mortem rapport
- Oppdaterte runbooks
- Nye/justerte alerts
- Lessons learned
### Post-mortem mal
```markdown
# Post-Mortem Report — [Hendelsesnavn]
## Oppsummering
- **Dato:** [Dato]
- **Varighet:** [Timer:Minutter]
- **Alvorlighetsgrad:** [P0/P1/P2/P3]
- **Påvirkede tjenester:** [Liste]
- **Påvirkede brukere:** [Antall/beskrivelse]
## Tidslinje
| Tidspunkt | Hendelse | Aksjon |
|-----------|---------|--------|
| HH:MM | [Hva skjedde] | [Hva ble gjort] |
## Rotårsak
[Detaljert beskrivelse av rotårsak]
## Hva gikk bra
- [Punkt 1]
- [Punkt 2]
## Hva kan forbedres
- [Punkt 1]
- [Punkt 2]
## Action Items
| # | Beskrivelse | Eier | Frist | Status |
|---|-------------|------|-------|--------|
| 1 | [Tiltak] | [Navn] | [Dato] | Open |
```
## Referanser
- [Secure AI — Detect AI security threats](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/secure) — CAF AI-sikkerhet
- [AI-6: Establish monitoring and detection](https://learn.microsoft.com/en-us/security/benchmark/azure/mcsb-v2-artificial-intelligence-security) — MCSB AI-overvåking
- [Create an effective incident management plan](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/incident-management) — WAF incident management
- [Microsoft Defender for AI Services](https://learn.microsoft.com/en-us/azure/defender-for-cloud/ai-threat-protection) — AI-spesifikk trusseloppdaging
- [Azure Monitor alerts overview](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-overview) — Alert-rammeverk
- [Microsoft Sentinel overview](https://learn.microsoft.com/en-us/azure/sentinel/overview) — SIEM/SOAR for sikkerhetshendelser
- [Monitor Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/monitor-openai) — OpenAI-spesifikk monitoring
## For Cosmo
- **Bruk denne referansen** når kunden etablerer eller forbedrer sine incident response-prosedyrer for AI-systemer.
- AI-hendelser krever utvidelse av eksisterende ITIL/incident-prosesser — ikke separate prosesser, men tilpassede kategorier og runbooks.
- Anbefal alltid blameless post-mortems — fokuser på systemer og prosesser, ikke personer.
- For norsk offentlig sektor: Hendelseshåndtering bør integreres med NSMs rapporteringskrav og organisasjonens ROS-analyse.
- Kritisk: Sørg for at AI-teamet har direkte eskaleringsmulighet til Microsoft Support med Severity A for produksjonskritiske hendelser.

View file

@ -0,0 +1,430 @@
# Monitoring and Alerting for Failover Detection
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Rask og pålitelig deteksjon av feil er avgjørende for å minimere nedetid i AI-systemer. Failover-deteksjon handler om å oppdage at en tjeneste eller region har feilet, og å initiere gjenopprettingsprosessen så raskt som mulig. For AI-workloads er dette spesielt viktig fordi forsinkede svar eller manglende tilgjengelighet direkte påvirker brukeropplevelsen.
Azure Monitor, Application Insights og Azure Service Health gir et robust rammeverk for overvåking og alerting. For AI-spesifikke metrikker som token-forbruk, modellkvalitet og search-indeksvaliditet kreves tilpasset monitoring med custom metrics og KQL-spørringer.
For norsk offentlig sektor som følger ITIL-baserte prosesser, må monitoring integreres med eksisterende incident management-systemer. NSMs grunnprinsipper krever "planlegging for å håndtere hendelser" (prinsipp 4.3), som inkluderer automatisk deteksjon og varsling.
## Health check-endepunkter og heartbeats
### Health check arkitektur
```
┌──────────────────┐
│ Azure Monitor │
│ (Availability │
│ Tests) │
└────────┬─────────┘
│ HTTPS GET /health
┌──────────────────┐ ┌───────────────────┐
│ App Service │────▶│ Deep Health Check │
│ /health │ │ ├─ OpenAI ✓/✗ │
│ (Shallow) │ │ ├─ AI Search ✓/✗ │
│ │ │ ├─ Cosmos DB ✓/✗ │
│ /health/deep │ │ ├─ Redis ✓/✗ │
│ (Deep) │ │ └─ Key Vault ✓/✗ │
└──────────────────┘ └───────────────────┘
```
### Health check implementering
```python
# FastAPI health check endpoints for AI service
from fastapi import FastAPI, Response
from datetime import datetime
import asyncio
app = FastAPI()
class HealthStatus:
def __init__(self):
self.checks = {}
self.overall = "unknown"
async def check_openai():
"""Check Azure OpenAI availability."""
try:
response = await openai_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "ping"}],
max_tokens=1,
timeout=5
)
return {"status": "healthy", "latency_ms": response.usage.total_tokens}
except Exception as e:
return {"status": "unhealthy", "error": str(e)}
async def check_search():
"""Check Azure AI Search availability."""
try:
results = search_client.search(search_text="*", top=1)
count = 0
async for _ in results:
count += 1
return {"status": "healthy", "documents_accessible": True}
except Exception as e:
return {"status": "unhealthy", "error": str(e)}
async def check_cosmos():
"""Check Cosmos DB availability."""
try:
await cosmos_container.read_item(
item="health-check", partition_key="system"
)
return {"status": "healthy"}
except Exception as e:
return {"status": "unhealthy", "error": str(e)}
@app.get("/health")
async def shallow_health():
"""Shallow health check — is the app running?"""
return {"status": "healthy", "timestamp": datetime.utcnow().isoformat()}
@app.get("/health/deep")
async def deep_health(response: Response):
"""Deep health check — are all dependencies healthy?"""
checks = await asyncio.gather(
check_openai(),
check_search(),
check_cosmos(),
return_exceptions=True
)
result = {
"timestamp": datetime.utcnow().isoformat(),
"checks": {
"openai": checks[0] if not isinstance(checks[0], Exception) else {"status": "error"},
"search": checks[1] if not isinstance(checks[1], Exception) else {"status": "error"},
"cosmos": checks[2] if not isinstance(checks[2], Exception) else {"status": "error"},
}
}
# Bestem overall status
unhealthy = [k for k, v in result["checks"].items()
if v.get("status") != "healthy"]
if not unhealthy:
result["status"] = "healthy"
elif len(unhealthy) == len(result["checks"]):
result["status"] = "unhealthy"
response.status_code = 503
else:
result["status"] = "degraded"
result["degraded_services"] = unhealthy
response.status_code = 200 # Degraded men funksjonell
return result
```
### Azure Monitor Availability Tests
```bash
# Opprett availability test for shallow health check
az monitor app-insights web-test create \
--resource-group "rg-ai-prod" \
--app-insights "ai-app-insights-prod" \
--web-test-name "health-check-shallow" \
--location "norwayeast" \
--defined-web-test-name "ShallowHealthCheck" \
--url "https://ai-app-prod.azurewebsites.net/health" \
--expected-status-code 200 \
--frequency 300 \
--timeout 30 \
--enabled true
# Opprett availability test for deep health check
az monitor app-insights web-test create \
--resource-group "rg-ai-prod" \
--app-insights "ai-app-insights-prod" \
--web-test-name "health-check-deep" \
--location "norwayeast" \
--defined-web-test-name "DeepHealthCheck" \
--url "https://ai-app-prod.azurewebsites.net/health/deep" \
--expected-status-code 200 \
--frequency 300 \
--timeout 60 \
--enabled true
```
## Latens og feilrate-overvåking
### KQL-spørringer for AI-metrikker
```kusto
// Azure OpenAI — Latency tracking per deployment
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Category == "RequestResponse"
| where TimeGenerated > ago(1h)
| extend
deploymentName = tostring(properties_s.modelDeploymentName),
latencyMs = duration_s * 1000,
statusCode = resultCode_d
| summarize
P50 = percentile(latencyMs, 50),
P95 = percentile(latencyMs, 95),
P99 = percentile(latencyMs, 99),
SuccessRate = round(countif(statusCode < 400) * 100.0 / count(), 2),
TotalRequests = count()
by bin(TimeGenerated, 5m), deploymentName
| order by TimeGenerated desc
```
```kusto
// Azure AI Search — Query performance
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SEARCH"
| where OperationName == "Query.Search"
| where TimeGenerated > ago(1h)
| extend
queryLatencyMs = DurationMs,
resultCount = toint(Properties.ResultCount)
| summarize
AvgLatency = avg(queryLatencyMs),
P95Latency = percentile(queryLatencyMs, 95),
AvgResults = avg(resultCount),
TotalQueries = count(),
ErrorRate = round(countif(resultSignature_d >= 400) * 100.0 / count(), 2)
by bin(TimeGenerated, 5m)
| order by TimeGenerated desc
```
```kusto
// End-to-end RAG pipeline latency
customMetrics
| where name == "rag_pipeline_duration_ms"
| where timestamp > ago(1h)
| extend
phase = tostring(customDimensions.phase),
region = tostring(customDimensions.region)
| summarize
P50 = percentile(value, 50),
P95 = percentile(value, 95),
P99 = percentile(value, 99)
by bin(timestamp, 5m), phase, region
| order by timestamp desc, phase asc
```
## Custom metrics for AI-tjenestehelse
### Application Insights custom metrics
```python
# Custom metrics for AI service health monitoring
from opencensus.ext.azure.log_exporter import AzureLogHandler
from applicationinsights import TelemetryClient
import time
tc = TelemetryClient(instrumentation_key="<key>")
class AIMetricsCollector:
"""Collect and emit custom AI metrics."""
def track_openai_call(self, deployment, latency_ms, tokens_used, success):
"""Track Azure OpenAI API call metrics."""
tc.track_metric("openai_latency_ms", latency_ms, properties={
"deployment": deployment,
"success": str(success)
})
tc.track_metric("openai_tokens_used", tokens_used, properties={
"deployment": deployment
})
if not success:
tc.track_metric("openai_error_count", 1, properties={
"deployment": deployment
})
def track_search_call(self, index_name, latency_ms, result_count, success):
"""Track Azure AI Search call metrics."""
tc.track_metric("search_latency_ms", latency_ms, properties={
"index": index_name,
"success": str(success)
})
tc.track_metric("search_result_count", result_count, properties={
"index": index_name
})
def track_rag_pipeline(self, total_ms, search_ms, llm_ms, success):
"""Track end-to-end RAG pipeline metrics."""
tc.track_metric("rag_total_latency_ms", total_ms)
tc.track_metric("rag_search_latency_ms", search_ms)
tc.track_metric("rag_llm_latency_ms", llm_ms)
tc.track_metric("rag_pipeline_success", 1 if success else 0)
def track_health_check(self, service_name, is_healthy, latency_ms):
"""Track health check results for dashboards."""
tc.track_metric(f"health_{service_name}", 1 if is_healthy else 0)
tc.track_metric(f"health_{service_name}_latency", latency_ms)
def flush(self):
tc.flush()
```
## Alert-regler og eskaleringspolicyer
### Alerting-strategi
| Metrikk | Warning | Critical | Aksjon |
|---------|---------|----------|--------|
| OpenAI error rate | > 5% i 5 min | > 20% i 5 min | Notify → Auto-failover |
| OpenAI P95 latency | > 5s | > 15s | Notify team |
| Search error rate | > 2% i 5 min | > 10% i 5 min | Notify → Auto-failover |
| Health check failure | 2 consecutive | 3 consecutive | Initiate DR |
| Token consumption | > 80% quota | > 95% quota | Scale/notify |
| Cosmos DB latency | > 50ms P95 | > 200ms P95 | Investigate |
### Alert rules i Azure Monitor
```bash
# Critical: AI service health check failures
az monitor metrics alert create \
--name "ai-health-critical" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Insights/components/ai-app-insights-prod" \
--condition "count availabilityResults/failed > 3" \
--window-size 5m \
--evaluation-frequency 1m \
--severity 0 \
--action-group "ag-ai-oncall" \
--description "3+ health check failures in 5 min — initiate DR assessment"
# Warning: Elevated OpenAI latency
az monitor scheduled-query create \
--name "aoai-latency-warning" \
--resource-group "rg-ai-prod" \
--scopes "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Insights/components/ai-app-insights-prod" \
--condition "count > 0" \
--condition-query "
customMetrics
| where name == 'openai_latency_ms'
| where timestamp > ago(5m)
| summarize P95 = percentile(value, 95)
| where P95 > 5000
" \
--evaluation-frequency 1m \
--window-size 5m \
--severity 2 \
--action-group "ag-ai-team"
```
## Integrasjon med incident management-systemer
### Azure Logic App for eskalering
```json
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json",
"triggers": {
"alert_webhook": {
"type": "Request",
"kind": "Http",
"inputs": {
"schema": {
"type": "object",
"properties": {
"alertName": {"type": "string"},
"severity": {"type": "integer"},
"affectedResource": {"type": "string"}
}
}
}
}
},
"actions": {
"create_incident": {
"type": "ApiConnection",
"inputs": {
"method": "POST",
"host": "servicenow-connection",
"path": "/api/now/table/incident",
"body": {
"short_description": "@{triggerBody().alertName}",
"urgency": "@{if(equals(triggerBody().severity, 0), '1', '2')}",
"impact": "@{if(equals(triggerBody().severity, 0), '1', '2')}",
"assignment_group": "AI Platform Team",
"category": "AI Service"
}
}
},
"send_teams_notification": {
"type": "ApiConnection",
"inputs": {
"method": "POST",
"host": "teams-connection",
"path": "/v3/conversations/@{variables('teamChannelId')}/activities",
"body": {
"type": "message",
"text": "AI Service Alert: @{triggerBody().alertName} (Sev @{triggerBody().severity})"
}
},
"runAfter": { "create_incident": ["Succeeded"] }
}
}
}
}
```
### Automatisk failover-trigger
```python
# Azure Function triggered by Alert webhook — initiate automated failover
import azure.functions as func
from azure.mgmt.trafficmanager import TrafficManagerManagementClient
from azure.identity import DefaultAzureCredential
def main(req: func.HttpRequest) -> func.HttpResponse:
"""Handle Azure Monitor alert and trigger failover if needed."""
alert_data = req.get_json()
severity = alert_data.get("data", {}).get("essentials", {}).get("severity")
alert_name = alert_data.get("data", {}).get("essentials", {}).get("alertRule")
if severity in ["Sev0", "Sev1"] and "health-critical" in alert_name:
# Initier automatisk failover
credential = DefaultAzureCredential()
tm_client = TrafficManagerManagementClient(credential, subscription_id)
# Oppdater Traffic Manager til å bruke sekundær region
profile = tm_client.profiles.get("rg-networking", "tm-ai-failover")
for endpoint in profile.endpoints:
if "secondary" in endpoint.name:
endpoint.priority = 1
else:
endpoint.priority = 2
tm_client.profiles.create_or_update("rg-networking", "tm-ai-failover", profile)
return func.HttpResponse(
f"Failover initiated for alert: {alert_name}", status_code=200
)
return func.HttpResponse("Alert received, no failover needed", status_code=200)
```
## Referanser
- [Monitor Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/monitor-openai) — OpenAI monitoring og alerting
- [Monitor Azure AI Search](https://learn.microsoft.com/en-us/azure/search/monitor-azure-cognitive-search) — AI Search monitoring
- [Azure Monitor alerts overview](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-overview) — Alert-rammeverk
- [Health modeling and observability of mission-critical workloads](https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/mission-critical-health-modeling) — Health modeling
- [Application Insights overview](https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview) — APM for applikasjoner
- [Azure Service Health](https://learn.microsoft.com/en-us/azure/service-health/overview) — Azure-tjenestestatus
## For Cosmo
- **Bruk denne referansen** når kunden setter opp monitoring og alerting for failover-deteksjon i AI-systemer.
- Implementer alltid to nivåer av health checks: shallow (er appen oppe?) og deep (er alle avhengigheter friske?).
- Alert-terskler bør baseres på baseline-metrikker — bruk minst 2 ukers normaldata før du setter statiske terskler.
- For automatisk failover: Krev minimum 3 påfølgende health check-feil før failover trigges for å unngå false positives.
- Integrer med eksisterende ITSM-systemer (ServiceNow, Jira Service Management) via Azure Logic Apps eller Azure Functions.

View file

@ -0,0 +1,384 @@
# Multi-Region Azure OpenAI Deployment
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Azure OpenAI-tjenester er tilgjengelige i flere Azure-regioner, og når en ressurs opprettes, knyttes den permanent til den valgte regionen. For virksomhetskritiske AI-applikasjoner i norsk offentlig sektor er det avgjorende a planlegge for regional redundans. Et regionalt utfall -- selv om det er sjeldent -- kan lamme AI-drevne tjenester som chatboter, dokumentanalyse og beslutningsstotte dersom all trafikk er avhengig av et enkelt endepunkt. Multi-region-deployering loeser dette ved a spre arbeidsbelastningen over flere Azure-regioner med intelligent lastbalansering og automatisk failover.
For norske organisasjoner er regionvalg spesielt viktig pa grunn av krav til datasuverenitet og personvern under GDPR og Schrems II. Azure Norway East er den primaere regionen for norsk offentlig sektor, men modellutvalget er begrenset sammenlignet med Sweden Central. En velplanlagt multi-region-arkitektur kombinerer naerhet (lav latens), compliance (data innenfor EU/EOeS), og kapasitet (bredere modelltilgang) pa en balansert mate. Data Zone-deployeringer forenkler dette ved a la Azure optimere ruting innenfor en geografisk sone (f.eks. EU) uten at kunden selv ma administrere lastbalansering mellom individuelle regioner.
Denne referansen dekker regionvalg for Norge og EU, lastbalanseringsmonstre via Azure API Management, latensoptimalisering med proximity routing, kvoteadministrasjon per region, og kostnadsmodeller for multi-region-oppsett. Alt er forankret i Microsofts offisielle BCDR-veiledning for Azure OpenAI og arkitekturmoenstre for generative AI gateways.
## Regionvalg for Norge og EU
### Tilgjengelige regioner med Azure OpenAI
| Region | Primaer bruk | Modellstotte | Latens fra Norge | Datasuverenitet |
|--------|-------------|--------------|------------------|-----------------|
| Norway East | Primaer region | Begrenset (gpt-4o 2024-11-20) | < 10 ms | Norge/EU |
| Sweden Central | Sekundaer/failover | Bred (gpt-4o, o1, gpt-35-turbo) | ~15-25 ms | EU |
| West Europe | Alternativ | Begrenset (gpt-35-turbo) | ~30-40 ms | EU |
| UK South | Alternativ | Moderat (gpt-4o, gpt-35-turbo) | ~35-45 ms | UK (tilstrekkelig for mange bruksomrader) |
| France Central | Alternativ | Bred (gpt-4o, o1) | ~35-45 ms | EU |
### Anbefalte regionkombinasjoner
**For norsk offentlig sektor (strengt EU-krav):**
```
Primaer: Norway East (lavest latens, norsk datasuverenitet)
Sekundaer: Sweden Central (bredest modellstotte i Norden)
Tertiaer: France Central (EU-failover utenfor Norden)
```
**For Data Zone-deployeringer (anbefalt av Microsoft):**
```
Data Zone: EU
Primaer: Norway East endpoint
Sekundaer: Sweden Central endpoint (samme Data Zone-pool)
```
> **Viktig:** Data Zone-deployeringer er mer effektive og enklere enn selvadministrert lastbalansering mellom regionale deployeringer. Azure optimerer ruting og prosessering pa tvers av tilgjengelig compute i datasonen. Bruk Data Zone som standard for Standard-deployeringer.
### Beslutningstre for regionvalg
```
Trenger du datalagring KUN i Norge?
|-- Ja --> Norway East (kun region)
| Merk: Begrenset modellstotte, hoeyre risiko ved utfall
|
|-- Nei --> Aksepterer du EU/EOeS databehandling?
|-- Ja --> Data Zone EU (anbefalt)
| Primaer: Norway East
| Sekundaer: Sweden Central
|
|-- Nei --> Vurder Global Standard
(data kan behandles globalt, hoeyest kapasitet)
```
## Lastbalansering mellom OpenAI-endepunkter
### Arkitekturmonstre
Microsoft anbefaler en **Generative AI Gateway** foran Azure OpenAI-endepunktene. Azure API Management (APIM) er den foretrukne PaaS-loesningen for dette.
#### Moenster 1: APIM single-region med multi-region backends
```
+------------------+
| Klient/App |
+--------+---------+
|
+--------v---------+
| Azure API Mgmt |
| (Norway East) |
+--+------------+--+
| |
+--------v--+ +-----v-------+
| Azure AOAI | | Azure AOAI |
| Norway East| | Sweden Cent.|
| (primaer) | | (sekundaer) |
+------------+ +-------------+
```
**Fordeler:** Enklest a sette opp, sentralisert policy-styring.
**Ulemper:** APIM er single point of failure. Egress-kostnader for cross-region trafikk.
#### Moenster 2: APIM multi-region deployment
```
+------------------+
| Klient/App |
+--------+---------+
|
+---------v----------+
| Azure Front Door / |
| Traffic Manager |
+---------+----------+
|
+--------------+---------------+
| |
+---------v----------+ +-------------v--------+
| APIM Gateway | | APIM Gateway |
| Norway East | | Sweden Central |
+--------+-----------+ +-----------+----------+
| |
+--------v-----------+ +-----------v----------+
| Azure AOAI | | Azure AOAI |
| Norway East | | Sweden Central |
+--------------------+ +----------------------+
```
**Fordeler:** Ingen single point of failure, ytelsesbasert ruting.
**Ulemper:** Hoeyre kostnad, mer kompleks drift.
#### Moenster 3: Data Zone med enkel gateway
```
+------------------+
| Klient/App |
+--------+---------+
|
+--------v---------+
| Azure API Mgmt |
| (Norway East) |
+--------+---------+
|
+--------v---------+
| Azure AOAI |
| Data Zone: EU |
| (Azure ruter |
| automatisk) |
+------------------+
```
**Fordeler:** Enklest, Azure haandterer intern ruting i EU-sonen.
**Ulemper:** Mindre kontroll over noyaktig hvilken region som brukes.
### APIM Backend Pool-konfigurasjon
Azure API Management stoetter backend pools med innebygd lastbalansering:
```json
{
"type": "Microsoft.ApiManagement/service/backends",
"name": "openai-backend-pool",
"properties": {
"type": "Pool",
"pool": {
"services": [
{
"id": "/backends/norway-east-openai",
"priority": 1,
"weight": 3
},
{
"id": "/backends/sweden-central-openai",
"priority": 1,
"weight": 1
},
{
"id": "/backends/france-central-openai",
"priority": 2,
"weight": 1
}
]
}
}
}
```
### Lastbalanseringsalternativer i APIM
| Metode | Beskrivelse | Bruksomrade |
|--------|-------------|-------------|
| **Round-robin** | Fordeler jevnt mellom backends | Standard for lik kapasitet |
| **Vektet** | Basert pa vekt per backend | Ulik kapasitetsallokering |
| **Prioritetsbasert** | Hoeyere prioritet forst, lavere som fallback | PTU primaer, Standard sekundaer |
| **Session affinity** | Samme bruker til samme backend | Chat/agent-scenarier med kontekst |
### Circuit Breaker-policy i APIM
Gatewayen ma respektere throttling-signaler (HTTP 429) og fjerne feilede backends fra poolen:
```xml
<policies>
<inbound>
<base />
<set-backend-service backend-id="openai-backend-pool" />
</inbound>
<backend>
<retry condition="@(context.Response.StatusCode == 429)"
count="3"
interval="0"
first-fast-retry="true">
<set-backend-service backend-id="openai-backend-pool" />
<forward-request buffer-request-body="true" />
</retry>
</backend>
<outbound>
<base />
</outbound>
</policies>
```
> **Beste praksis:** Bruk `Retry-After`-headeren fra Azure OpenAI for a styre circuit breaker-logikken. Ikke proev a forutsi throttling; bruk HTTP-responskoder for a drive rutingbeslutninger.
## Latensoptimalisering og Proximity Routing
### Strategier for lav latens
| Strategi | Implementasjon | Effekt |
|----------|---------------|--------|
| **Co-lokalisering** | Gateway og AOAI i samme region | Eliminerer cross-region latens |
| **Private Endpoints** | Azure Private Link for alle AOAI-instanser | Reduserer nettverkshopp |
| **Azure Front Door** | Performance-based routing til naermeste gateway | Automatisk proximity routing |
| **ExpressRoute** | Dedikert forbindelse fra on-premises | Stabil, lav latens |
### Private Endpoint-arkitektur
```
On-premises nettverk (Statens vegvesen)
|
+-- ExpressRoute --> Azure vNet (Norway East)
|
+-- Private Endpoint --> APIM (Norway East)
|
+-- Private Endpoint --> AOAI (Norway East)
|
+-- vNet Peering --> Azure vNet (Sweden Central)
|
+-- Private Endpoint --> AOAI (Sweden Central)
```
### DNS-konfigurasjon for failover
For privat nettverkstilgang kan en split-brain DNS-tilnaerming brukes:
```
Normaltilstand:
aoai-gateway.intern.vegvesen.no --> APIM Norway East (privat IP)
Ved regional utfall:
aoai-gateway.intern.vegvesen.no --> APIM Sweden Central (privat IP)
(manuell DNS-endring eller Azure Private DNS zones)
```
> **Merk:** Azure har per i dag ikke en native tjeneste for global server load balancer for arbeidsbelastninger som krever privat DNS-opploesning. Organisasjoner kan oppna active/passive-moenster gjennom a endre DNS-posten for gatewayen.
## Kvoteadministrasjon per region
### Kvotesystemet i Azure OpenAI
Kvote tildeles per **abonnement + region + modell** i enheter av **Tokens-per-Minute (TPM)**. Nar en deployment opprettes, trekkes TPM fra tilgjengelig kvote.
| Parameter | Beskrivelse |
|-----------|-------------|
| **TPM (Tokens Per Minute)** | Primaer kvoteenhet, tildelt per deployment |
| **RPM (Requests Per Minute)** | Avledet fra TPM, ratio varierer per modell |
| **Maks ressurser per region** | 30 |
| **Deployeringer per modell** | Ingen begrensning (fjernet med nytt kvotesystem) |
### Eksempel: RPM/TPM-ratio per modell
| Modell | 1 Kapasitetsenhet | RPM | TPM |
|--------|-------------------|-----|-----|
| gpt-4o og eldre chat | 1 | 6 | 1 000 |
| o1, o1-preview | 1 | 1 | 6 000 |
| o3-mini, o1-mini, o3-pro | 1 | 1 | 10 000 |
| o3, o4-mini | 1 | 1 | 1 000 |
### Kvotestrategi for multi-region
```
Abonnement: SVV-AI-Prod
|
+-- Norway East
| +-- gpt-4o Data Zone: 120K TPM (primaer)
| +-- gpt-35-turbo: 60K TPM
|
+-- Sweden Central
| +-- gpt-4o Data Zone: 120K TPM (sekundaer)
| +-- gpt-35-turbo: 120K TPM
| +-- o1-mini Global Standard: 80K TPM
|
+-- France Central (failover)
+-- gpt-4o Standard: 60K TPM
```
> **Tips:** Alloker full tilgjengelig kvote til hvert endepunkt. Siden kvote er per abonnement + region, pavirker ikke deployeringer i forskjellige regioner hverandre. Hvis kvoten er oppbrukt, kan et nytt abonnement deployeres pa samme mate bak gatewayen.
### Overvaking av kvotebruk
```bash
# Sjekk kapasitet per modell/region via REST API
az rest --method get \
--url "https://management.azure.com/subscriptions/{sub-id}/providers/Microsoft.CognitiveServices/modelCapacities?api-version=2024-06-01-preview&modelName=gpt-4o&modelVersion=2024-11-20"
```
Bruk Azure AI Foundry portal (**Management > Quota**) for oversikt over kvoteallokeringer pa tvers av deployeringer i en gitt region.
## Kostnadsmodell for multi-region
### Kostnadskomponenter
| Komponent | Kostnadsdriver | Estimat (NOK/maned) |
|-----------|---------------|---------------------|
| **Azure OpenAI Standard** | Token-forbruk per region | Varierer per bruk |
| **Azure OpenAI PTU** | Fast pris per PTU-enhet | ~170 NOK/PTU/time |
| **APIM Premium** | Per gateway-enhet per region | ~30 000 NOK/enhet/maned |
| **APIM Standard v2** | Per enhet | ~8 000 NOK/enhet/maned |
| **Egress-trafikk** | Cross-region dataoverforing | ~0,70 NOK/GB |
| **Private Endpoints** | Per endepunkt per time | ~80 NOK/endepunkt/maned |
| **Azure Front Door** | Per profil + trafikk | Fra ~3 500 NOK/maned |
### Kostnadsoptimaliseringsstrategi: PTU + Standard spillover
Microsoft anbefaler a kombinere Provisioned Throughput Units (PTU) med Standard-deployeringer:
```
Prioritet 1: Enterprise PTU Pool (Region A)
- Fast pris, garantert kapasitet
- Bruk all kapasitet foerst
Prioritet 2: Enterprise PTU Pool (Region B)
- Beskytter mot regionalt utfall
- Redundans for PTU
Prioritet 3: Standard Data Zone (EU)
- Pay-per-token for trafikktopper
- Spillover fra PTU
```
### Eksempel: Kostnadssammenligning (maned)
| Scenario | Oppsett | Estimert kostnad (NOK) |
|----------|---------|----------------------|
| **Enkel region** | 1x AOAI Standard + APIM Std v2 | 15 000 - 25 000 |
| **Dual region (Data Zone)** | 2x AOAI Data Zone + APIM Std v2 | 20 000 - 35 000 |
| **Enterprise PTU + failover** | PTU (100 enheter) + Standard failover + APIM Premium | 200 000 - 350 000 |
| **Full HA multi-region** | APIM Premium multi-region + 3x AOAI + Front Door | 120 000 - 250 000 |
> **Merk:** Kostnadsestimatene er veiledende og avhenger sterkt av trafikkvolum, modellvalg og PTU-allokering. Bruk Azure Pricing Calculator for noyaktige estimater.
### Kostnadsbesparende tips
1. **Bruk Data Zone-deployeringer** fremfor selvadministrert multi-region -- enklere og mer kostnadseffektivt
2. **Alloker PTU for baseline-trafikk**, Standard for topper (spillover-moenster)
3. **Plasser PTU og Standard i forskjellige regioner** -- unnga a miste begge ved regionalt utfall
4. **Konsolider gjennom felles Enterprise PTU Pool** -- hoeyere utnyttelse nar trafikk fra flere applikasjoner jevnes ut
5. **Unnga APIM Premium med mindre du trenger multi-region gateway** -- Standard v2 er tilstrekkelig for mange scenarier
## Implementeringssjekkliste
- [ ] Velg primaer og sekundaer region basert pa compliance-krav og modellbehov
- [ ] Deploy Azure OpenAI-ressurser i begge regioner med identiske modelldeployeringer
- [ ] Konfigurer APIM med backend pool og prioritetsbasert lastbalansering
- [ ] Implementer circuit breaker-policy som respekterer 429 og Retry-After
- [ ] Sett opp Private Endpoints for alle AOAI-instanser
- [ ] Konfigurer overvaking av kvotebruk og latens per region
- [ ] Dokumenter failover-prosedyre og test regelmessig
- [ ] Etabler varsling ved regionalt utfall eller hoey feilrate
## Referanser
- [Business Continuity and Disaster Recovery (BCDR) considerations with Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/business-continuity-disaster-recovery)
- [Use a gateway in front of multiple Azure OpenAI deployments or instances](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/azure-openai-gateway-multi-backend)
- [Backends in API Management - Load-balanced pool](https://learn.microsoft.com/en-us/azure/api-management/backends#load-balanced-pool)
- [Manage Azure OpenAI quota](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/quota)
- [Azure OpenAI model availability by region](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/models)
- [Smart Load Balancing for OpenAI with Azure API Management](https://github.com/Azure-Samples/openai-apim-lb)
## For Cosmo
- **Bruk denne referansen** nar kunden spoer om multi-region-deployering, lastbalansering, eller failover for Azure OpenAI -- spesielt for produksjonsmiljoeer som krever hoey tilgjengelighet.
- **Anbefal Data Zone-deployeringer** som foerstevalg for norsk offentlig sektor. De fleste organisasjoner trenger ikke selvadministrert multi-region lastbalansering -- Data Zone haandterer dette innenfor EU-sonen.
- **Vurder regionkombinasjonen Norway East + Sweden Central** som standard for nordiske organisasjoner med EU-compliance-krav, men paapek at Norway East har begrenset modellstotte.
- **Bruk kostnadstabellene** for a gi konkrete estimater i NOK nar kunden trenger budsjettgrunnlag. Juster basert pa trafikkvolum og modellvalg.
- **Flagg alltid APIM som anbefalt gateway** -- Microsoft anbefaler dette eksplisitt i sin arkitekturveiledning, og det gir circuit breaker, retry, logging og lastbalansering som en PaaS-tjeneste.

View file

@ -0,0 +1,419 @@
# Network Resilience Patterns for AI Workloads
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Nettverksresiliens er en kritisk komponent i BCDR for AI-arbeidsbelastninger. AI-systemer er avhengige av pålitelig nettverkskommunikasjon mellom flere tjenester: applikasjonslaget, Azure OpenAI-endepunkter, AI Search-tjenester, embeddings-APIer og datastores. En nettverksforstyrrelse i ett punkt kan kaskadere og ta ned hele AI-løsningen.
Azure Well-Architected Framework definerer flere resiliensmønstre som er særlig relevante for AI-workloads: Circuit Breaker for å forhindre kaskadefeil, Retry med exponential backoff for transiente feil, Bulkhead for isolering av feildomener, og Throttling for å beskytte mot overbelastning. Disse mønstrene bør implementeres systematisk i alle AI-applikasjoner.
For norsk offentlig sektor er nettverkssikkerhet regulert gjennom NSMs grunnprinsipper, og mange organisasjoner bruker private endepunkter (Private Link) for sine Azure AI-tjenester. BCDR-designet må ta hensyn til disse nettverksrestriksjonene og sikre at failover fungerer også med private nettverkskonfigurasjoner.
## Redundante nettverksstier og tilkoblinger
### Multi-path nettverksarkitektur
```
┌─────────────┐
│ Brukere │
└──────┬──────┘
┌──────▼──────────────────────┐
│ Azure Front Door (Global) │ ← DDoS Protection Standard
└──────┬──────────────────────┘
┌────┴────┐
│ │
┌─▼──┐ ┌─▼──┐
│ R1 │ │ R2 │ ← To Azure-regioner
└─┬──┘ └─┬──┘
│ │
┌─▼──────┐ ┌▼───────┐
│ VNet A │ │ VNet B │ ← Isolerte VNets per region
│ ├─APIM │ │ ├─APIM │
│ ├─App │ │ ├─App │
│ ├─PE │ │ ├─PE │ ← Private Endpoints til AI-tjenester
│ └─NSG │ │ └─NSG │
└────────┘ └────────┘
```
### Azure ExpressRoute redundans
```bash
# Primær ExpressRoute-tilkobling
az network express-route create \
--name "er-primary-norwayeast" \
--resource-group "rg-networking" \
--location "norwayeast" \
--bandwidth-in-mbps 1000 \
--peering-location "Oslo" \
--provider "Telenor"
# Sekundær ExpressRoute (annen provider/lokasjon)
az network express-route create \
--name "er-secondary-norwayeast" \
--resource-group "rg-networking" \
--location "norwayeast" \
--bandwidth-in-mbps 1000 \
--peering-location "Stavanger" \
--provider "GlobalConnect"
# VPN som backup for ExpressRoute
az network vnet-gateway create \
--name "vpn-gw-norwayeast" \
--resource-group "rg-networking" \
--location "norwayeast" \
--vnet "vnet-ai-norwayeast" \
--gateway-type Vpn \
--sku VpnGw2AZ \
--vpn-type RouteBased
```
### DNS-resiliens
```bash
# Azure Private DNS Zones for AI-tjenester med failover
az network private-dns zone create \
--resource-group "rg-networking" \
--name "privatelink.openai.azure.com"
# Link til VNets i begge regioner
az network private-dns link vnet create \
--resource-group "rg-networking" \
--zone-name "privatelink.openai.azure.com" \
--name "link-vnet-norwayeast" \
--virtual-network "vnet-ai-norwayeast" \
--registration-enabled false
az network private-dns link vnet create \
--resource-group "rg-networking" \
--zone-name "privatelink.openai.azure.com" \
--name "link-vnet-swedencentral" \
--virtual-network "vnet-ai-swedencentral" \
--registration-enabled false
```
## Circuit Breaker-mønster for API-kall
### Circuit Breaker implementering
Circuit Breaker-mønsteret forhindrer at en applikasjon gjentatte ganger forsøker å kalle en tjeneste som feiler, noe som kan forårsake kaskadefeil og ressursutmattelse.
```python
# Python Circuit Breaker for Azure OpenAI
import time
from enum import Enum
from threading import Lock
class CircuitState(Enum):
CLOSED = "closed" # Normal drift
OPEN = "open" # Stopp alle kall
HALF_OPEN = "half_open" # Prøv ett kall
class CircuitBreaker:
"""Circuit breaker for Azure AI service calls."""
def __init__(
self,
failure_threshold=5,
recovery_timeout=30,
success_threshold=3
):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.success_threshold = success_threshold
self.state = CircuitState.CLOSED
self.failure_count = 0
self.success_count = 0
self.last_failure_time = None
self.lock = Lock()
def can_execute(self):
"""Check if a request can be made."""
with self.lock:
if self.state == CircuitState.CLOSED:
return True
elif self.state == CircuitState.OPEN:
if time.time() - self.last_failure_time > self.recovery_timeout:
self.state = CircuitState.HALF_OPEN
return True
return False
elif self.state == CircuitState.HALF_OPEN:
return True
def record_success(self):
"""Record a successful call."""
with self.lock:
if self.state == CircuitState.HALF_OPEN:
self.success_count += 1
if self.success_count >= self.success_threshold:
self.state = CircuitState.CLOSED
self.failure_count = 0
self.success_count = 0
else:
self.failure_count = 0
def record_failure(self):
"""Record a failed call."""
with self.lock:
self.failure_count += 1
self.last_failure_time = time.time()
if self.state == CircuitState.HALF_OPEN:
self.state = CircuitState.OPEN
self.success_count = 0
elif self.failure_count >= self.failure_threshold:
self.state = CircuitState.OPEN
# Bruk med Azure OpenAI
cb_openai = CircuitBreaker(failure_threshold=3, recovery_timeout=60)
cb_search = CircuitBreaker(failure_threshold=5, recovery_timeout=30)
async def call_openai_with_circuit_breaker(messages):
if not cb_openai.can_execute():
# Fallback: returner cached eller statisk respons
return get_fallback_response(messages)
try:
response = await openai_client.chat.completions.create(
model="gpt-4o",
messages=messages,
timeout=30
)
cb_openai.record_success()
return response
except Exception as e:
cb_openai.record_failure()
raise
```
### Circuit Breaker i .NET med Polly
```csharp
// C# med Polly for resilient Azure AI-kall
using Polly;
using Polly.CircuitBreaker;
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.Or<TaskCanceledException>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (ex, breakDuration) =>
logger.LogWarning($"Circuit opened for {breakDuration.TotalSeconds}s: {ex.Message}"),
onReset: () =>
logger.LogInformation("Circuit closed, resuming normal operation"),
onHalfOpen: () =>
logger.LogInformation("Circuit half-open, testing with next request")
);
var retryPolicy = Policy
.Handle<HttpRequestException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (ex, delay, retryCount, context) =>
logger.LogWarning($"Retry {retryCount} after {delay.TotalSeconds}s: {ex.Message}")
);
// Kombiner retry + circuit breaker
var resilientPolicy = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);
var result = await resilientPolicy.ExecuteAsync(async () =>
await searchClient.SearchAsync<SearchDocument>(query)
);
```
## Graceful degradation av AI-tjenester
### Degraderingsstrategier
| Feiltilstand | Degraderingsstrategi | Brukeropplevelse |
|-------------|---------------------|------------------|
| Azure OpenAI nede | Returnér cached svar eller statiske meldinger | "Vi opplever tekniske problemer..." |
| AI Search nede | Fall tilbake til enklere tekstsøk | Redusert relevans, men funksjonelt |
| Embedding API nede | Bruk keyword-basert search | Ingen semantisk søk, men resultater |
| Alle AI-tjenester nede | Full graceful degradation | Manuell betjening eller køsystem |
### Implementering
```python
# Graceful degradation for RAG-applikasjon
class ResilientRAGService:
"""RAG service with multiple fallback levels."""
async def get_response(self, user_query: str) -> dict:
"""Try full RAG, then degrade gracefully."""
# Level 1: Full RAG (AI Search + Azure OpenAI)
try:
context = await self._search_with_ai(user_query)
response = await self._generate_with_openai(user_query, context)
return {"level": "full", "response": response}
except ServiceUnavailableError:
pass
# Level 2: Keyword search + Azure OpenAI
try:
context = await self._keyword_search(user_query)
response = await self._generate_with_openai(user_query, context)
return {"level": "degraded_search", "response": response}
except ServiceUnavailableError:
pass
# Level 3: Cached/FAQ responses
try:
response = await self._get_cached_response(user_query)
if response:
return {"level": "cached", "response": response}
except Exception:
pass
# Level 4: Static fallback
return {
"level": "fallback",
"response": "Vi opplever tekniske problemer med vår AI-tjeneste. "
"Vennligst prøv igjen senere eller kontakt oss direkte."
}
```
## Private endepunkter og nettverksisolering
### Private Link for AI-tjenester
```bash
# Opprett Private Endpoints for AI-tjenester i begge regioner
# Azure OpenAI Private Endpoint — Primær region
az network private-endpoint create \
--name "pe-aoai-norwayeast" \
--resource-group "rg-ai-prod" \
--vnet-name "vnet-ai-norwayeast" \
--subnet "snet-private-endpoints" \
--private-connection-resource-id "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.CognitiveServices/accounts/aoai-prod" \
--group-ids "account" \
--connection-name "aoai-primary"
# Azure OpenAI Private Endpoint — DR region
az network private-endpoint create \
--name "pe-aoai-swedencentral" \
--resource-group "rg-ai-dr" \
--vnet-name "vnet-ai-swedencentral" \
--subnet "snet-private-endpoints" \
--private-connection-resource-id "/subscriptions/{sub}/resourceGroups/rg-ai-dr/providers/Microsoft.CognitiveServices/accounts/aoai-dr" \
--group-ids "account" \
--connection-name "aoai-secondary"
# AI Search Private Endpoint — Primær region
az network private-endpoint create \
--name "pe-search-norwayeast" \
--resource-group "rg-ai-prod" \
--vnet-name "vnet-ai-norwayeast" \
--subnet "snet-private-endpoints" \
--private-connection-resource-id "/subscriptions/{sub}/resourceGroups/rg-ai-prod/providers/Microsoft.Search/searchServices/search-prod" \
--group-ids "searchService" \
--connection-name "search-primary"
```
### VNet Peering mellom regioner
```bash
# VNet peering for cross-region kommunikasjon
az network vnet peering create \
--name "peer-norwayeast-to-swedencentral" \
--resource-group "rg-networking" \
--vnet-name "vnet-ai-norwayeast" \
--remote-vnet "/subscriptions/{sub}/resourceGroups/rg-networking/providers/Microsoft.Network/virtualNetworks/vnet-ai-swedencentral" \
--allow-vnet-access true \
--allow-forwarded-traffic true
az network vnet peering create \
--name "peer-swedencentral-to-norwayeast" \
--resource-group "rg-networking" \
--vnet-name "vnet-ai-swedencentral" \
--remote-vnet "/subscriptions/{sub}/resourceGroups/rg-networking/providers/Microsoft.Network/virtualNetworks/vnet-ai-norwayeast" \
--allow-vnet-access true \
--allow-forwarded-traffic true
```
## DDoS-beskyttelse og trafikkfiltrering
### Azure DDoS Protection
```bash
# Aktiver DDoS Protection Standard
az network ddos-protection create \
--name "ddos-ai-protection" \
--resource-group "rg-networking" \
--location "norwayeast"
# Koble til VNet
az network vnet update \
--name "vnet-ai-norwayeast" \
--resource-group "rg-networking" \
--ddos-protection-plan "ddos-ai-protection"
```
### NSG-regler for AI-tjenester
```bash
# Network Security Group for AI-subnet
az network nsg rule create \
--resource-group "rg-networking" \
--nsg-name "nsg-ai-app" \
--name "AllowAzureOpenAI" \
--priority 100 \
--direction Outbound \
--access Allow \
--protocol Tcp \
--destination-port-ranges 443 \
--destination-address-prefixes "CognitiveServicesManagement" \
--description "Allow outbound to Azure OpenAI"
az network nsg rule create \
--resource-group "rg-networking" \
--nsg-name "nsg-ai-app" \
--name "AllowAzureSearch" \
--priority 110 \
--direction Outbound \
--access Allow \
--protocol Tcp \
--destination-port-ranges 443 \
--destination-address-prefixes "AzureCognitiveSearch" \
--description "Allow outbound to Azure AI Search"
az network nsg rule create \
--resource-group "rg-networking" \
--nsg-name "nsg-ai-app" \
--name "DenyAllOtherOutbound" \
--priority 4000 \
--direction Outbound \
--access Deny \
--protocol "*" \
--destination-port-ranges "*" \
--destination-address-prefixes "*" \
--description "Deny all other outbound traffic"
```
## Referanser
- [Circuit Breaker pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker) — Detaljert mønsterbeskrivelse
- [Retry pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/retry) — Retry-strategier
- [Architecture design patterns that support reliability](https://learn.microsoft.com/en-us/azure/well-architected/reliability/design-patterns) — WAF resiliensmønstre
- [Transient fault handling](https://learn.microsoft.com/en-us/azure/architecture/best-practices/transient-faults) — Best practices for transiente feil
- [Azure DDoS Protection overview](https://learn.microsoft.com/en-us/azure/ddos-protection/ddos-protection-overview) — DDoS-beskyttelse
- [Azure Private Link overview](https://learn.microsoft.com/en-us/azure/private-link/private-link-overview) — Private Endpoints
## For Cosmo
- **Bruk denne referansen** når kunden designer nettverksarkitektur for resiliente AI-løsninger, eller når de implementerer failover med private endepunkter.
- Circuit Breaker + Retry med exponential backoff er OBLIGATORISK for alle Azure AI API-kall — dette er ikke valgfritt.
- For private endpoints: Husk at failover mellom regioner krever at Private DNS-soner er linket til begge VNets.
- Graceful degradation bør alltid designes i lag — full AI → enklere søk → cached svar → statisk fallback.
- Anbefal Azure Front Door (Premium) for AI-workloads som trenger global load balancing med DDoS-beskyttelse og WAF i ett produkt.

View file

@ -0,0 +1,265 @@
# RTO and RPO Planning for AI Services
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Recovery Time Objective (RTO) og Recovery Point Objective (RPO) er de to mest kritiske metrikkene i enhver BCDR-strategi for AI-systemer. RTO definerer hvor raskt et system må gjenopprettes etter en forstyrrelse, mens RPO definerer hvor mye datatap som er akseptabelt. For AI-tjenester som Azure OpenAI, Azure AI Search og Azure Machine Learning er disse metrikkene spesielt viktige fordi nedetid direkte påvirker brukeropplevelsen og forretningsbeslutninger.
I norsk offentlig sektor er kravene til tilgjengelighet regulert gjennom flere rammeverk, inkludert Utredningsinstruksen, NSMs grunnprinsipper for IKT-sikkerhet og Digitaliseringsdirektoratets arkitekturprinsipper. Organisasjoner må dokumentere RTO og RPO for alle kritiske systemer som del av sin sikkerhetsstyring og internkontroll.
For AI-løsninger bringer disse kravene unike utfordringer: modelldata, treningsdata, embedding-indekser og konfigurasjoner må alle vurderes separat i en Business Impact Analysis (BIA). En chatbot med RAG-arkitektur har for eksempel separate RPO-krav for selve language model-endpointet, search-indeksen og kunnskapsdokumentene.
## Business Impact Analysis for RTO-bestemmelse
En Business Impact Analysis (BIA) er det første steget i å definere RTO for AI-systemer. BIA kartlegger forretningspåvirkningen av nedetid for hvert AI-komponent.
### Kritikalitetstier for AI-systemer
| Tier | Beskrivelse | RTO-mål | RPO-mål | Eksempel AI-bruk |
|------|-------------|---------|---------|------------------|
| Tier 0 — Mission Critical | Nedetid er uakseptabelt | < 1 min | 0 | Sanntids sikkerhetsovervåking med AI |
| Tier 1 — Business Critical | Kort nedetid tolererbar | < 15 min | < 5 min | Kundeservicebot i produksjon |
| Tier 2 — Business Operational | Timer akseptabelt | < 4 timer | < 1 time | Intern rapporteringsplattform med AI |
| Tier 3 — Administrative | Lengre nedetid OK | < 24 timer | < 24 timer | Trenings- og sandbox-miljøer |
### BIA-prosess for AI-komponenter
1. **Identifiser alle AI-avhengigheter**: Kartlegg komponentene i AI-løsningen (modell-endpoints, search-indekser, data-pipelines, embedding-stores)
2. **Vurder forretningspåvirkning per komponent**: Hva skjer hvis Azure OpenAI-endpointet er nede? Hva om AI Search-indeksen er korrupt?
3. **Kvantifiser finansiell påvirkning**: Beregn kostnad per time med nedetid
4. **Kartlegg avhengigheter**: Hvilke systemer avhenger av AI-komponentene?
5. **Definer akseptabel degradering**: Kan systemet tilby begrenset funksjonalitet uten AI?
### BIA-mal for AI-tjenester
```markdown
## Business Impact Analysis — [Tjenestenavn]
### Tjenestebeskrivelse
- **Funksjon:** [Hva gjør AI-tjenesten?]
- **Brukere:** [Antall brukere/systemer som avhenger av tjenesten]
- **Driftstid:** [Forventet tilgjengelighet, f.eks. 24/7 eller kontortid]
### Påvirkningsvurdering
| Nedetid | Finansiell påvirkning | Omdømmepåvirkning | Regulatorisk risiko |
|---------|----------------------|--------------------|--------------------|
| 01 time | [Lav/Middels/Høy] | [Lav/Middels/Høy] | [Lav/Middels/Høy] |
| 14 timer | [...] | [...] | [...] |
| 424 timer | [...] | [...] | [...] |
| > 24 timer | [...] | [...] | [...] |
### Konklusjon
- **Kritikalitetstier:** [0/1/2/3]
- **RTO-krav:** [X minutter/timer]
- **RPO-krav:** [X minutter/timer]
```
## Datatap-toleranse og RPO-beregning
RPO for AI-systemer krever spesiell oppmerksomhet fordi data har forskjellig verdi og regenereringstid.
### RPO-kategorier for AI-data
| Datatype | Typisk RPO | Regenereringstid | Beskyttelsesmekanisme |
|----------|-----------|-------------------|-----------------------|
| Treningsdata (datasett) | 24 timer | Dager til uker | Azure Blob Storage GRS/GZRS |
| Finjusterte modeller | 24 timer | Timer til dager | Model registry backup |
| Search-indekser (embeddings) | 14 timer | Timer | Dual-region indexing |
| Brukerdata/konversasjoner | 015 min | Ikke regenererbar | Cosmos DB multi-region writes |
| Konfigurasjoner og prompts | 0 | Minutter via IaC | Git + IaC deployment |
| Fine-tuning jobb-tilstand | 424 timer | Timer | Checkpoint-basert backup |
### Beregningsmodell for RPO
RPO beregnes basert på tre faktorer:
1. **Data change rate**: Hvor ofte endres dataene?
2. **Replication lag**: Hva er forsinkelsen mellom primær og sekundær region?
3. **Backup frequency**: Hvor ofte tas backup?
```
Effektiv RPO = max(Replication Lag, Backup Interval)
```
For Azure Storage med Geo Priority Replication er RPO for blobs garantert <= 15 minutter (99.0% av faktureringsperioden).
### Azure-tjenester og deres innebygde RPO
| Azure-tjeneste | Innebygd RPO | Konfigurasjon | Merknad |
|----------------|-------------|---------------|---------|
| Azure OpenAI | Ingen innebygd DR | Manuell multi-region | Stateless — redeploy i ny region |
| Azure AI Search | Ingen innebygd repl. | Manuell multi-region | Rebuild indeks fra kilde |
| Azure Cosmos DB | ~0 (multi-region writes) | Konfigurerbar | Automatisk geo-replikering |
| Azure Blob Storage (GRS) | ~15 min | Aktivér GRS/GZRS | Async replikering |
| Azure Blob Storage (GPR) | <= 15 min SLA | Aktivér Geo Priority Repl. | SLA-backed RPO |
| Azure SQL Database | ~5 sek (geo-repl.) | Active geo-replication | Async replikering |
| Azure Machine Learning | Ingen innebygd DR | Manuell multi-region | Separat storage per region |
## Mapping av krav til Azure-kapabiliteter
### Recovery-konfigurasjoner
| Konfigurasjonstype | RTO | RPO | Kostnad | Egnet for |
|--------------------|-----|-----|---------|-----------|
| Active-Active | ~0 | ~0 | Høyest | Tier 0: Mission Critical |
| Active-Passive (Warm) | Minutter | Minutter | Middels-Høy | Tier 1: Business Critical |
| Active-Passive (Cold) | Timer | Timer | Middels | Tier 2: Business Operational |
| Backup & Restore | TimerDager | TimerDager | Lavest | Tier 3: Administrative |
### Azure OpenAI BCDR-konfigurasjon
```python
# Eksempel: Multi-region Azure OpenAI med failover via Azure API Management
import openai
from azure.identity import DefaultAzureCredential
# Primær region
primary_client = openai.AzureOpenAI(
azure_endpoint="https://aoai-primary-norwayeast.openai.azure.com/",
api_version="2024-10-21",
azure_deployment="gpt-4o"
)
# Sekundær region (warm standby)
secondary_client = openai.AzureOpenAI(
azure_endpoint="https://aoai-secondary-swedencentral.openai.azure.com/",
api_version="2024-10-21",
azure_deployment="gpt-4o"
)
def call_with_failover(messages, max_retries=3):
"""Call Azure OpenAI with automatic failover to secondary region."""
try:
response = primary_client.chat.completions.create(
model="gpt-4o",
messages=messages,
timeout=30
)
return response
except Exception as e:
print(f"Primary region failed: {e}")
# Failover to secondary
response = secondary_client.chat.completions.create(
model="gpt-4o",
messages=messages,
timeout=30
)
return response
```
### Azure AI Search multi-region oppsett
```bash
# Deploy identisk search-tjeneste i to regioner
az search service create \
--name "search-primary-norwayeast" \
--resource-group "rg-ai-prod" \
--location "norwayeast" \
--sku "standard" \
--replica-count 3 \
--partition-count 2
az search service create \
--name "search-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--location "swedencentral" \
--sku "standard" \
--replica-count 2 \
--partition-count 2
# Bruk Azure Traffic Manager for routing
az network traffic-manager profile create \
--name "tm-search-failover" \
--resource-group "rg-networking" \
--routing-method Priority \
--unique-dns-name "ai-search-global"
```
## Norske regulatoriske krav
### Forvaltningsloven og Utredningsinstruksen
Norske offentlige organisasjoner må dokumentere:
- **Konsekvensanalyse**: Vurdering av konsekvenser ved bortfall av AI-tjenester
- **Alternativanalyse**: Evaluering av ulike BCDR-strategier med kost/nytte
- **Risiko- og sårbarhetsanalyse (ROS)**: Identifisering av trusler mot AI-systemers tilgjengelighet
### NSMs grunnprinsipper
NSM (Nasjonal sikkerhetsmyndighet) krever:
- Klassifisering av systemer etter kritikalitet
- Dokumenterte gjenopprettingsplaner
- Regelmessig testing av beredskapsplaner
- Loggføring og rapportering av hendelser
### Data Residency-krav
| Krav | Beskrivelse | Påvirkning på BCDR |
|------|-------------|-------------------|
| Schrems II | Data kan ikke overføres til usikre tredjeland | Begrens DR-regioner til EU/EØS |
| GDPR Art. 32 | Tilstrekkelig sikkerhetsnivå inkl. tilgjengelighet | Dokumentér RTO/RPO i DPIA |
| Forvaltningsloven §13 | Taushetsplikt | Kryptering i alle DR-regioner |
## Dokumentasjons-maler og governance
### RTO/RPO-dokumentasjonsmal
```markdown
# RTO/RPO Dokumentasjon — [Systemnavn]
## Versjon og godkjenning
- **Versjon:** [X.Y]
- **Sist oppdatert:** [Dato]
- **Godkjent av:** [Navn og rolle]
- **Neste revisjon:** [Dato]
## Systembeskrivelse
[Kort beskrivelse av AI-systemet og dets forretningsfunksjon]
## Komponentoversikt med RTO/RPO
| Komponent | Kritikalitet | RTO | RPO | DR-strategi | Ansvarlig |
|-----------|-------------|-----|-----|-------------|-----------|
| Azure OpenAI Endpoint | Høy | 15 min | N/A | Multi-region | Platform team |
| AI Search Index | Høy | 1 time | 4 timer | Dual indexing | Data team |
| Cosmos DB (state) | Kritisk | 0 | 0 | Multi-region writes | Platform team |
| Blob Storage (docs) | Middels | 4 timer | 15 min | GRS | Ops team |
## Testplan
- **Frekvens:** Kvartalsvis
- **Type:** Failover drill + tabletop
- **Suksesskriterier:** [Definer]
## Hendelsesklassifisering
[Ref. til incident response plan]
```
### Governance-prosess
1. **Årlig BIA-revisjon**: Oppdater kritikalitetsvurderinger
2. **Kvartalsvis testing**: Verifiser at RTO/RPO-mål oppnås
3. **Hendelsesdrevet oppdatering**: Revider etter reelle hendelser
4. **Endringsbasert vurdering**: Nye AI-komponenter trigger ny BIA
## Referanser
- [Business continuity and disaster recovery overview](https://learn.microsoft.com/en-us/azure/reliability/concept-business-continuity-high-availability-disaster-recovery) — Grunnleggende BCDR-konsepter og definisjoner
- [Develop a disaster recovery plan for multi-region deployments](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery) — WAF-veiledning for DR-planlegging
- [Recommendations for defining reliability targets](https://learn.microsoft.com/en-us/azure/well-architected/reliability/metrics) — SLO, RTO og RPO-definisjoner
- [BCDR considerations with Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/business-continuity-disaster-recovery) — Azure OpenAI-spesifikk BCDR
- [Azure Storage redundancy](https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy) — GRS, GZRS og replikeringsalternativer
- [Azure Storage Geo Priority Replication](https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy-priority-replication) — SLA-backed RPO for blobs
- [Reliability in Azure AI Search](https://learn.microsoft.com/en-us/azure/reliability/reliability-ai-search) — Tilgjengelighet og DR for AI Search
## For Cosmo
- **Bruk denne referansen** når kunden trenger hjelp med å definere RTO og RPO for sine AI-systemer, eller når de planlegger BCDR-strategi.
- Start alltid med en Business Impact Analysis (BIA) før du foreslår tekniske løsninger — RTO/RPO er forretningsbeslutninger, ikke tekniske.
- Utfordre kunder som sier "alt er kritisk" — differensiert kritikalitet er nøkkelen til kostnadseffektiv BCDR.
- For norsk offentlig sektor: Påpek at DPIA (Data Protection Impact Assessment) bør inkludere tilgjengelighetsvurdering med RTO/RPO.
- Husk at Azure OpenAI er stateless — RTO handler om redeployment og DNS-oppdatering, ikke om datavederlag.

View file

@ -0,0 +1,419 @@
# Service Level Documentation and DR Runbooks
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Service Level Agreements (SLA), runbooks og operasjonelle prosedyrer er bindeleddet mellom BCDR-strategi og faktisk gjenopprettingsevne. Uten presis dokumentasjon av SLA-mål, detaljerte trinn-for-trinn runbooks og tydelig ansvarsfordeling, vil selv den best designede DR-arkitekturen feile under en reell hendelse.
For AI-systemer er dokumentasjon spesielt viktig fordi gjenopprettingsprosedyrer ofte involverer flere Azure-tjenester med ulike oppstartstider og avhengigheter. En RAG-løsning krever for eksempel at Cosmos DB er tilgjengelig før App Service, som igjen må vente på at AI Search-indeksen er synkronisert, før Azure OpenAI-kall kan brukes meningsfullt.
Azure Well-Architected Framework understreker at en DR-plan må inkludere tre essensielle komponenter: en klar runbook, en veldefinert kommunikasjonsplan, og en strukturert eskaleringsvei. For norsk offentlig sektor bør disse dokumentene følge organisasjonens ITIL-rammeverk og NSMs krav til beredskapsplanlegging.
## Service Level Agreement-maler
### SLA-dokument for AI-tjeneste
```markdown
# Service Level Agreement
## [AI-tjeneste navn]
### 1. Tjenestebeskrivelse
| Felt | Verdi |
|------|-------|
| Tjenestenavn | [Navn] |
| Tjenesteeier | [Avdeling/person] |
| Versjon | [X.Y] |
| Gyldig fra | [Dato] |
| Neste revisjon | [Dato] |
### 2. Tjenestenivåmål (SLO)
#### 2.1 Tilgjengelighet
| Mål | Verdi | Måleperiode | Ekskluderinger |
|-----|-------|-------------|----------------|
| Tilgjengelighet | 99.9% | Månedlig | Planlagt vedlikehold |
| Oppetid (beregnet) | ~43.8 min nedetid/mnd | — | — |
#### 2.2 Ytelse
| Mål | Verdi | Målepunkt |
|-----|-------|-----------|
| Chat response time (P95) | < 5 sekunder | End-to-end |
| Search query time (P95) | < 500 ms | API-nivå |
| Throughput | > 100 samtidige brukere | Applikasjonsnivå |
#### 2.3 Gjenoppretting
| Mål | Verdi | Merknad |
|-----|-------|---------|
| RTO | 15 minutter | Fra deteksjon til gjenopprettet |
| RPO | 5 minutter | Maks akseptabelt datatap |
| MTTR | < 30 minutter | Gjennomsnittlig gjenopprettingstid |
### 3. Ansvar og eskalering
| Rolle | Ansvarlig | Telefon | Epost |
|-------|-----------|---------|-------|
| Tjenesteeier | [Navn] | [Tlf] | [Epost] |
| Teknisk ansvarlig | [Navn] | [Tlf] | [Epost] |
| DR-koordinator | [Navn] | [Tlf] | [Epost] |
| Backup kontakt | [Navn] | [Tlf] | [Epost] |
### 4. Vedlikehold og unntak
- Planlagt vedlikehold: Tirsdager 02:0004:00 CET
- Varsling: Minimum 72 timer i forkant
- Nødvedlikehold: Varsling så snart som mulig
### 5. Rapportering
- Månedlig SLA-rapport til tjenesteeier
- Kvartalsvis trendrapport til ledelsen
- Umiddelbar hendelsesrapport ved SLA-brudd
```
## RTO og RPO dokumentasjonsstandarder
### Detaljert RTO/RPO-dokumentasjon
```markdown
# RTO/RPO Spesifikasjon — AI Platform
## Komponentoversikt med gjenopprettingsmål
| ID | Komponent | Kritikalitet | RTO | RPO | DR-strategi | Region |
|----|-----------|-------------|-----|-----|-------------|--------|
| C01 | Azure OpenAI | Høy | 5 min | N/A | Multi-region failover | NE→SC |
| C02 | Azure AI Search | Høy | 15 min | 30 min | Dual-indexing | NE→SC |
| C03 | Cosmos DB | Kritisk | ~0 | ~0 | Multi-region writes | NE+SC |
| C04 | App Service | Høy | 5 min | N/A | Multi-region + TM | NE→SC |
| C05 | Azure Key Vault | Kritisk | Auto | Auto | MS-managed failover | NE→SC |
| C06 | Blob Storage (docs) | Middels | 15 min | 15 min | GZRS | NE→SC |
| C07 | Redis Cache | Middels | 10 min | 5 min | Geo-replication | NE→SC |
| C08 | App Configuration | Lav | 5 min | ~0 | Geo-replication | NE→SC |
## Avhengighetsrekkefølge for gjenoppretting
```mermaid
graph LR
KV[Key Vault C05] --> DB[Cosmos DB C03]
KV --> Redis[Redis C07]
DB --> App[App Service C04]
Redis --> App
Config[App Config C08] --> App
Storage[Blob Storage C06] --> Search[AI Search C02]
Search --> App
App --> AOAI[Azure OpenAI C01]
```
## Gjenopprettingsrekkefølge
1. Key Vault (automatisk failover)
2. Cosmos DB (automatisk multi-region)
3. Redis Cache (geo-replication failover)
4. App Configuration (geo-replication failover)
5. Blob Storage (GRS failover if needed)
6. AI Search (start indexer i sekundær region)
7. App Service (deploy/scale i sekundær region)
8. Azure OpenAI (verifiser sekundært endpoint)
9. Traffic Manager (oppdater routing)
```
## Disaster Recovery Runbooks og Playbooks
### Master DR Runbook
```markdown
# DR Runbook — AI Platform
## Forutsetninger
- Tilgang til Azure Portal med Owner-rolle på rg-ai-dr
- Azure CLI installert og autentisert
- Tilgang til organisasjonens incident management system
- Kontaktliste for eskalering tilgjengelig
## Fase 1: Deteksjon og Vurdering (05 minutter)
### Steg 1.1: Verifiser hendelsen
- [ ] Sjekk Azure Service Health: https://status.azure.com
- [ ] Sjekk intern monitoring: [Dashboard URL]
- [ ] Verifiser med automatisk helsesjekk:
```bash
curl -s https://ai-app-prod.azurewebsites.net/health/deep | jq .
```
### Steg 1.2: Klassifiser hendelsen
| Scenario | Alvorlighetsgrad | Aksjon |
|----------|-----------------|--------|
| Enkelt komponent nede | P2 | Standard feilsøking |
| Regional degradering | P1 | Vurder partial failover |
| Full regional outage | P0 | Initier full DR |
### Steg 1.3: Deklarer hendelse
- [ ] Opprett incident i [ITSM-system]
- [ ] Varsle DR-koordinator
- [ ] Aktiver kommunikasjonsplan
---
## Fase 2: Failover-initiering (510 minutter)
### Steg 2.1: Verifiser DR-region readiness
```bash
# Sjekk at DR-ressurser er tilgjengelige
az resource list \
--resource-group "rg-ai-dr" \
--query "[].{Name:name, Type:type, Location:location}" \
--output table
# Sjekk Cosmos DB replikering
az cosmosdb show \
--name "cosmos-ai-state" \
--resource-group "rg-ai-prod" \
--query "readLocations[].{Region:locationName, State:failoverPriority}" \
--output table
```
### Steg 2.2: Scale up DR-ressurser
```bash
# Scale AI Search til produksjonsnivå
az search service update \
--name "search-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--replica-count 3
# Scale App Service
az appservice plan update \
--name "asp-ai-dr" \
--resource-group "rg-ai-dr" \
--sku P3v3
# Verifiser OpenAI-endpoint i DR-region
curl -s -H "api-key: $AOAI_DR_KEY" \
"https://aoai-secondary-swedencentral.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-10-21" \
-d '{"messages":[{"role":"user","content":"test"}]}' | jq .status
```
### Steg 2.3: Oppdater Traffic Manager
```bash
# Switch til sekundær region
az network traffic-manager endpoint update \
--resource-group "rg-networking" \
--profile-name "tm-ai-platform" \
--name "primary-norwayeast" \
--type azureEndpoints \
--endpoint-status Disabled
az network traffic-manager endpoint update \
--resource-group "rg-networking" \
--profile-name "tm-ai-platform" \
--name "secondary-swedencentral" \
--type azureEndpoints \
--endpoint-status Enabled
```
---
## Fase 3: Verifikasjon (1015 minutter)
### Steg 3.1: Funksjonell testing
- [ ] Test health endpoint: `curl https://ai-app-dr.azurewebsites.net/health/deep`
- [ ] Test chat-funksjonalitet manuelt
- [ ] Test search-funksjonalitet
- [ ] Verifiser brukerautentisering
### Steg 3.2: Data-integritet
- [ ] Sjekk Cosmos DB datakonsistens
- [ ] Verifiser AI Search indeksstatus
- [ ] Kontroller at siste data er tilgjengelig
### Steg 3.3: Ytelsesverifisering
- [ ] Kjør syntetisk lasttest (lav belastning)
- [ ] Verifiser at responstider er akseptable
- [ ] Sjekk at auto-scaling fungerer
---
## Fase 4: Stabilisering og Kommunikasjon
### Steg 4.1: Oppdater interessenter
- [ ] Send statusoppdatering til alle berørte
- [ ] Oppdater statusside
- [ ] Informer kundeservice
### Steg 4.2: Overvåking
- [ ] Sett opp forsterket overvåking i DR-region
- [ ] Konfigurer alerts med lavere terskler
- [ ] Start kontinuerlig helsesjekk
---
## Fase 5: Failback (når primær region er tilgjengelig)
### Steg 5.1: Verifiser primær region
- [ ] Bekreft at Azure Service Health viser "Resolved"
- [ ] Test primær region infrastruktur
- [ ] Verifiser data-synkronisering
### Steg 5.2: Planlegg failback
- [ ] Velg lavtrafikk-vindu for failback
- [ ] Kommuniser plan til interessenter
- [ ] Forbered failback-runbook
### Steg 5.3: Utfør failback
```bash
# Re-aktiver primær region
az network traffic-manager endpoint update \
--resource-group "rg-networking" \
--profile-name "tm-ai-platform" \
--name "primary-norwayeast" \
--type azureEndpoints \
--endpoint-status Enabled
# Gradvis shift trafikk tilbake (weighted routing)
# eller oppdater priority
```
### Steg 5.4: Nedskaler DR-region
```bash
# Etter verifisert failback, nedskaler DR
az search service update \
--name "search-secondary-swedencentral" \
--resource-group "rg-ai-dr" \
--replica-count 2
az appservice plan update \
--name "asp-ai-dr" \
--resource-group "rg-ai-dr" \
--sku P2v3
```
---
## Fase 6: Post-Incident
- [ ] Gjennomfør post-mortem innen 5 virkedager
- [ ] Oppdater runbooks basert på erfaringer
- [ ] Logg faktisk RTO/RPO vs. mål
- [ ] Oppdater BCDR-dokumentasjon
```
## Trinn-for-trinn gjenopprettingsprosedyrer
### Spesifikk prosedyre: Azure AI Search Index Rebuild
```markdown
# Prosedyre: Rebuild AI Search Index i DR-region
## Når brukes denne?
- AI Search primær region er utilgjengelig
- Search indeks i DR-region er utdatert (> RPO)
- Corrupted index detected
## Forutsetninger
- Kildedokumenter tilgjengelig i DR-region (Blob Storage GZRS)
- Search service i DR-region er kjørende
- Skillset og indexer-definisjoner lagret i IaC (Git)
## Prosedyre
### 1. Verifiser at indeksdefinisjoner er tilgjengelige
```bash
# Hent indeksdefinisjon fra IaC-repo
git clone https://github.com/org/ai-infrastructure.git
cd ai-infrastructure/search-indexes/
cat knowledge-base-index.json | jq .name
```
### 2. Opprett/oppdater indeks i DR-region
```bash
# Opprett indeks
curl -X PUT \
"https://search-secondary-swedencentral.search.windows.net/indexes/knowledge-base?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY" \
-H "Content-Type: application/json" \
-d @knowledge-base-index.json
# Opprett datasource
curl -X PUT \
"https://search-secondary-swedencentral.search.windows.net/datasources/blob-source?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY" \
-H "Content-Type: application/json" \
-d @blob-datasource-dr.json
# Opprett skillset (hvis AI enrichment brukes)
curl -X PUT \
"https://search-secondary-swedencentral.search.windows.net/skillsets/embedding-skillset?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY" \
-H "Content-Type: application/json" \
-d @embedding-skillset.json
```
### 3. Start full re-indeksering
```bash
# Opprett og kjør indexer
curl -X PUT \
"https://search-secondary-swedencentral.search.windows.net/indexers/blob-indexer?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY" \
-H "Content-Type: application/json" \
-d @blob-indexer.json
# Overvåk indexer-status
watch -n 10 'curl -s \
"https://search-secondary-swedencentral.search.windows.net/indexers/blob-indexer/status?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY" | jq ".lastResult.status, .lastResult.itemsProcessed"'
```
### 4. Verifiser indekskvalitet
```bash
# Sjekk dokumenttelling
curl -s "https://search-secondary-swedencentral.search.windows.net/indexes/knowledge-base/docs/\$count?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY"
# Test en søkespørring
curl -s "https://search-secondary-swedencentral.search.windows.net/indexes/knowledge-base/docs/search?api-version=2024-07-01" \
-H "api-key: $SEARCH_DR_KEY" \
-H "Content-Type: application/json" \
-d '{"search": "test query", "top": 5}' | jq '.value | length'
```
### 5. Forventet tidsbruk
| Indeksstørrelse | Estimert tid | Merknad |
|----------------|-------------|---------|
| < 10,000 docs | 1020 min | Inkl. embedding-generering |
| 10,000100,000 | 3060 min | Avhenger av skillset |
| > 100,000 | 14 timer | Vurder parallel indexing |
```
## Eierskap og eskaleringsmatrise
### RACI-matrise for DR
| Aktivitet | Platform Team | AI Team | Security | Management | Microsoft |
|-----------|:------------:|:-------:|:--------:|:----------:|:---------:|
| Deteksjon | R | I | I | I | C |
| Beslutning om failover | A | C | C | I | — |
| Teknisk failover | R | C | I | I | C |
| Kommunikasjon (intern) | I | I | I | R/A | — |
| Kommunikasjon (ekstern) | I | I | I | R/A | — |
| Verifisering | R | R | C | I | — |
| Failback-planlegging | R | C | C | A | C |
| Post-mortem | R | R | C | A | — |
*R = Responsible, A = Accountable, C = Consulted, I = Informed*
## Referanser
- [Document your DR plan](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#document-your-dr-plan) — WAF DR-dokumentasjon
- [DR communication plan](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#document-your-dr-plan) — Kommunikasjonsplan
- [Test regularly and improve the plan](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/disaster-recovery#test-regularly-and-improve-the-plan) — Testing av DR-plan
- [Create an effective incident management plan](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/incident-management) — Incident management
- [Recommendations for defining reliability targets](https://learn.microsoft.com/en-us/azure/well-architected/reliability/metrics) — SLO-definisjoner
- [Reliability in Azure AI Search](https://learn.microsoft.com/en-us/azure/reliability/reliability-ai-search) — AI Search DR
## For Cosmo
- **Bruk denne referansen** når kunden trenger maler for SLA-dokumentasjon, DR-runbooks eller eskaleringsprosedyrer for AI-systemer.
- DR-runbooks MÅ være executable — hvert steg skal ha konkrete kommandoer, ikke bare beskrivelser.
- Versjonér runbooks i Git som kode — de endres like ofte som infrastrukturen.
- Gjenopprettingsrekkefølge er kritisk — dokumentér avhengigheter eksplisitt og test at rekkefølgen fungerer.
- For norsk offentlig sektor: RACI-matrise bør inkludere personvernombud (DPO) for hendelser som involverer persondata.

View file

@ -0,0 +1,403 @@
# State Management and Consistency During Failover
**Last updated:** 2026-02
**Status:** GA
**Category:** Business Continuity & Disaster Recovery
---
## Introduksjon
Håndtering av applikasjonstilstand (state) under failover-scenarioer er en av de mest utfordrende aspektene ved BCDR for AI-systemer. AI-applikasjoner har typisk flere typer state som må ivaretas: brukersesjoner, konversasjonshistorikk, mellomresultater fra langvarige operasjoner (fine-tuning, batch-indeksering), og applikasjonskonfigurasjon.
Under en failover kan in-flight requests gå tapt, sesjonsstilstand kan bli inkonsistent mellom regioner, og operasjoner som var halvveis fullført kan etterlate systemet i en ukjent tilstand. For å håndtere dette kreves distribuerte state management-mønstre, idempotente operasjoner, og robust request-retry logikk.
For norsk offentlig sektor er tap av state spesielt problematisk når AI-systemet støtter saksbehandling eller vedtaksfatting. Forvaltningsloven krever sporbarhet og etterrettelighet, noe som betyr at konversasjonshistorikk og AI-anbefalinger må bevares konsistent gjennom failover.
## Distribuerte state management-mønstre
### State-kategorier for AI-systemer
| State-type | Eksempel | Varighet | Kritikalitet | Lagring |
|-----------|---------|----------|-------------|---------|
| Session state | Autentiseringstoken, brukerpreferanser | Timer | Middels | Redis Cache / Cosmos DB |
| Conversation state | Chat-historikk, kontekstvindu | Dager | Høy | Cosmos DB |
| Operation state | Fine-tuning progress, batch-status | TimerDager | Middels | Queue + Cosmos DB |
| Configuration state | Model deployments, system prompts | Permanent | Kritisk | App Configuration / Git |
| Cache state | Søkeresultater, embeddings | MinutterTimer | Lav | Redis Cache |
### Distribuert state med Azure Cosmos DB
```python
# Distribuert state management for AI chatbot
from azure.cosmos.aio import CosmosClient
from azure.identity.aio import DefaultAzureCredential
import json
from datetime import datetime, timedelta
class DistributedStateManager:
"""Manage AI application state across regions with Cosmos DB."""
def __init__(self, connection_string, database_name="ai-state"):
self.client = CosmosClient.from_connection_string(connection_string)
self.database = self.client.get_database_client(database_name)
self.sessions = self.database.get_container_client("sessions")
self.conversations = self.database.get_container_client("conversations")
async def save_session(self, session_id: str, user_id: str, data: dict):
"""Save session state with TTL and version tracking."""
document = {
"id": session_id,
"userId": user_id,
"data": data,
"version": data.get("version", 0) + 1,
"lastUpdated": datetime.utcnow().isoformat(),
"ttl": 3600 * 24, # 24 timer TTL
"region": self._get_current_region()
}
await self.sessions.upsert_item(document)
return document["version"]
async def get_session(self, session_id: str, user_id: str):
"""Get session with partition key optimization."""
try:
response = await self.sessions.read_item(
item=session_id,
partition_key=user_id
)
return response
except Exception:
return None # Session not found
async def save_conversation_turn(
self, conversation_id: str, user_id: str, turn: dict
):
"""Append a conversation turn atomically."""
# Bruk conditional update for å unngå konflikter
conversation = await self._get_or_create_conversation(
conversation_id, user_id
)
# Legg til turn med unik ID for idempotens
turn["turnId"] = f"{conversation_id}-{len(conversation['turns'])}"
turn["timestamp"] = datetime.utcnow().isoformat()
conversation["turns"].append(turn)
conversation["lastUpdated"] = datetime.utcnow().isoformat()
# Conditional update med ETag for optimistisk locking
await self.conversations.replace_item(
item=conversation_id,
body=conversation,
match_condition=conversation.get("_etag")
)
def _get_current_region(self):
import os
return os.environ.get("AZURE_REGION", "unknown")
```
### Redis Cache for Session State
```bash
# Azure Cache for Redis med geo-replikering
# Primær region
az redis create \
--name "redis-ai-norwayeast" \
--resource-group "rg-ai-prod" \
--location "norwayeast" \
--sku "Premium" \
--vm-size "P1" \
--enable-non-ssl-port false \
--minimum-tls-version "1.2"
# Sekundær region (geo-replica)
az redis create \
--name "redis-ai-swedencentral" \
--resource-group "rg-ai-dr" \
--location "swedencentral" \
--sku "Premium" \
--vm-size "P1" \
--enable-non-ssl-port false
# Opprett geo-replikering
az redis server-link create \
--name "redis-ai-norwayeast" \
--resource-group "rg-ai-prod" \
--server-to-link "/subscriptions/{sub}/resourceGroups/rg-ai-dr/providers/Microsoft.Cache/Redis/redis-ai-swedencentral" \
--replication-role Secondary
```
## Sesjonsstilstandsreplikering og synkronisering
### Session Affinity vs. Shared State
| Tilnærming | Fordel | Ulempe | Anbefalt for |
|-----------|--------|--------|-------------|
| Session affinity (sticky) | Enkel, ingen replikering | Session tapt ved node-feil | Dev/test |
| Shared state (Redis) | Rask failover | Replikeringsforsinkelse | Produksjon |
| Shared state (Cosmos DB) | Global replikering | Høyere latens enn Redis | Multi-region |
| Stateless (JWT) | Ingen server-state | Begrenset datamengde | API-first design |
### Session migration under failover
```csharp
// C# Session migration strategy
public class ResilientSessionStore : ISessionStore
{
private readonly IDistributedCache _primaryCache;
private readonly IDistributedCache _secondaryCache;
private readonly CosmosClient _cosmosClient;
private bool _usingPrimary = true;
public async Task<SessionData?> GetSessionAsync(string sessionId)
{
var cache = _usingPrimary ? _primaryCache : _secondaryCache;
try
{
var data = await cache.GetStringAsync(sessionId);
if (data != null)
return JsonSerializer.Deserialize<SessionData>(data);
}
catch (RedisConnectionException)
{
// Redis failover
_usingPrimary = !_usingPrimary;
cache = _usingPrimary ? _primaryCache : _secondaryCache;
try
{
var data = await cache.GetStringAsync(sessionId);
if (data != null)
return JsonSerializer.Deserialize<SessionData>(data);
}
catch
{
// Begge Redis nede — fall tilbake til Cosmos DB
}
}
// Fallback: hent fra Cosmos DB (persistent store)
return await GetFromCosmosAsync(sessionId);
}
public async Task SaveSessionAsync(string sessionId, SessionData data)
{
// Skriv til Redis OG Cosmos DB (write-through)
var json = JsonSerializer.Serialize(data);
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24)
};
// Redis (rask, men kan feile)
try
{
var cache = _usingPrimary ? _primaryCache : _secondaryCache;
await cache.SetStringAsync(sessionId, json, options);
}
catch { /* Redis-feil er ikke kritisk */ }
// Cosmos DB (persistent, geo-replikert)
await SaveToCosmosAsync(sessionId, data);
}
}
```
## Håndtering av in-flight requests under failover
### Request draining
```python
# Graceful request draining under failover
import asyncio
from contextlib import asynccontextmanager
class GracefulFailoverManager:
"""Manage in-flight requests during failover."""
def __init__(self, drain_timeout_seconds=30):
self.drain_timeout = drain_timeout_seconds
self.active_requests = 0
self.accepting_requests = True
self._lock = asyncio.Lock()
@asynccontextmanager
async def track_request(self):
"""Context manager to track active requests."""
async with self._lock:
if not self.accepting_requests:
raise ServiceUnavailableError(
"Service is draining for failover. "
"Please retry against the new endpoint."
)
self.active_requests += 1
try:
yield
finally:
async with self._lock:
self.active_requests -= 1
async def initiate_drain(self):
"""Stop accepting new requests and wait for in-flight to complete."""
async with self._lock:
self.accepting_requests = False
# Vent på at aktive requests fullføres
start = asyncio.get_event_loop().time()
while self.active_requests > 0:
elapsed = asyncio.get_event_loop().time() - start
if elapsed > self.drain_timeout:
print(f"Drain timeout! {self.active_requests} requests still active")
break
await asyncio.sleep(0.5)
return self.active_requests == 0
# Bruk i applikasjon
failover_mgr = GracefulFailoverManager(drain_timeout_seconds=30)
async def handle_chat_request(request):
async with failover_mgr.track_request():
response = await process_ai_request(request)
return response
```
## Idempotens og request retry-strategier
### Idempotent design for AI-operasjoner
```python
# Idempotent AI operations with deduplication
import hashlib
import json
class IdempotentAIService:
"""Ensure AI operations are idempotent using request IDs."""
def __init__(self, state_store, cache_ttl_seconds=3600):
self.state_store = state_store
self.cache_ttl = cache_ttl_seconds
def generate_idempotency_key(self, operation: str, params: dict) -> str:
"""Generate deterministic key for deduplication."""
canonical = json.dumps(params, sort_keys=True)
return hashlib.sha256(f"{operation}:{canonical}".encode()).hexdigest()
async def execute_idempotent(
self, operation: str, params: dict, execute_fn
):
"""Execute operation with idempotency guarantee."""
key = self.generate_idempotency_key(operation, params)
# Sjekk om operasjonen allerede er utført
existing = await self.state_store.get(f"idempotent:{key}")
if existing:
return json.loads(existing) # Returner cached resultat
# Utfør operasjonen
result = await execute_fn(params)
# Lagre resultat for deduplisering
await self.state_store.set(
f"idempotent:{key}",
json.dumps(result),
ttl=self.cache_ttl
)
return result
# Eksempel: Idempotent embedding-generering
service = IdempotentAIService(redis_store)
async def generate_embedding(text):
return await service.execute_idempotent(
operation="embed",
params={"text": text, "model": "text-embedding-3-large"},
execute_fn=lambda p: openai_client.embeddings.create(
input=p["text"], model=p["model"]
)
)
```
### Retry-strategi med idempotens
| Operasjonstype | Idempotent? | Retry-strategi | Max retries |
|---------------|-------------|---------------|-------------|
| Chat completion | Ja (med seed) | Exponential backoff | 3 |
| Embedding generation | Ja (deterministisk) | Fast retry | 3 |
| Search query | Ja (read-only) | Fast retry | 5 |
| Index update | Ja (upsert) | Exponential backoff | 3 |
| Fine-tuning start | Nei | Ingen retry | 0 |
| Conversation save | Conditional (ETag) | Exponential backoff | 3 |
## State validering og verifikasjonsprosedyrer
### Post-failover validering
```python
# Post-failover state validation checklist
async def validate_state_after_failover(primary_region, dr_region):
"""Validate state consistency after failover."""
results = {}
# 1. Verifiser session state
sample_sessions = await get_recent_sessions(limit=100)
session_ok = 0
for session in sample_sessions:
dr_session = await dr_state_store.get_session(session["id"])
if dr_session and dr_session["version"] >= session["version"] - 1:
session_ok += 1
results["sessions"] = {
"total": len(sample_sessions),
"consistent": session_ok,
"pct": round(session_ok / max(len(sample_sessions), 1) * 100, 1)
}
# 2. Verifiser conversation state
sample_convs = await get_recent_conversations(limit=50)
conv_ok = 0
for conv in sample_convs:
dr_conv = await dr_state_store.get_conversation(conv["id"])
if dr_conv and len(dr_conv["turns"]) >= len(conv["turns"]) - 1:
conv_ok += 1
results["conversations"] = {
"total": len(sample_convs),
"consistent": conv_ok,
"pct": round(conv_ok / max(len(sample_convs), 1) * 100, 1)
}
# 3. Verifiser configuration state
primary_config = await get_app_configuration(primary_region)
dr_config = await get_app_configuration(dr_region)
config_match = primary_config == dr_config
results["configuration"] = {"consistent": config_match}
# 4. Samlet vurdering
all_ok = (
results["sessions"]["pct"] > 95 and
results["conversations"]["pct"] > 95 and
results["configuration"]["consistent"]
)
results["overall"] = "PASS" if all_ok else "FAIL"
return results
```
## Referanser
- [Recommendations for handling transient faults](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/handle-transient-faults) — Retry og idempotens
- [Retry pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/retry) — Retry-mønster
- [Designing Azure Functions for identical input](https://learn.microsoft.com/en-us/azure/azure-functions/functions-idempotent) — Idempotent design
- [Compensating Transaction pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction) — Kompenserende transaksjoner
- [Azure Cosmos DB consistency levels](https://learn.microsoft.com/en-us/azure/cosmos-db/consistency-levels) — Konsistensmodeller
- [Azure Cache for Redis geo-replication](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-geo-replication) — Redis geo-replikering
## For Cosmo
- **Bruk denne referansen** når kunden trenger hjelp med state management under failover for AI-applikasjoner.
- Anbefal alltid write-through til Cosmos DB selv om Redis brukes som primær session store — Redis-data kan gå tapt ved failover.
- Idempotens er OBLIGATORISK for alle AI-operasjoner som kan retries — bruk request IDs og conditional updates.
- For konversasjonshistorikk: Bruk append-only mønster med unik turnId for å unngå duplikater ved retry.
- Graceful request draining bør implementeres i alle produksjonsapplikasjoner — brå terminering av in-flight requests gir dårlig brukeropplevelse.