# Backend Pool Management & Health Probes

**Last updated:** 2026-02
**Status:** GA
**Category:** API Management & AI Gateway

---

## Introduksjon

Backend pool management i Azure API Management er fundamentalt for å bygge robuste AI-gateways. Når organisasjoner skalerer sin bruk av Azure OpenAI og andre LLM-tjenester, trenger de en mekanisme for å distribuere trafikk på tvers av flere backend-instanser, håndtere throttling gracefully, og sikre at feilende backends ikke påvirker sluttbrukere. APIM backend pools gir nettopp denne kapabiliteten med støtte for round-robin, vektet, prioritetsbasert og session-aware load balancing.

For norsk offentlig sektor, der AI-tjenester ofte skal være tilgjengelige for mange etater og brukere, er riktig backend pool-konfigurasjon avgjørende. Et typisk mønster er å ha Provisioned Throughput Units (PTU) som prioritert backend med pay-as-you-go Standard-deployments som fallback. Combined med circuit breaker-regler sikrer dette at tjenesten forblir tilgjengelig selv under høy belastning eller partielle feil.

Denne referansen dekker konfigurasjon av backend-entiteter, opprettelse av load-balanserte pools, circuit breaker-regler, helsesjekker, og timeout/retry-logikk — alt spesifikt for AI-workloads med Azure OpenAI som backend.

---

## Backend Configuration

### Opprette Backend-entiteter

Hver Azure OpenAI-instans representeres som en backend-entitet i APIM:

```bicep
resource aoaiBackendWestEurope 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  name: 'ai-gateway-apim/aoai-westeurope'
  properties: {
    url: 'https://aoai-westeurope.openai.azure.com'
    protocol: 'http'
    title: 'Azure OpenAI - West Europe'
    description: 'PTU deployment i West Europe'
    credentials: {
      authorization: {
        scheme: 'managed-identity'
        parameter: 'https://cognitiveservices.azure.com'
      }
    }
    tls: {
      validateCertificateChain: true
      validateCertificateName: true
    }
  }
}

resource aoaiBackendNorthEurope 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  name: 'ai-gateway-apim/aoai-northeurope'
  properties: {
    url: 'https://aoai-northeurope.openai.azure.com'
    protocol: 'http'
    title: 'Azure OpenAI - North Europe'
    description: 'Standard deployment i North Europe (fallback)'
    credentials: {
      authorization: {
        scheme: 'managed-identity'
        parameter: 'https://cognitiveservices.azure.com'
      }
    }
  }
}
```

### Backend Properties

| Egenskap | Beskrivelse | Relevans for AI |
|----------|-------------|----------------|
| `url` | Base URL for backend-tjenesten | Azure OpenAI endpoint |
| `protocol` | `http` for REST-backends | Alltid `http` for OpenAI |
| `credentials` | Autentiseringsmetode | Managed identity anbefalt |
| `circuitBreaker` | Circuit breaker-regler | Håndterer 429 throttling |
| `tls` | TLS-valideringinnstillinger | Sertifikatkjedevalidering |

### Referere til Backend i Policyer

```xml
<inbound>
    <base />
    <!-- Direkte backend-referanse -->
    <set-backend-service backend-id="aoai-westeurope" />
</inbound>
```

### Automatisk Backend-deteksjon

APIM kan automatisk matche requests til backend-entiteter basert på URL. Når en request sendes til en backend-URL som matcher en registrert backend-entitet, brukes denne automatisk — inkludert circuit breaker-regler og credentials.

---

## Load-Balanced Backend Pools

### Pool-typer for AI-workloads

| Load Balancing | Beskrivelse | AI-bruksscenario |
|---------------|-------------|-----------------|
| Round-robin | Jevn distribusjon | Likeverdige pay-as-you-go instanser |
| Weighted | Vektet distribusjon | Blue-green deployment av modeller |
| Priority-based | Prioritetsgrupper | PTU først, Standard som fallback |
| Session-aware | Sticky sessions | Chat-assistenter, tråd-baserte samtaler |

### Priority-basert Pool (PTU + Standard Fallback)

Det mest brukte mønsteret for AI-workloads:

