ms-ai-architect/skills/ms-ai-security/references/performance-scalability/connection-pooling-patterns.md
Kjell Tore Guttormsen 070141f06b chore(ms-ai-architect): refresh KB medium-bucket — 74 files [skip-docs]
KB-currency refresh (medium priority, 2026-06-19) via /architect:kb-update.
74 medium-prioritets filer re-verifisert mot Microsoft Learn (MCP) — delegert
til 15 parallelle Opus-subagenter (3 bølger) gruppert etter delt kilde, med
disjunkte fil-sett. Verifisert i hovedkontekst (scope-sjekk + diff-review av
de faktatunge gruppene + tester).

Hovedendringer (faktuelle korreksjoner + currency):
- Azure AI Search semantic ranker: TILGJENGELIG PÅ ALLE TIERS (også Free/Basic
  m/ gratis månedlig kvote) — gammel KB sa feilaktig "kun S1+". Korrigert i
  tier-tabell, anti-patterns og beslutningstabell (azure-ai-search-setup).
- APIM score-threshold = DISTANSE (lavere = strengere): tuning-tabellen i
  rag-caching-optimization hadde retningen baklengs — invertert til korrekt.
- Agentic retrieval GA/preview-nyanse presisert (hovedkontekst-korreksjon mot
  agentic-retrieval-how-to-migrate): GA via REST 2026-04-01 returnerer EKSTRAKTIV
  grounding (references + activity), IKKE syntetiserte svar. Answer synthesis,
  ikke-minimal reasoning effort (LLM query planning) og multi-turn messages
  forblir preview (2026-05-01-preview). Subagent hadde overforenklet til "hele
  kjernepipelinen GA"; rettet i agentic-rag-patterns + citation-tracking.
- Copilot Studio modell-tabeller (platforms/copilot-studio): fjernet Claude Opus
  4.5 + GPT-5.2 (borte fra kilde), lagt til Claude Sonnet 4.6/Opus 4.6 (GA),
  Opus 4.7 + Mistral Medium 3.5 (experimental); GPT-5 Reasoning/Auto = preview;
  A2A GA (apr 2026).
- Computer Use (CUA): Copilot Studio GA 2026-05-07; 4 modeller m/ tier/status
  (OpenAI CUA + Sonnet 4.5 GA, Sonnet 4.6 + Opus 4.6 experimental); 5 credits/
  steg standard, 15 premium; US-only region-krav FJERNET i GA-dok; Cloud PC pool
  + Hosted browser + bring-your-own-machine.
- Azure AI Search REST API-versjoner bumpet: 2025-09-01 -> 2026-04-01 (stabil),
  2025-11-01-preview -> 2026-05-01-preview (hybrid-search, rag-security-rbac,
  chunking).
- Power Automate-integrasjon: trigger "Run a flow from Copilot" -> "When an agent
  calls the flow"; App Service innebygd MCP (preview) lagt til.
- M365 Copilot-manifest v1.26 -> v1.28 (GA, mai) / v1.29 dokumentert (juni);
  "Tenant graph grounding" -> "Work IQ".
- Speech fast transcription 2t/300MB -> 5t/500MB; multilingual 14 -> 15 locales
  (+ pt-BR). Content Understanding reasoning preview -> GA (v1.0, 2025-11-01).
- Security Copilot E5 -> E5+E7. Død Databricks-URL ci-cd/best-practices ->
  ci-cd/flows. Prompt Flow retirement (2027-04-20 -> MAF) notert der den
  presenteres som go-forward. Gateway-topologi-tabell-feil rettet.
- Alle 74 Last updated -> 2026-06-19.

Discovery ikke kjørt (historisk kun Databricks-støy) -> 389-telling uendret,
ingen resync. validate 239 PASS, kb-integrity 115/115 (262 orphan-warnings
uendret), gitleaks clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 14:02:18 +02:00

16 KiB

Connection Pooling Patterns

