Bootcamp i FastAPI-backendudvikling · Lektion

Alarmering på SLO'er og error budgets

Definér servicemål, og forbind handlingsrettede alarmer, der udløses, før brugerne bemærker forringelsen.

Lektion 4 af 413 trin

Alarmering på SLO'er og error budgets er en gratis Bootcamp i FastAPI-backendudvikling-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Bootcamp i FastAPI-backendudvikling, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Bootcamp i FastAPI-backendudvikling-kurset indeholder 4 lektioner i alt.

Hvorfor du skal alarmere på SLO'er og ikke rå målinger

Traditionelle alarmer udløses af rå symptomer som CPU > 90% eller error_count > 100. Problemet er, at de sender besked om ting, som brugerne aldrig bemærker, og forbliver tavse under langsom forringelse, der skader kunderne.

SLO-baseret alarmering vender dette på hovedet. Først definerer du, hvad "god service" betyder for en bruger, og derefter alarmerer du kun, når du risikerer at bryde det løfte.

  • SLI (serviceniveauindikator): en målt brøkdel, f.eks. andelen af hurtige, vellykkede anmodninger.
  • SLO (serviceniveaumål): målet for denne SLI, f.eks. 99,9 % over 30 dage.
  • Fejlbudget: det tilladte antal fejl, altså 100 % minus SLO'en.

I denne lektion definerer du SLO'er for en FastAPI-tjeneste og forbinder alarmer, der udløses før brugerne bemærker forringelsen.

Valg af en god SLI til en API

En god SLI er forholdet mellem gode hændelser og gyldige hændelser, skaleret fra 0 til 100 %. For en FastAPI-backend er de to vigtigste SLI'er:

  • Tilgængelighed: vellykkede svar / alle gyldige svar. Betragt 5xx som fejl, og udeluk normalt 4xx (klientens fejl).
  • Forsinkelse: anmodninger, der betjenes under en tærskel / alle anmodninger, f.eks. svar, der er hurtigere end 300 ms.

Nedenfor er en lille, selvstændig beregner, der omdanner rå anmodningslogfiler til disse to SLI'er.

def compute_slis(requests, latency_threshold_ms=300):
    valid = [r for r in requests if r["status"] < 500 or r["status"] >= 500]
    total = len(valid)
    good_avail = sum(1 for r in valid if r["status"] < 500)
    fast = sum(1 for r in valid if r["latency_ms"] <= latency_threshold_ms)
    availability = good_avail / total
    latency_sli = fast / total
    return {"availability": availability, "latency": latency_sli}


sample = [
    {"status": 200, "latency_ms": 120},
    {"status": 200, "latency_ms": 410},
    {"status": 500, "latency_ms": 90},
    {"status": 200, "latency_ms": 250},
    {"status": 503, "latency_ms": 600},
]

slis = compute_slis(sample)
print(f"availability = {slis['availability']:.2%}")
print(f"latency      = {slis['latency']:.2%}")

Fra SLO til fejlbudget

Når du først har forpligtet dig til et SLO, er fejlbudgettet ganske enkelt de fejl, du må have, før du overskrider det.

  • SLO på 99,9 % over 30 dage → budget = 0,1 % af alle anmodninger må fejle.
  • Hvis du betjener 10.000.000 anmodninger om måneden, svarer det til 10.000 mislykkede anmodninger, du kan bruge.
  • Udtrykt som tid med fuldt driftsstop: 30 dage × 0,1 % ≈ 43 minutter nedetid om måneden.

Budgettet er en valuta. Hver fejl bruger af den. Alarmering handler om at overvåge denne valutas forbrændingshastighed.

def error_budget(slo_percent, total_requests, window_days=30):
    allowed_failure_ratio = 1 - (slo_percent / 100)
    budget_requests = total_requests * allowed_failure_ratio
    budget_minutes = window_days * 24 * 60 * allowed_failure_ratio
    return budget_requests, budget_minutes


for slo in (99.0, 99.9, 99.99):
    reqs, mins = error_budget(slo, 10_000_000)
    print(f"SLO {slo}% -> {reqs:,.0f} req budget, {mins:.1f} min downtime/30d")

Forbrændingshastighed: Grundideen