```bicep
resource aoaiPool 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  name: 'ai-gateway-apim/aoai-pool'
  properties: {
    description: 'PTU prioritert med Standard fallback'
    type: 'Pool'
    pool: {
      services: [
        {
          // PTU deployment - prioritet 1 (brukes først)
          id: '/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ApiManagement/service/ai-gateway-apim/backends/aoai-ptu-westeurope'
          priority: 1
          weight: 1
        }
        {
          // Standard deployment - prioritet 2 (fallback)
          id: '/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ApiManagement/service/ai-gateway-apim/backends/aoai-standard-westeurope'
          priority: 2
          weight: 1
        }
        {
          // Standard deployment annen region - prioritet 3 (siste fallback)
          id: '/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ApiManagement/service/ai-gateway-apim/backends/aoai-standard-northeurope'
          priority: 3
          weight: 1
        }
      ]
    }
  }
}
```

### Weighted Pool (Blue-Green)

For gradvis utrulling av ny modellversjon:

```bicep
resource aoaiPoolBlueGreen 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  name: 'ai-gateway-apim/aoai-bluegreen'
  properties: {
    description: 'Blue-green deployment for modelloppgradering'
    type: 'Pool'
    pool: {
      services: [
        {
          // Eksisterende modellversjon (blue) - 90% trafikk
          id: '.../backends/aoai-gpt4o-v1'
          priority: 1
          weight: 9
        }
        {
          // Ny modellversjon (green) - 10% trafikk
          id: '.../backends/aoai-gpt4o-v2'
          priority: 1
          weight: 1
        }
      ]
    }
  }
}
```

### Session-Aware Pool for Chat-tjenester

Sikrer at alle requests i en chat-samtale rutes til samme backend:

```bicep
resource aoaiPoolSession 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  name: 'ai-gateway-apim/aoai-chat-pool'
  properties: {
    description: 'Session-aware pool for Assistants API'
    type: 'Pool'
    pool: {
      services: [
        {
          id: '.../backends/aoai-assistant-1'
          priority: 1
          weight: 1
        }
        {
          id: '.../backends/aoai-assistant-2'
          priority: 1
          weight: 1
        }
      ]
      sessionAffinity: {
        sessionId: {
          source: 'Cookie'
          name: 'SessionId'
        }
      }
    }
  }
}
```

**Merk:** Session awareness bruker Set-Cookie header. Klienten MÅ håndtere cookies korrekt.

---

## Health Probe Policies

### Circuit Breaker som Health Check

APIM bruker circuit breaker-regler for å vurdere backend-helse, i stedet for tradisjonelle health probes. Når feilbetingelsene i circuit breaker trigges, markeres backend som utilgjengelig og trafikk rutes til neste prioritetsgruppe.

```bicep
resource aoaiBackendWithBreaker 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  name: 'ai-gateway-apim/aoai-westeurope'
  properties: {
    url: 'https://aoai-westeurope.openai.azure.com'
    protocol: 'http'
    circuitBreaker: {
      rules: [
        {
          failureCondition: {
            count: 3
            errorReasons: ['Server errors']
            interval: 'PT1M'
            statusCodeRanges: [
              { min: 429, max: 429 }  // Throttling
              { min: 500, max: 599 }  // Server errors
            ]
          }
          name: 'ai-breaker'
          tripDuration: 'PT30S'
          acceptRetryAfter: true  // Respekter Retry-After header
        }
      ]
    }
  }
}
```

### Circuit Breaker Properties

| Egenskap | Beskrivelse | Anbefalt verdi for AI |
|----------|-------------|----------------------|
| `count` | Antall feil før trip | 3-5 (avhenger av trafikkmengde) |
| `interval` | Tidsvindu for feilmåling | PT1M (1 minutt) |
| `statusCodeRanges` | HTTP-koder som telles som feil | 429, 500-599 |
| `tripDuration` | Standard varighet for åpen circuit | PT30S - PT5M |
| `acceptRetryAfter` | Bruk Retry-After header fra backend | `true` (alltid for Azure OpenAI) |

### Viktig: Retry-After for Azure OpenAI

Azure OpenAI returnerer `Retry-After` header ved 429-responser. Verdien kan være stor (opptil 1 dag ved alvorlig overbelastning). Med `acceptRetryAfter: true` respekterer circuit breakeren denne verdien automatisk:

```
Request → 429 (Retry-After: 60) → Circuit åpner → Venter 60 sekunder → Circuit lukker
```

---

## Custom Health Checks