Last updated: 2026-06-19 | Verified: MCP 2026-06-19 Status: GA Category: Performance & Scalability


Introduksjon

Connection pooling er en kritisk ytelsesoptimalisering for applikasjoner som kommuniserer med Azure AI Services. Hver HTTP-forbindelse til Azure OpenAI eller andre AI-endepunkter krever TCP-håndtrykk og eventuelt TLS-forhandling, noe som legger til betydelig latens per forespørsel. Uten connection pooling opprettes og lukkes forbindelser for hver eneste forespørsel, noe som fører til port-utmattelse, økt responstid og unødvendig CPU-bruk.

I .NET-økosystemet er HttpClient den sentrale klassen for HTTP-kommunikasjon, og Microsofts offisielle retningslinjer er tydelige: bruk én statisk HttpClient-instans per logisk klient, eller bruk IHttpClientFactory for å håndtere DNS-endringer og connection lifecycle. Azure OpenAI SDK-ene (både Python og C#) håndterer connection pooling internt, men korrekt konfigurasjon er fortsatt nødvendig for optimal ytelse.

For norsk offentlig sektor der AI-tjenester typisk nås via private endpoints og ofte går gjennom Azure API Management, er connection pooling spesielt viktig. Nettverkskjeden (klient → APIM → Private Endpoint → Azure OpenAI) multipliserer latens-kostnaden av nye forbindelser, og korrekt pooling kan redusere p50-latens med 30-50 ms per forespørsel.

Kjernekomponenter

Komponent Formål Teknologi
HttpClient / HttpClientFactory HTTP connection management i .NET System.Net.Http
SocketsHttpHandler Underliggende socket-håndtering med pool .NET 6+
aiohttp.ClientSession Asynkron HTTP med connection pool i Python aiohttp
httpx.AsyncClient Moderne asynkron HTTP-klient med pool httpx
Azure OpenAI SDK Innebygd connection management azure-ai-openai
Azure API Management Gateway med backend connection pooling Azure APIM

Pool Sizing-strategier

Beregning av optimal pool-størrelse

Pool-størrelsen bør baseres på forventet concurrent request-volum og responstid fra backend-tjenesten.

# Beregn optimal pool-størrelse
# Formel: pool_size = concurrent_requests * avg_response_time_seconds / target_utilization

def calculate_pool_size(
    concurrent_users: int,
    avg_response_time_ms: float,
    requests_per_user_per_second: float = 1.0,
    target_utilization: float = 0.75
) -> int:
    """Calculate optimal connection pool size for AI workloads."""
    concurrent_requests = concurrent_users * requests_per_user_per_second
    avg_response_time_s = avg_response_time_ms / 1000

    # Connections needed = concurrent requests * time each holds a connection
    connections_needed = concurrent_requests * avg_response_time_s

    # Add headroom for bursts
    pool_size = int(connections_needed / target_utilization)

    # Azure OpenAI typical ranges
    return max(pool_size, 10)  # Minimum 10 connections

# Eksempel: 50 samtidige brukere, 800ms avg responstid
optimal = calculate_pool_size(
    concurrent_users=50,
    avg_response_time_ms=800,
    requests_per_user_per_second=0.5
)
print(f"Anbefalt pool-størrelse: {optimal}")  # ~27 connections

.NET HttpClientFactory-konfigurasjon

// Program.cs - Optimal HttpClient-konfigurasjon for Azure OpenAI
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http;

var builder = WebApplication.CreateBuilder(args);

// Registrer named HttpClient for Azure OpenAI
builder.Services.AddHttpClient("AzureOpenAI", client =>
{
    client.BaseAddress = new Uri(
        builder.Configuration["AzureOpenAI:Endpoint"]!);
    client.DefaultRequestHeaders.Add("api-key",
        builder.Configuration["AzureOpenAI:ApiKey"]!);
    client.Timeout = TimeSpan.FromSeconds(120);
})
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
    // Pool-konfigurasjon
    MaxConnectionsPerServer = 50,          // Maks connections per host
    PooledConnectionLifetime = TimeSpan.FromMinutes(5),  // DNS refresh
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),

    // Keep-alive
    KeepAlivePingPolicy = HttpKeepAlivePingPolicy.WithActiveRequests,
    KeepAlivePingDelay = TimeSpan.FromSeconds(30),
    KeepAlivePingTimeout = TimeSpan.FromSeconds(10),

    // Performance
    EnableMultipleHttp2Connections = true,
    AutomaticDecompression = System.Net.DecompressionMethods.GZip
})
.SetHandlerLifetime(TimeSpan.FromMinutes(10));  // Handler rotation

