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>
17 KiB
Load Balancing Across Azure OpenAI Instances
Last updated: 2026-02 Status: GA Category: API Management & AI Gateway
Introduksjon
Lastbalansering på tvers av flere Azure OpenAI-instanser er en kritisk kapabilitet for enterprise AI-arkitekturer. Azure OpenAI har begrensninger på tokens per minutt (TPM) og requests per minutt (RPM) per deployment, og én enkelt instans vil sjelden dekke behovene til en hel organisasjon. Ved å distribuere trafikk over flere instanser -- gjerne i ulike regioner -- kan organisasjoner øke total kapasitet, forbedre tilgjengelighet og optimalisere kostnader.
Azure API Management (APIM) tilbyr innebygd backend pool-funksjonalitet som gjør dette uten egenutviklet kode. Backend pools støtter round-robin, weighted, priority-basert og session-aware lastbalansering, kombinert med circuit breaker for automatisk failover. For norsk offentlig sektor er dette spesielt relevant: flere etater kan dele infrastruktur, mens Provisioned Throughput Units (PTU) prioriteres for å maksimere investert kapasitet.
Det er viktig å forstå at APIM-lastbalansering er approksimasjon: ulike gateway-instanser synkroniserer ikke state seg imellom. Dette betyr at vektede fordelinger er omtrentlige, ikke eksakte. For de fleste AI-brukstilfeller er dette akseptabelt, da Azure OpenAI selv håndterer throttling med 429-responser og Retry-After headers.
Backend Pool-konsepter
Hva er en backend pool?
En backend pool i APIM er en samling av backend-tjenester som gatewayen behandler som én logisk enhet for lastbalansering. For Azure OpenAI betyr dette at flere OpenAI-instanser (potensielt i ulike regioner, med ulike deployment-typer) grupperes bak ett endepunkt.
| Egenskap | Verdi |
|---|---|
| Maks backends per pool | 30 |
| Synkronisering mellom gateway-instanser | Nei (approksimasjon) |
| Session awareness | Ja (cookie-basert) |
| Health checking | Via circuit breaker |
| Deployment-modell | Bicep, ARM, REST API, Portal |
Backend-registrering
Hver backend i poolen registreres med URL, autentisering og valgfrie metadata:
<!-- Policy: Rut til backend pool -->
<set-backend-service backend-id="openai-pool" />
Load Balancing-strategier
Strategi 1: Round-Robin
Fordeler requests jevnt mellom alle backends i poolen.
Request 1 → Backend A (Norway East)
Request 2 → Backend B (Sweden Central)
Request 3 → Backend C (West Europe)
Request 4 → Backend A (Norway East) ← syklusen gjentas
Bruk når:
- Alle instanser har lik kapasitet (samme TPM-allokering)
- Ingen preferanse for spesifikke regioner
- Enkel konfigurasjon er prioritert
Bicep:
resource backendPool 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-pool'
properties: {
type: 'Pool'
pool: {
services: [
{
id: '/backends/openai-norwayeast'
}
{
id: '/backends/openai-swedencentral'
}
{
id: '/backends/openai-westeurope'
}
]
}
}
}
Strategi 2: Weighted (vektet)
Fordeler requests basert på tildelte vekter. Nyttig når backends har ulik kapasitet.
Vekter: A=3, B=2, C=1 (totalt 6)
→ A mottar ~50% av trafikk
→ B mottar ~33% av trafikk
→ C mottar ~17% av trafikk
Bruk når:
- Backends har ulik TPM-allokering
- Blue-green deployment med gradvis trafikkskift
- Ulike pricing-modeller (PTU vs. pay-as-you-go)
Bicep:
resource backendPool 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-pool-weighted'
properties: {
type: 'Pool'
pool: {
services: [
{
id: '/backends/openai-norwayeast-ptu'
weight: 5
priority: 1
}
{
id: '/backends/openai-swedencentral-paygo'
weight: 3
priority: 1
}
{
id: '/backends/openai-westeurope-paygo'
weight: 2
priority: 1
}
]
}
}
}
Strategi 3: Priority-Based (anbefalt for AI)
Organiserer backends i prioritetsgrupper. Lavere prioritetsnummer = høyere prioritet. Backends i lavere prioritetsgrupper brukes kun når alle backends i høyere grupper er utilgjengelige (circuit breaker utløst).
Priority 1: PTU-instanser (fast pris, utnytt først)
├── openai-norwayeast-ptu (weight: 3)
└── openai-swedencentral-ptu (weight: 2)
Priority 2: Pay-as-you-go fallback
├── openai-westeurope-paygo (weight: 1)
└── openai-eastus-paygo (weight: 1)
Typisk scenario for norsk offentlig sektor:
| Prioritet | Deployment-type | Region | Begrunnelse |
|---|---|---|---|
| 1 | PTU | Norway East | Datasuverenitet + fast pris, bruk først |
| 1 | PTU | Sweden Central | Nær-region redundans |
| 2 | Pay-as-you-go | West Europe | Spillover ved høy last |
| 3 | Pay-as-you-go | East US | Nødfallback ved regional utfall |
Bicep:
resource backendPool 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-pool-priority'
properties: {
type: 'Pool'
pool: {
services: [
{
id: '/backends/openai-norwayeast-ptu'
weight: 3
priority: 1
}
{
id: '/backends/openai-swedencentral-ptu'
weight: 2
priority: 1
}
{
id: '/backends/openai-westeurope-paygo'
weight: 1
priority: 2
}
{
id: '/backends/openai-eastus-paygo'
weight: 1
priority: 3
}
]
}
}
}
Strategi 4: Session-Aware
Sikrer at alle requests fra samme bruker-sesjon rutes til samme backend. Kritisk for Azure OpenAI Assistants API der thread state er bundet til en spesifikk instans.
Sesjon 1: Bruker A ──cookie──► Backend A (alle requests i sesjonen)
Sesjon 2: Bruker B ──cookie──► Backend B (alle requests i sesjonen)
Sesjon 3: Bruker C ──cookie──► Backend A (ny sesjon, tilfeldig valgt)
Bruk når:
- Assistants API (thread state)
- Chat-applikasjoner med stateful backends
- Når backend cacher bruker-kontekst
Bicep:
resource backendPool 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-pool-session'
properties: {
type: 'Pool'
pool: {
services: [
{
id: '/backends/openai-norwayeast'
weight: 1
priority: 1
}
{
id: '/backends/openai-swedencentral'
weight: 1
priority: 1
}
]
sessionAffinity: {
type: 'Cookie'
cookieName: 'apim-session-id'
}
}
}
}
Cookie-håndtering for klienter:
Klienter MÅ lagre Set-Cookie-headeren fra APIM og sende den tilbake i påfølgende requests for å opprettholde sesjonsaffinitet.
Individual Backend-konfigurasjon
Registrere en Azure OpenAI backend
resource openaiBackend 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-norwayeast-ptu'
properties: {
url: 'https://aoai-norwayeast.openai.azure.com/openai'
protocol: 'http'
description: 'Azure OpenAI PTU deployment i Norway East'
circuitBreaker: {
rules: [
{
name: 'openai-circuit-breaker'
failureCondition: {
count: 3
interval: 'PT1M'
statusCodeRanges: [
{ min: 429, max: 429 }
{ min: 500, max: 599 }
]
}
tripDuration: 'PT10S'
acceptRetryAfter: true
}
]
}
}
}
Autentisering via Managed Identity
<policies>
<inbound>
<set-backend-service backend-id="openai-pool-priority" />
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</inbound>
</policies>
RBAC-konfigurasjon:
// Grant Cognitive Services User role to APIM managed identity
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: openaiResource
name: guid(apim.id, openaiResource.id, 'cognitive-services-user')
properties: {
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
'a97b65f3-24c7-4388-baec-2e87135dc908' // Cognitive Services User
)
principalId: apim.identity.principalId
principalType: 'ServicePrincipal'
}
}
Deployment Slot Selection
Routing til ulike modell-deployments
Når backends har ulike deployment-navn (f.eks. gpt-4o i en region, gpt4-turbo i en annen), kan APIM-policies transformere URL-en:
<policies>
<inbound>
<set-backend-service backend-id="openai-pool-priority" />
<!-- Override deployment name basert på backend-region -->
<choose>
<when condition="@(context.Backend?.AzureRegion == "norwayeast")">
<rewrite-uri template="/deployments/gpt-4o/chat/completions" />
</when>
<when condition="@(context.Backend?.AzureRegion == "swedencentral")">
<rewrite-uri template="/deployments/gpt4-turbo/chat/completions" />
</when>
</choose>
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</inbound>
</policies>
Modell-versjonshåndtering
<!-- Sett api-version basert på backend -->
<set-query-parameter name="api-version" exists-action="override">
<value>2024-10-21</value>
</set-query-parameter>
Regional Distribution
Topologi 1: Single-Region APIM, Multi-Region Backends
APIM (Norway East)
│
┌────────┼────────┐
▼ ▼ ▼
OpenAI OpenAI OpenAI
(Norway East) (Sweden C.) (West EU)
Priority 1 Priority 1 Priority 2
Fordeler: Enkel arkitektur, ett kontrollpunkt Ulemper: APIM er single point of failure, cross-region latens
Topologi 2: Multi-Region APIM, Regional Backends
Client → DNS (latency-based routing)
│
┌────────┴────────┐
▼ ▼
APIM Gateway APIM Gateway
(Norway East) (Sweden Central)
│ │
▼ ▼
OpenAI OpenAI
(Norway East) (Sweden Central)
Fordeler: Ingen regional single point of failure, lav latens Ulemper: Krever APIM Premium, dyrere
Bicep for multi-region APIM:
resource apim 'Microsoft.ApiManagement/service@2023-09-01-preview' = {
name: 'apim-ai-gateway'
location: 'norwayeast'
sku: {
name: 'Premium'
capacity: 1
}
properties: {
additionalLocations: [
{
location: 'swedencentral'
sku: {
name: 'Premium'
capacity: 1
}
}
]
}
}
Topologi 3: Active-Active med Active-Passive Backends
Kombinerer regional redundans med kostnadsoptimalisering:
APIM Gateway (Norway East)
├── Active: OpenAI PTU (Norway East) Priority 1
├── Passive: OpenAI PAYGO (Norway East) Priority 2
└── Cross: OpenAI PAYGO (Sweden C.) Priority 3 (kun ved regional feil)
APIM Gateway (Sweden Central)
├── Active: OpenAI PTU (Sweden C.) Priority 1
├── Passive: OpenAI PAYGO (Sweden C.) Priority 2
└── Cross: OpenAI PAYGO (Norway East) Priority 3
Regional policy routing:
<choose>
<when condition="@(context.Deployment.Region == "Norway East")">
<set-backend-service backend-id="pool-norwayeast" />
</when>
<when condition="@(context.Deployment.Region == "Sweden Central")">
<set-backend-service backend-id="pool-swedencentral" />
</when>
</choose>
Throttling og Retry-håndtering
Smart Load Balancing
Når en backend returnerer 429 (Too Many Requests), skal gatewayen:
- Lese
Retry-After-headeren - Markere backend som utilgjengelig via circuit breaker
- Umiddelbart retry til neste tilgjengelige backend i poolen
- IKKE vente (ingen delay mellom retries til ulike backends)
<policies>
<inbound>
<set-backend-service backend-id="openai-pool-priority" />
</inbound>
<backend>
<retry condition="@(context.Response.StatusCode == 429)"
count="3"
interval="0"
first-fast-retry="true">
<set-backend-service backend-id="openai-pool-priority" />
</retry>
</backend>
</policies>
PTU + PAYGO Spillover-mønster
Det mest vanlige mønsteret for kostnadsoptimalisering:
Normal trafikk:
All trafikk → PTU (Priority 1, fast pris)
Ved throttling (PTU kapasitet brukt opp):
Circuit breaker utløst på PTU
Trafikk → PAYGO (Priority 2, pay-per-token)
Etter PTU recovery:
Circuit breaker reset
Trafikk → PTU (Priority 1, tilbake til fast pris)
| Fase | Backend | Kostnad | Latens |
|---|---|---|---|
| Normal | PTU | Fast (forutsigbar) | Lav (garantert) |
| Spillover | PAYGO | Variabel (høyere) | Variabel |
| Recovery | PTU | Fast | Lav |
Komplett Bicep-eksempel
@description('Komplett AI Gateway med priority-based load balancing')
param location string = 'norwayeast'
param environment string = 'prod'
// Azure OpenAI instances
resource aoaiNorway 'Microsoft.CognitiveServices/accounts@2024-10-01' existing = {
name: 'aoai-norwayeast-${environment}'
}
resource aoaiSweden 'Microsoft.CognitiveServices/accounts@2024-10-01' existing = {
name: 'aoai-swedencentral-${environment}'
}
// APIM Instance
resource apim 'Microsoft.ApiManagement/service@2023-09-01-preview' = {
name: 'apim-ai-gw-${environment}'
location: location
sku: {
name: 'StandardV2'
capacity: 1
}
identity: {
type: 'SystemAssigned'
}
properties: {
publisherEmail: 'ai-team@example.no'
publisherName: 'AI Gateway'
}
}
// Backend: Norway East PTU
resource backendNorwayPTU 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-norwayeast-ptu'
properties: {
url: '${aoaiNorway.properties.endpoint}openai'
protocol: 'http'
circuitBreaker: {
rules: [
{
name: 'throttle-protection'
failureCondition: {
count: 3
interval: 'PT1M'
statusCodeRanges: [
{ min: 429, max: 429 }
{ min: 500, max: 599 }
]
}
tripDuration: 'PT10S'
acceptRetryAfter: true
}
]
}
}
}
// Backend: Sweden Central PAYGO
resource backendSwedenPAYGO 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-swedencentral-paygo'
properties: {
url: '${aoaiSweden.properties.endpoint}openai'
protocol: 'http'
circuitBreaker: {
rules: [
{
name: 'throttle-protection'
failureCondition: {
count: 3
interval: 'PT1M'
statusCodeRanges: [
{ min: 429, max: 429 }
{ min: 500, max: 599 }
]
}
tripDuration: 'PT10S'
acceptRetryAfter: true
}
]
}
}
}
// Backend Pool with priority-based routing
resource backendPool 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-pool'
properties: {
type: 'Pool'
pool: {
services: [
{
id: '/backends/${backendNorwayPTU.name}'
weight: 3
priority: 1
}
{
id: '/backends/${backendSwedenPAYGO.name}'
weight: 1
priority: 2
}
]
}
}
}
Overvåking og feilsøking
Identifisere hvilken backend som serverte request
<outbound>
<set-header name="X-Backend-Id" exists-action="override">
<value>@(context.Backend?.Id ?? "unknown")</value>
</set-header>
<set-header name="X-Backend-Type" exists-action="override">
<value>@(context.Backend?.Type ?? "unknown")</value>
</set-header>
</outbound>
KQL for load balancing-distribusjon
ApiManagementGatewayLogs
| where OperationId == "ChatCompletions_Create"
| extend backendUrl = tostring(BackendUrl)
| summarize RequestCount = count() by backendUrl, bin(TimeGenerated, 1h)
| render columnchart
For Cosmo
- Priority-based load balancing med PTU som Priority 1 og PAYGO som Priority 2 er det anbefalte mønsteret for enterprise AI-arkitekturer -- det maksimerer utnyttelsen av forhåndskjøpt kapasitet og faller automatisk tilbake til pay-per-use ved behov.
- Backend pools er approksimerte: ulike gateway-instanser synkroniserer ikke, så vektede fordelinger er omtrentlige. For AI-workloads er dette akseptabelt fordi Azure OpenAI selv håndterer throttling med 429/Retry-After.
- Session awareness er kritisk for Assistants API og chat-applikasjoner med stateful backends -- aktiver dette med cookie-basert sesjonsaffinitet i pool-konfigurasjonen.
- For norsk offentlig sektor med datasuverenitetskrav: prioriter Norway East og Sweden Central, bruk private endpoints, og vurder om cross-region failover til EU-regioner er akseptabelt under gjeldende regelverk.
- Kombiner alltid backend pools med circuit breaker (inkludert
acceptRetryAfter: true) for intelligent failover ved 429-responser fra Azure OpenAI.