Forbrændingshastighed er, hvor hurtigt du bruger fejlbudgettet sammenlignet med det forventede tempo. En forbrændingshastighed på 1 betyder, at du præcis vil opbruge 30-dagesbudgettet på 30 dage. En forbrændingshastighed på 14.4 betyder, at du vil opbruge det på omtrent 2 dage.

Formlen:

  • burn_rate = observed_error_rate / (1 - SLO)
  • Hvis SLO = 99,9 %, er budgettets fejlfrekvens 0,001. En observeret fejlfrekvens på 1,44 % giver en forbrændingshastighed på 0.0144 / 0.001 = 14.4.

Høj forbrændingshastighed over et kort vindue = noget brænder lige nu. Moderat forbrænding over et langt vindue = en langsom lækage. Du alarmerer om begge dele.

def burn_rate(observed_error_rate, slo_percent):
    budget_rate = 1 - (slo_percent / 100)
    return observed_error_rate / budget_rate


for err in (0.001, 0.005, 0.0144, 0.05):
    br = burn_rate(err, 99.9)
    hours_to_exhaust = (30 * 24) / br if br else float("inf")
    print(f"err={err:.3%} -> burn={br:5.1f}x, exhausts budget in {hours_to_exhaust:6.1f}h")

Alarmer med flere tidsvinduer og forbrændingshastigheder

En enkelt tærskel er en fælde: Hvis du alarmerer for hurtigt, bliver du kaldt ud på korte udsving; hvis du venter for længe, overser du reelle driftsforstyrrelser. Det mønster, som Google SRE anbefaler, bruger flere forbrændingshastigheder over flere tidsvinduer:

  • Hurtig forbrænding: 14.4x over 1 time (og et tjek på 5 minutter) → tilkald nu, for hele månedens budget bliver brugt på ~2 dage.
  • Langsom forbrænding: 6x over 6 timer → tilkald, vedvarende lækage.
  • Drypvist forbrug: 1x over 3 dage → opret en opgave, ikke en tilkaldelse.

Hvis du kombinerer et langt tidsvindue med et kort vindue til at kontrollere, "om det stadig sker", eliminerer du falske positiver: Alarmen udløses kun, hvis forbrændingen både er alvorlig og aktuel.

ALERT_TIERS = [
    {"name": "page_fast", "burn": 14.4, "long_window_h": 1, "short_window_m": 5},
    {"name": "page_slow", "burn": 6.0, "long_window_h": 6, "short_window_m": 30},
    {"name": "ticket",    "burn": 1.0, "long_window_h": 72, "short_window_m": 360},
]


def evaluate(long_burn, short_burn):
    for tier in ALERT_TIERS:
        if long_burn >= tier["burn"] and short_burn >= tier["burn"]:
            return tier["name"]
    return "ok"


print(evaluate(long_burn=16.0, short_burn=15.0))  # spike still active
print(evaluate(long_burn=16.0, short_burn=0.2))   # recovered, suppress
print(evaluate(long_burn=2.0,  short_burn=2.0))    # slow leak -> ticket

Instrumentering af FastAPI til at levere data til SLI'en

Alarmer er kun så gode som deres data. Tilføj Prometheus-tællere og et histogram via middleware, så hver forespørgsel bidrager til dine SLI'er for tilgængelighed og svartid.

Dette er framework-kode (FastAPI + middleware), så den kan ikke køres selvstændigt, men den viser det kanoniske instrumenteringsmønster.

import time
from fastapi import FastAPI, Request
from prometheus_client import Counter, Histogram, make_asgi_app

app = FastAPI()

REQUESTS = Counter(
    "http_requests_total", "All requests", ["method", "path", "status"]
)
LATENCY = Histogram(
    "http_request_duration_seconds", "Request latency", ["path"],
    buckets=(0.05, 0.1, 0.3, 0.5, 1.0, 2.5),
)


@app.middleware("http")
async def record_metrics(request: Request, call_next):
    start = time.perf_counter()
    response = await call_next(request)
    elapsed = time.perf_counter() - start
    path = request.url.path
    REQUESTS.labels(request.method, path, response.status_code).inc()
    LATENCY.labels(path).observe(elapsed)
    return response