// Registrer Azure OpenAI-klient med pooled HttpClient
builder.Services.AddSingleton(sp =>
{
    var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
    var httpClient = httpClientFactory.CreateClient("AzureOpenAI");

    return new Azure.AI.OpenAI.AzureOpenAIClient(
        new Uri(builder.Configuration["AzureOpenAI:Endpoint"]!),
        new Azure.AzureKeyCredential(
            builder.Configuration["AzureOpenAI:ApiKey"]!));
});

Keep-alive-konfigurasjon

HTTP/2 Multiplexing

Azure OpenAI støtter HTTP/2, som muliggjør multipleksing av flere forespørsler over én enkelt TCP-forbindelse:

// HTTP/2 multiplexing for Azure OpenAI
var handler = new SocketsHttpHandler
{
    // Aktiver HTTP/2 med multipleksing
    EnableMultipleHttp2Connections = true,

    // Keep-alive for langvarige streams
    KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always,
    KeepAlivePingDelay = TimeSpan.FromSeconds(15),
    KeepAlivePingTimeout = TimeSpan.FromSeconds(5),

    // Connection lifecycle
    PooledConnectionLifetime = TimeSpan.FromMinutes(10),
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),
    MaxConnectionsPerServer = 100
};

var client = new HttpClient(handler)
{
    DefaultRequestVersion = HttpVersion.Version20,
    DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower
};

Python aiohttp Session Management

import aiohttp
import asyncio
from openai import AsyncAzureOpenAI

async def create_optimized_session() -> aiohttp.ClientSession:
    """Create an optimized aiohttp session for Azure OpenAI."""
    connector = aiohttp.TCPConnector(
        limit=100,              # Total connection pool size
        limit_per_host=50,      # Max connections per host
        ttl_dns_cache=300,      # DNS cache TTL i sekunder
        keepalive_timeout=30,   # Keep-alive timeout
        enable_cleanup_closed=True,
        force_close=False       # Gjenbruk connections
    )

    timeout = aiohttp.ClientTimeout(
        total=120,              # Total timeout
        connect=10,             # Connection timeout
        sock_read=60            # Read timeout
    )

    return aiohttp.ClientSession(
        connector=connector,
        timeout=timeout,
        headers={"Connection": "keep-alive"}
    )

# Bruk med Azure OpenAI Python SDK
async def create_pooled_openai_client() -> AsyncAzureOpenAI:
    """Create Azure OpenAI client with optimized connection pooling."""
    import httpx

    transport = httpx.AsyncHTTPTransport(
        retries=3,
        limits=httpx.Limits(
            max_connections=100,
            max_keepalive_connections=50,
            keepalive_expiry=30
        )
    )

    http_client = httpx.AsyncClient(
        transport=transport,
        timeout=httpx.Timeout(120.0, connect=10.0)
    )

    return AsyncAzureOpenAI(
        azure_endpoint="https://my-aoai.openai.azure.com",
        api_key="...",
        api_version="2024-10-21",
        http_client=http_client
    )

Connection Recycling

Håndtering av DNS-endringer

Når Azure OpenAI-endepunkter er bak Traffic Manager eller Azure Front Door, endres IP-adresser regelmessig. Connection pooling må balansere gjenbruk med DNS-fornyelse:

