# 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() .Or() .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() .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(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.