### Policy-basert Health Check

Implementer en custom health endpoint som sjekker backend-tilgjengelighet:

```xml
<!-- Health check API operation -->
<policies>
    <inbound>
        <base />
    </inbound>
    <backend>
        <!-- Send en minimal request til Azure OpenAI for å sjekke tilgjengelighet -->
        <forward-request timeout="10" />
    </backend>
    <outbound>
        <base />
        <choose>
            <when condition="@(context.Response.StatusCode == 200)">
                <return-response>
                    <set-status code="200" reason="OK" />
                    <set-body>{
    "status": "healthy",
    "backend": "@(context.Request.Url.Host)",
    "region": "@(context.Deployment.Region)",
    "timestamp": "@(DateTime.UtcNow.ToString("o"))"
}</set-body>
                </return-response>
            </when>
            <otherwise>
                <return-response>
                    <set-status code="503" reason="Service Unavailable" />
                    <set-body>{
    "status": "unhealthy",
    "backend": "@(context.Request.Url.Host)",
    "statusCode": @(context.Response.StatusCode),
    "timestamp": "@(DateTime.UtcNow.ToString("o"))"
}</set-body>
                </return-response>
            </otherwise>
        </choose>
    </outbound>
</policies>
```

### APIM Innebygd Health Endpoint

APIM tilbyr et innebygd status-endepunkt for overvåking:

```
GET https://{apim-name}-{region}-01.regional.azure-api.net/status-0123456789abcdef
```

Bruk dette med Azure Traffic Manager eller egendefinerte overvåkingssystemer.

---

## Timeout and Retry Logic

### Timeout-konfigurasjon for AI-requests

AI-forespørsler kan ta vesentlig lenger tid enn tradisjonelle API-kall, spesielt for store prompts eller streaming-scenarier:

| Scenario | Anbefalt Timeout | Begrunnelse |
|----------|-----------------|-------------|
| Chat completion | 60-120 sekunder | Store prompts, lange responser |
| Streaming | 120-240 sekunder | Langt-levende forbindelser |
| Embedding | 30-60 sekunder | Typisk raskere enn completions |
| Image generation | 120-180 sekunder | DALL-E kan ta lang tid |
| Assistants API | 120-300 sekunder | Komplekse tool-kall |

### Forward-request Policy med Timeout

```xml
<backend>
    <forward-request timeout="120"
                     fail-on-error-status-code="true"
                     buffer-response="false" />
</backend>
```

### Retry Policy for Transiente Feil

```xml
<backend>
    <retry condition="@(context.Response.StatusCode == 429 ||
                        context.Response.StatusCode >= 500)"
           count="3"
           interval="1"
           delta="2"
           max-interval="30"
           first-fast-retry="true">
        <forward-request timeout="120" buffer-response="false" />
    </retry>
</backend>
```

### Retry vs Circuit Breaker

| Aspekt | Retry | Circuit Breaker |
|--------|-------|----------------|
| Scope | Enkelt request | Alle requests til backend |
| Formål | Håndtere transiente feil | Beskytte overbelastet backend |
| Ventetid | Kort (sekunder) | Lengre (sekunder til minutter) |
| Backend-påvirkning | Sender nye requests | Stopper requests |
| Kombinasjon | Ja, retry innenfor circuit breaker | Ja, breaker trigger etter retry-feil |

---

## Pool Metrics

### Token-metriker per Backend

```xml
<outbound>
    <base />
    <llm-emit-token-metric namespace="ai-gateway-metrics">
        <dimension name="Backend" value="@(context.Request.Url.Host)" />
        <dimension name="Pool" value="@(context.Backend?.Id ?? "direct")" />
        <dimension name="BackendType" value="@(context.Backend?.Type ?? "unknown")" />
        <dimension name="Region" value="@(context.Deployment.Region)" />
        <dimension name="Model" value="@(context.Request.MatchedParameters["deployment-id"])" />
    </llm-emit-token-metric>
</outbound>
```

### KQL Queries for Pool-overvåking

**Token-fordeling per backend:**

```kusto
ApiManagementGatewayLlmLog
| where TimeGenerated > ago(1h)
| summarize
    TotalTokens = sum(TotalTokens),
    PromptTokens = sum(PromptTokens),
    CompletionTokens = sum(CompletionTokens),
    RequestCount = count()
  by BackendUrl
| order by TotalTokens desc
```