// Connection recycling pattern
public class ConnectionRecyclingConfig
{
    // PooledConnectionLifetime: Tvinger nye DNS-oppslag
    // Sett lavere enn DNS TTL for failover-scenarier
    public TimeSpan PooledConnectionLifetime { get; set; }
        = TimeSpan.FromMinutes(5);

    // PooledConnectionIdleTimeout: Fjern ubrukte connections
    public TimeSpan PooledConnectionIdleTimeout { get; set; }
        = TimeSpan.FromMinutes(2);

    // Handler lifetime for IHttpClientFactory
    // Roterer hele handleren — nye connections med ny DNS
    public TimeSpan HandlerLifetime { get; set; }
        = TimeSpan.FromMinutes(10);
}

// Anti-pattern: ALDRI gjør dette
// ❌ var client = new HttpClient();  // Ny for hver forespørsel
// ❌ using var client = new HttpClient(); // Disponeres for tidlig

// Korrekt pattern: Singleton eller factory
// ✅ Statisk HttpClient med SocketsHttpHandler
// ✅ IHttpClientFactory i DI

Load Distribution

Round-robin over multiple Azure OpenAI-instanser

import asyncio
import random
from dataclasses import dataclass, field
from typing import Optional
from openai import AsyncAzureOpenAI

@dataclass
class AzureOpenAIBackend:
    endpoint: str
    api_key: str
    priority: int = 1
    is_healthy: bool = True
    retry_after: Optional[float] = None
    client: Optional[AsyncAzureOpenAI] = field(default=None, repr=False)

class ConnectionPoolLoadBalancer:
    """Load balancer with dedicated connection pools per backend."""

    def __init__(self, backends: list[AzureOpenAIBackend]):
        self.backends = backends
        # Separat connection pool per backend
        for backend in self.backends:
            backend.client = AsyncAzureOpenAI(
                azure_endpoint=backend.endpoint,
                api_key=backend.api_key,
                api_version="2024-10-21",
                max_retries=0  # Vi håndterer retry selv
            )

    def _select_backend(self) -> AzureOpenAIBackend:
        """Select backend by priority, then random among same priority."""
        import time

        # Filtrer friske backends
        available = [
            b for b in self.backends
            if b.is_healthy or (
                b.retry_after and time.time() > b.retry_after
            )
        ]

        if not available:
            available = self.backends  # Fallback til alle

        # Velg laveste prioritet (høyest prioritet)
        min_priority = min(b.priority for b in available)
        candidates = [b for b in available if b.priority == min_priority]

        return random.choice(candidates)

    async def chat_completion(self, messages: list, **kwargs):
        """Route request to best available backend."""
        import time

        for attempt in range(len(self.backends)):
            backend = self._select_backend()
            try:
                response = await backend.client.chat.completions.create(
                    messages=messages, **kwargs
                )
                backend.is_healthy = True
                return response
            except Exception as e:
                if hasattr(e, 'status_code') and e.status_code == 429:
                    retry_after = getattr(e, 'retry_after', 10)
                    backend.retry_after = time.time() + retry_after
                    backend.is_healthy = False
                elif hasattr(e, 'status_code') and e.status_code >= 500:
                    backend.is_healthy = False
                else:
                    raise

        raise Exception("All backends exhausted")

Azure API Management som Connection Pooling-lag (oppdatert 2026-06-19)

APIM håndterer backend connection pooling mot Azure OpenAI, noe som avlaster klientsiden:

APIM Backend Pool-konfigurasjon