app.mount("/metrics", make_asgi_app())

Skriv SLI'en som en PromQL-recording rule

Med tællerne på plads udtrykker du SLI'erne i PromQL. En recording rule beregner fejlandelen på forhånd, så alarmreglerne forbliver effektive og læsbare.

Forholdet mellem vellykkede hændelser i alarmvinduet er det, du sammenligner med tærsklen for forbrændingshastigheden. Bemærk, at tærsklen 0.0144 er lig med 14.4 × (1 - 0.999) — forbrændingshastigheden er indarbejdet i sammenligningen.

# prometheus rules.yml
groups:
  - name: slo_recording
    rules:
      - record: job:http_error_ratio:rate1h
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[1h]))
          /
          sum(rate(http_requests_total[1h]))

      - record: job:http_error_ratio:rate5m
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m]))
          /
          sum(rate(http_requests_total[5m]))

Alarmreglen for hurtig forbrænding

Nu kommer alarmen. Den udløses kun, når både fejlandelen for 1 time og 5 minutter overskrider tærsklen på 14.4x forbrænding for en SLO på 99,9 %. Det korte tidsvindue sikrer, at problemet stadig foregår, før en vagtgående tekniker tilkaldes.

  • 0.0144 = 14.4 × (1 - 0.999)
  • for: 2m filtrerer kortvarige spidser fra.
  • Etiketter dirigerer alvorlighedsgraden, og annotationer indeholder linket til runbooken.
# prometheus alerts.yml
groups:
  - name: slo_alerts
    rules:
      - alert: HighErrorBudgetBurnFast
        expr: |
          job:http_error_ratio:rate1h > 0.0144
          and
          job:http_error_ratio:rate5m > 0.0144
        for: 2m
        labels:
          severity: page
          slo: availability-99.9
        annotations:
          summary: "Burning error budget 14.4x (1h+5m)"
          description: "At this rate the 30d budget is gone in ~2 days."
          runbook: "https://runbooks.internal/slo-fast-burn"

Simulér en alarmbeslutning i Python

Før du stoler på dine regler i produktion, skal du simulere dem. Denne selvstændige evaluator afspiller et vindue med forespørgsler, beregner både korte og lange fejlandele og afgør, om en tilkaldelse skal udløses — præcis som reglen med flere tidsvinduer.

def error_ratio(window):
    if not window:
        return 0.0
    failures = sum(1 for r in window if r >= 500)
    return failures / len(window)


def should_page(long_window, short_window, slo=99.9, multiplier=14.4):
    threshold = multiplier * (1 - slo / 100)
    long_r = error_ratio(long_window)
    short_r = error_ratio(short_window)
    return long_r > threshold and short_r > threshold, long_r, short_r


long_w = [200] * 940 + [500] * 60   # 6% errors over the hour
short_w = [200] * 95 + [500] * 5     # 5% still in last 5 min

fire, lr, sr = should_page(long_w, short_w)
print(f"long={lr:.2%} short={sr:.2%} -> page={fire}")

SLO'er for svartid kræver percentiler, ikke gennemsnit

Gennemsnit skjuler problemerne i halen. Hvis 99 % af forespørgslerne tager 80 ms, og 1 % tager 4 sekunder, ser gennemsnittet fint ud, mens de reelle brugere bliver frustrerede. Definér SLO'er for svartid ud fra percentiler (p95, p99) eller som andelen under en tærskel.

Med et Prometheus-histogram er p99 over 5 minutter:

  • histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))

Nedenfor viser en ren Python-hjælpefunktion til p-kvantiler den matematik, som dit histogram tilnærmer.

def percentile(values, p):
    if not values:
        return None
    s = sorted(values)
    k = (len(s) - 1) * (p / 100)
    lo = int(k)
    hi = min(lo + 1, len(s) - 1)
    frac = k - lo
    return s[lo] + (s[hi] - s[lo]) * frac


latencies = [70, 75, 80, 82, 90, 95, 110, 130, 300, 4000]
for p in (50, 95, 99):
    print(f"p{p} = {percentile(latencies, p):.0f} ms")

Handlingsrettede alarmer og budgetpolitik