**Circuit breaker-trigging per backend:**

```kusto
ApiManagementGatewayLogs
| where TimeGenerated > ago(24h)
| where ResponseCode == 503
| where BackendResponseCode == 429 or BackendResponseCode >= 500
| summarize
    TripCount = count(),
    AvgRetryAfter = avg(todouble(ResponseHeaders["Retry-After"]))
  by BackendUrl, bin(TimeGenerated, 1h)
| order by TimeGenerated desc
```

**Backend-tilgjengelighet:**

```kusto
ApiManagementGatewayLogs
| where TimeGenerated > ago(24h)
| summarize
    TotalRequests = count(),
    SuccessRequests = countif(ResponseCode >= 200 and ResponseCode < 300),
    ThrottledRequests = countif(ResponseCode == 429),
    ErrorRequests = countif(ResponseCode >= 500)
  by BackendUrl, bin(TimeGenerated, 15m)
| extend Availability = round(100.0 * SuccessRequests / TotalRequests, 2)
| order by TimeGenerated desc
```

### Azure Monitor Alerts for Backend Pools

```bicep
resource backendHealthAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = {
  name: 'ai-gateway-backend-errors'
  location: 'global'
  properties: {
    severity: 2
    evaluationFrequency: 'PT5M'
    windowSize: 'PT15M'
    criteria: {
      'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
      allOf: [
        {
          name: 'HighBackendErrors'
          metricName: 'BackendRequestCount'
          operator: 'GreaterThan'
          threshold: 50
          timeAggregation: 'Total'
          dimensions: [
            {
              name: 'BackendResponseCodeCategory'
              operator: 'Include'
              values: ['5xx']
            }
          ]
        }
      ]
    }
    actions: [
      {
        actionGroupId: actionGroup.id
      }
    ]
  }
}
```

---

## Best Practices

### Backend Pool Design for AI

| Anbefaling | Begrunnelse |
|------------|-------------|
| PTU som Priority 1, Standard som Priority 2 | Utnytter fast PTU-kapasitet først |
| Circuit breaker med `acceptRetryAfter: true` | Respekterer Azure OpenAI throttling |
| Separate pools per region | Unngår cross-region latens |
| Session awareness for chat | Sikrer kontekst i samtaler |
| Maks 30 backends per pool | APIM-begrensning |

### Anti-patterns

| Anti-pattern | Problem | Løsning |
|-------------|---------|---------|
| Én pool med backends i mange regioner | Cross-region latens | Regionspesifikke pools |
| Ingen circuit breaker | Backend overbelastes | Alltid konfigurer circuit breaker |
| Kort tripDuration | Konstant flapping | Minimum 30 sekunder |
| Retry uten circuit breaker | DDoS mot egen backend | Kombiner begge |

---

## Referanser

- [Backends in API Management](https://learn.microsoft.com/en-us/azure/api-management/backends) — Offisiell backend-dokumentasjon
- [AI gateway in Azure API Management](https://learn.microsoft.com/en-us/azure/api-management/genai-gateway-capabilities) — AI gateway resiliency-funksjoner
- [Circuit breaker pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker) — Arkitekturmønster for circuit breaker
- [Smart Load Balancing for OpenAI Endpoints](https://github.com/Azure-Samples/openai-apim-lb) — GitHub sample med priority-basert routing
- [GenAI Gateway Toolkit](https://github.com/Azure-Samples/ai-gateway) — Lab-exercises for AI gateway

---

## For Cosmo

- **Bruk denne referansen** når kunder trenger å sette opp load balancing mellom flere Azure OpenAI-instanser via APIM, spesielt for PTU + Standard fallback-mønstre.
- Anbefal alltid circuit breaker med `acceptRetryAfter: true` for Azure OpenAI backends — dette er kritisk for å håndtere 429 throttling uten å overbelaste backend.
- Husk begrensningen: Maks 30 backends per pool. For store organisasjoner med mange regioner, bruk hierarkiske pools (en pool per region, med regional routing via policy).
- Session awareness er viktig for Assistants API og chat-scenarier — uten dette kan tråder miste kontekst når requests rutes til forskjellige backends.
- Circuit breaker-regler er tilnærmede (approximate) pga. distribuert arkitektur — ulike gateway-instanser synkroniserer ikke circuit state.