<!-- APIM: Backend pool med automatisk connection management -->
<policies>
    <inbound>
        <base />
        <!-- APIM gjenbruker backend-connections automatisk via intern pool -->
        <!-- Klientene ser APIM som et enkelt endepunkt -->
        <set-backend-service id="aoai-pool" backend-id="aoai-norway-backend" />
        
        <!-- Legg til correlation ID for tracing -->
        <set-header name="x-correlation-id" exists-action="skip">
            <value>@(context.RequestId)</value>
        </set-header>
    </inbound>
    
    <backend>
        <retry condition="@(context.Response.StatusCode == 429 || context.Response.StatusCode >= 500)"
               count="3" interval="0" first-fast-retry="true">
            <!-- APIM håndterer retry mot backend-pool -->
            <forward-request timeout="120" />
        </retry>
    </backend>
    
    <outbound>
        <!-- Eksponer backend latens-metrikk til klient -->
        <set-header name="x-backend-latency-ms" exists-action="override">
            <value>@(context.Elapsed.TotalMilliseconds.ToString())</value>
        </set-header>
    </outbound>
</policies>

Backend-konfigurasjoner i APIM (4 topologier)

Microsoft anbefaler disse mønstrene for APIM connection pooling mot Azure OpenAI:

  1. Single backend: Én APIM → én Azure OpenAI (enkelt, begrenset kvote)
  2. Multi-backend single region: APIM med weighted round-robin mellom Azure OpenAI-instanser
  3. Multi-subscription: Separate Azure OpenAI-instanser i ulike subscriptions for kvote-skalering
  4. Multi-region: APIM i flere regioner, each med regionale backends

Klientene trenger aldri kjenne til antallet backends — APIM håndterer routing transparent.

Norsk offentlig sektor

Connection pooling har spesielle hensyn for norsk offentlig sektor:

  • Data residency: Alle connections må gå via regioner som oppfyller Schrems II-kravene. Ved bruk av Azure Norway East som primær region, konfigurer PooledConnectionLifetime kort nok til å håndtere failover til Sweden Central.
  • Private endpoints: Connection pools som bruker Private Link har andre DNS-oppløsningsmønstre. Konfigurer ttl_dns_cache i Python eller PooledConnectionLifetime i .NET til å matche DNS TTL for privatelink-soner (typisk 10 sekunder).
  • NSMs grunnprinsipper: Logging av connection pool-metrikker (aktive connections, pool hits/misses, connection errors) er påkrevd for å oppfylle krav om overvåking av nettverkstrafikk.
  • Anskaffelsesreglement: Ved bruk av tredjepartsbiblioteker for connection pooling, verifiser at de er godkjent for bruk i offentlig sektor (åpen kildekode med akseptabel lisens).

Beslutningsrammeverk

Scenario Anbefaling Begrunnelse
Enkelttjeneste, lav trafikk (<10 RPS) Statisk HttpClient med default pool Enkel oppsett, tilstrekkelig ytelse
Enkelttjeneste, høy trafikk (>50 RPS) HttpClientFactory med SocketsHttpHandler DNS rotation, pool sizing, monitoring
Multi-region med failover Separat pool per region + load balancer Isolerer feil, støtter weighted routing
Via Azure APIM APIM backend pool + klient-side pool APIM håndterer backend-balansering
Streaming/SSE-respons Dedikert pool med lange timeouts Streaming holder connections åpne lenger
Azure Functions (serverless) Static HttpClient i startup Unngå cold start connection overhead

Referanser

For Cosmo

  • Bruk denne referansen når kunden rapporterer høy latens, port-utmattelse, eller timeout-feil mot Azure OpenAI — connection pooling er ofte root cause.
  • Anbefal IHttpClientFactory for .NET og httpx.AsyncClient med Limits for Python — aldri instansier HttpClient per forespørsel.
  • For multi-region AI-arkitekturer, opprett separate connection pools per region med individuelle health checks og retry-after tracking.
  • Sett PooledConnectionLifetime til 2-5 minutter for å balansere DNS-fornyelse med connection gjenbruk — kortere for failover-scenarier.
  • Monitorer alltid connections.active, connections.idle og pool.exhausted metrikker i Application Insights for å oppdage pool-problemer tidlig.