En alarm, som ingen kan handle på, er støj. Gør hver tilkaldelse handlingsrettet:

  • Symptom-baseret: Alarmér ved et brud på SLO'en (brugerne er berørt), ikke ved én bestemt årsag.
  • Runbook vedlagt: Hver alarm linker til trin til diagnosticering og afhjælpning.
  • Dirigeret efter alvorlighedsgrad: page vækker nogen, mens ticket kan vente til arbejdstiden.

Knyt det til en fejlbudgetpolitik: Når budgettet er sundt, kan du levere funktioner hurtigt. Når det er opbrugt, skal du sætte risikable udrulninger på pause og prioritere pålidelighed. Budgettet gør pålidelighed til en fælles, datadrevet beslutning i stedet for en holdning.

def budget_policy(consumed_ratio):
    if consumed_ratio < 0.5:
        return "GREEN: ship freely"
    if consumed_ratio < 0.9:
        return "YELLOW: extra review on risky changes"
    if consumed_ratio < 1.0:
        return "ORANGE: freeze non-critical deploys"
    return "RED: budget exhausted, reliability work only"


for used in (0.2, 0.7, 0.95, 1.1):
    print(f"{used:.0%} budget used -> {budget_policy(used)}")

Hurtigt tjek: Vælg alarmudløseren

Du kører en FastAPI-tjeneste med en SLO for tilgængelighed på 99,9 %. Du vil kun tilkalde den vagtgående tekniker ved problemer, der reelt truer månedens fejlbudget, samtidig med at du undgår falske alarmer fra korte udsving. Hvilken alarmstrategi passer bedst?

Opsummering: SLO-drevet alarmering

Du har lært at alarmere ud fra brugervendt pålidelighed i stedet for rå symptomer:

  • SLI = vellykkede hændelser / gyldige hændelser; SLO = målet; fejlbudget = 100 % minus SLO'en.
  • Forbrændingshastighed = observeret fejlrate / budgetrate; den fortæller, hvor hurtigt budgettet bliver brugt.
  • Alarmer med flere tidsvinduer og flere forbrændingshastigheder (f.eks. 14.4x over 1 time + 5 minutter for en tilkaldelse og langsommere forbrændinger for en opgave) opdager reel forringelse tidligt uden at tilkalde nogen ved korte udsving.
  • Instrumentér FastAPI med Prometheus-tællere og histogrammer, udtryk SLI'er som recording rules, og definér alarmer ud fra fejlandelen — brug percentiler, aldrig gennemsnit, for svartid.
  • Alle alarmer skal være handlingsrettede: symptom-baserede, forbundet med en runbook, dirigeret efter alvorlighedsgrad og understøttet af en fejlbudgetpolitik, der afgør, hvornår du skal levere, og hvornår du skal sætte ændringer på pause.

Hvis det gøres rigtigt, udløses dine tilkaldelser, før brugerne bemærker forringelsen — og forbliver stille, når alt fungerer.

Gratis at komme i gang

Lær Bootcamp i FastAPI-backendudvikling med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
21
Lektioner
84

Ofte stillede spørgsmål

Er lektionen “Alarmering på SLO'er og error budgets” gratis?

Ja — alle 3 lektioner i læringssporet Bootcamp i FastAPI-backendudvikling, inklusive “Alarmering på SLO'er og error budgets”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Bootcamp i FastAPI-backendudvikling-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Alarmering på SLO'er og error budgets”?

Definér servicemål, og forbind handlingsrettede alarmer, der udløses, før brugerne bemærker forringelsen. Du øver dig i Bootcamp i FastAPI-backendudvikling med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Bootcamp i FastAPI-backendudvikling?

Der kræves ingen tidligere erfaring. Bootcamp i FastAPI-backendudvikling på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Alarmering på SLO'er og error budgets”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Bootcamp i FastAPI-backendudvikling-lektion?

Ja. Alle Bootcamp i FastAPI-backendudvikling-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Struktureret JSON-logging og korrelations-id'er
  2. Distribueret tracing med OpenTelemetry
  3. Prometheus-metrics og RED/USE-dashboards
  4. Alarmering på SLO'er og error budgets
← Tilbage til Bootcamp i FastAPI-backendudvikling