Ein SLI ist eine Messung dessen, was Nutzer erlebt haben, ein SLO ist das Ziel, das du für diese Messung setzt, ein SLA ist ein Vertrag, der festlegt, was passiert, wenn das Ziel verfehlt wird, und das Error Budget ist die Differenz zwischen 100 Prozent und dem SLO, gezählt in fehlgeschlagenen Requests, die du dir leisten darfst. Ein SLO von 99,9 Prozent über 30 Tage auf einem Service mit 10 Millionen Requests ist ein Budget von 10.000 Fehlern. Mit diesen vier Zahlen beantwortet ein SRE die Frage, die der Rest der Organisation nicht beantworten kann: Wie zuverlässig soll dieser Service sein, und ist es heute sicher, auszuliefern?

Dies ist Teil 2 von Budget for Failure. Teil 1 hat die SRE-Rolle beschrieben und endete bei ihrer Abhängigkeit: Nichts davon funktioniert ohne eine Zahl. Dieser Teil ist noch 101-Level. Er definiert die Begriffe, liest die AWS-SLAs darauf, was sie tatsächlich versprechen, berechnet einen ersten SLI aus Load-Balancer-Metriken, die du bereits hast, und macht aus dem Ergebnis ein Budget mit angehängter Policy.

SLI: das Verhältnis von guten zu gültigen Events

Ein Service Level Indicator ist eine Zahl zwischen 0 und 100 Prozent, jedes Mal auf dieselbe Weise berechnet: gute Events geteilt durch gültige Events. Für einen Request-getriebenen Service sind die beiden nützlichsten SLIs:

  • Verfügbarkeit: Requests, die ohne Serverfehler beantwortet wurden, geteilt durch alle Requests.
  • Latenz: Requests, die schneller als ein Schwellenwert (sagen wir 300 ms) beantwortet wurden, geteilt durch alle Requests.

In dieser Definition verstecken sich zwei Designentscheidungen. Erstens, was als gültig zählt. Ein 404 für eine URL, die nicht existiert, ist der Service, der korrekt funktioniert; ein 429 von deinem eigenen Rate Limiter ist diskutabel; ein 500 ist es nicht. Entscheide es einmal und schreib es auf, denn der Nenner ist die Stelle, an der SLIs still und leise frisiert werden. Zweitens, wo du misst. Je näher am Nutzer, desto ehrlicher die Zahl. Eine Metrik am Load Balancer sieht Fehler, die die Anwendung nie loggt, etwa ein Target, das die Verbindung verweigert hat. Eine Metrik innerhalb der Anwendung übersieht sie.

Durchschnitte taugen nicht als SLI. Eine durchschnittliche Latenz von 120 ms ist damit vereinbar, dass jeder zwanzigste Request vier Sekunden dauert. Die Verhältnisform ("97,2 Prozent der Requests unter 300 ms") sagt dir, wie viele Nutzer eine schlechte Erfahrung hatten, und genau das willst du begrenzen.

SLO: das Ziel und das Zeitfenster, über das es gemessen wird

Ein Service Level Objective ist ein SLI plus ein Ziel plus ein Zeitfenster: "99,9 Prozent der Requests sind erfolgreich, gemessen über rollierende 30 Tage". Alle drei Teile sind Pflicht. Ein Ziel ohne Zeitfenster ist nicht falsifizierbar, denn jede schlechte Stunde lässt sich wegmitteln, indem man nachträglich einen längeren Zeitraum wählt.

Beim Ziel kommen die Neunen ins Spiel, und über die Neunen denkt es sich leichter als erlaubte Ausfallzeit nach. Für ein 30-Tage-Fenster (43.200 Minuten):

SLOErlaubte schlechte Zeit in 30 TagenErlaubte schlechte Requests pro 10 Millionen
99 %7 Stunden 12 Minuten100.000
99,5 %3 Stunden 36 Minuten50.000
99,9 %43 Minuten 12 Sekunden10.000
99,95 %21 Minuten 36 Sekunden5.000
99,99 %4 Minuten 19 Sekunden1.000
99,999 %26 Sekunden100

Lies die Tabelle von unten. Bei 99,99 Prozent hast du etwa vier Minuten im Monat. Ein Mensch, der um 03:00 Uhr gepaged wird, braucht länger, um überhaupt einen Laptop zu finden, was bedeutet: Ein Four-Nines-SLO ist ein Bekenntnis zu automatisierter Erkennung und automatisierter Wiederherstellung, mit Menschen erst danach. Jede zusätzliche Neun ist ungefähr eine Zehntelung des erlaubten Fehlers und in der Praxis ein großer Kostensprung. Das richtige SLO ist die niedrigste Zahl, oberhalb derer deine Nutzer den Unterschied nicht bemerken würden, nicht die höchste Zahl, die auf einer Folie gut aussieht.

Hundert Prozent sind nie das richtige Ziel. Sie verbieten jedes Deploy, jede Migration und jede Abhängigkeit, die du nicht kontrollierst, und deine Nutzer erreichen dich über Heim-WLAN und Mobilfunknetze, die weit unzuverlässiger sind als alles, was du betreibst.

SLA: der Vertrag, und was AWS dir tatsächlich schuldet

Ein Service Level Agreement ist ein SLO mit Konsequenzen, unterschrieben mit einem Kunden. Die Konsequenz ist meist Geld. Das ist der ganze Unterschied, und deshalb ist das SLA immer lockerer als das interne SLO: Du willst es bemerken und reagieren, lange bevor aus einem Verstoß eine Rückerstattung wird.

AWS ist das SLA, das die meisten von uns zuerst lesen, und es lohnt sich, es genau zu lesen, denn der Wortlaut lehrt das Konzept. Vier, die unter einem typischen Web-Service liegen:

Service und BedingungMonatliche Uptime-ZusageGutschrift bei Verfehlung
EC2, Instances über zwei oder mehr AZs (Region-Level)99,99 %10 %, 30 % unter 99,0 %, 100 % unter 95,0 %
EC2, eine einzelne Instance (Instance-Level)99,5 %10 %, 30 % unter 99,0 %, 100 % unter 95,0 %
Elastic Load Balancing, Load Balancer über zwei oder mehr AZs99,99 %10 %, 30 % unter 99,0 %, 100 % unter 95,0 %
RDS, Multi-AZ DB Instance oder Cluster99,95 %10 %, 25 % unter 99,0 %, 100 % unter 95,0 %
S3 Standard99,9 %10 %, 25 % unter 99,0 %, 100 % unter 95,0 %

Drei Dinge in diesen Dokumenten wiegen schwerer als die Prozentzahlen.

Die Abhilfe ist ein Service Credit. Fällt S3 Standard einen Monat lang auf 99,5 Prozent, hast du Anspruch auf 10 Prozent der S3-Kosten dieses Monats für die betroffene Region, verrechnet mit einer künftigen Rechnung, nachdem du einen Antrag mit Nachweisen gestellt hast. Dein entgangener Umsatz, deine eigenen SLA-Strafen und dein Wochenende sind nicht Teil der Rechnung. Ein SLA ist eine Preisbedingung. Es ist keine Versicherung und keine Vorhersage, wie sich der Service verhalten wird.

Die Zusage ist an deine Architektur gebunden. Die 99,99 Prozent für EC2 gelten nur, wenn alle laufenden Instances über zwei oder mehr Availability Zones in der Region verteilt sind. Läufst du in einer Zone, gilt für dich die Instance-Level-Zusage von 99,5 Prozent, die rund 3,6 Stunden Ausfall pro Monat erlaubt. Das SLA kodiert das Design, das AWS von dir erwartet.

"Unavailable" hat eine enge juristische Definition. Jedes SLA definiert seine eigene Messung, pro Minute oder pro Fünf-Minuten-Intervall, und seine eigenen Ausschlüsse. Langsam ist nicht unavailable. Erhöhte Fehlerraten in einer API, von der du abhängst, zählen möglicherweise gar nicht.

Dein erster SLI, aus Metriken, die du bereits hast

Wenn dein Service hinter einem Application Load Balancer sitzt, hält CloudWatch bereits einen Verfügbarkeits-SLI bereit. Drei Metriken im Namespace AWS/ApplicationELB reichen: RequestCount, HTTPCode_Target_5XX_Count (Fehler, die dein Code zurückgegeben hat) und HTTPCode_ELB_5XX_Count (Fehler, die der Load Balancer selbst erzeugt hat, etwa wenn kein gesundes Target geantwortet hat). Speichere das als sli.json:

[
  { "Id": "req", "ReturnData": false,
    "MetricStat": { "Stat": "Sum", "Period": 86400,
      "Metric": { "Namespace": "AWS/ApplicationELB", "MetricName": "RequestCount",
        "Dimensions": [{ "Name": "LoadBalancer", "Value": "app/checkout/0123456789abcdef" }] } } },
  { "Id": "t5xx", "ReturnData": false,
    "MetricStat": { "Stat": "Sum", "Period": 86400,
      "Metric": { "Namespace": "AWS/ApplicationELB", "MetricName": "HTTPCode_Target_5XX_Count",
        "Dimensions": [{ "Name": "LoadBalancer", "Value": "app/checkout/0123456789abcdef" }] } } },
  { "Id": "e5xx", "ReturnData": false,
    "MetricStat": { "Stat": "Sum", "Period": 86400,
      "Metric": { "Namespace": "AWS/ApplicationELB", "MetricName": "HTTPCode_ELB_5XX_Count",
        "Dimensions": [{ "Name": "LoadBalancer", "Value": "app/checkout/0123456789abcdef" }] } } },
  { "Id": "sli", "Label": "availability_percent",
    "Expression": "100 * (req - FILL(t5xx, 0) - FILL(e5xx, 0)) / req" }
]
aws cloudwatch get-metric-data \
  --start-time "$(date -u -v-30d +%Y-%m-%dT00:00:00Z)" \
  --end-time "$(date -u +%Y-%m-%dT00:00:00Z)" \
  --metric-data-queries file://sli.json \
  --query 'MetricDataResults[0].[Timestamps,Values]'

Das liefert eine Verfügbarkeitszahl pro Tag für die letzten 30 Tage (die date -v-Syntax ist macOS; unter Linux nimm date -u -d '30 days ago'). FILL(…, 0) ist wichtig: CloudWatch veröffentlicht für eine Fehlermetrik in einer Periode ohne Fehler keinen Datenpunkt, und ohne das Fill kommt ein perfekter Tag als fehlende Daten zurück statt als 100 Prozent.

Für Latenz hat derselbe Namespace TargetResponseTime, und die Percentile-Rank-Statistik von CloudWatch bringt sie direkt in die Verhältnisform: PR(:0.3) liefert den Prozentsatz der Requests, die in 300 ms oder weniger abgeschlossen wurden.

Das Error Budget: was das SLO dich ausgeben lässt

Sobald das Business sich darauf geeinigt hat, dass 99,9 Prozent gut genug sind, hören die verbleibenden 0,1 Prozent auf, ein zu beseitigender Defekt zu sein, und werden zu einem Kontingent, das genutzt werden darf. Steht der Service bei 99,97 Prozent und das Fenster hat noch zehn Tage, ist Raum für Risiko: die Migration ausliefern, den Cluster upgraden, den Failover-Test fahren. Steht er bei 99,88 Prozent, ist keiner da, und niemand muss eine Diskussion gewinnen, um das festzustellen. Ein Service, der jedes Fenster mit unangetastetem Budget beendet, ist auch kein Triumph: Entweder ist das SLO lockerer, als die Nutzer brauchen, oder das Team bezahlt für Zuverlässigkeit, die niemand verlangt hat.

Das Budget lässt sich in Events oder in Zeit zählen, und die beiden verhalten sich unterschiedlich.

SLO                      99.9% over 30 days
requests in window       10,000,000
error budget             (1 - 0.999) x 10,000,000 = 10,000 failed requests

bad requests so far      6,400
budget consumed          6,400 / 10,000 = 64%
budget remaining         3,600 requests = 36%

Event-basierte Budgets gewichten Fehler nach Traffic. Zehn Minuten Totalausfall zur Dienstagsspitze kosten weit mehr als zehn Minuten am Sonntag um 04:00 Uhr, was dem entspricht, was Nutzer erlebt haben. Das ist die Form, die für alles Request-getriebene vorzuziehen ist.

Zeitbasierte Budgets zählen schlechte Minuten: 99,9 Prozent über 30 Tage sind 43 Minuten und 12 Sekunden. Sie sind einem Nicht-Engineer leichter zu erklären und passen zu Services ohne stetigen Request-Strom, etwa einer Batch-Pipeline oder einem internen Tool mit wenig Traffic. Der Preis ist, dass eine Minute entweder ganz schlecht oder ganz gut zählt, du also eine Regel brauchst, was eine Minute schlecht macht (zum Beispiel "Fehlerrate über 1 Prozent"), und ein Teilausfall entweder unsichtbar ist oder voll zählt.

Das Fenster zählt so viel wie das Ziel. Ein rollierendes 30-Tage-Fenster spiegelt immer die jüngere Vergangenheit, und ein schlechter Tag verlässt die Rechnung genau 30 Tage später; es passt besser, um die Nutzererfahrung zu verfolgen. Ein Kalender-Fenster setzt sich am Ersten des Monats zurück, was zu Reporting und den meisten SLAs passt, und hat eine unangenehme Eigenschaft: Ein Incident am 2. verbraucht das Budget für vier Wochen, während derselbe Incident am 30. zwei Tage später vergeben ist.

Was das Budget verbraucht

Alles, was den Request eines Nutzers fehlschlagen lässt, zieht vom selben Konto ab, wer auch immer es verursacht hat. Das ist der Punkt. Ungefähr absteigend nach dem, was ein typisches Team ausgibt:

  • Änderungen. Deploys, Config-Pushes, Feature Flags, Schema-Migrationen. In den meisten Postmortem-Sammlungen ist Change die größte Einzelursache für Incidents. Wenn du die Change Failure Rate nach DORA verfolgst, misst du den Hauptverbraucher bereits.
  • Abhängigkeiten. Eine regionale API-Verlangsamung, ein Drittanbieter für Zahlungen, ein DNS-Problem. Es ist dein Budget, auch wenn es nicht deine Schuld ist, denn den Nutzer interessiert nicht, wessen Schuld es ist.
  • Kapazität und Last. Throttling, kalte Caches, eine Scaling Policy, die zwei Minuten zu spät reagiert.
  • Geplante Arbeit. Wartungsfenster, Failover-Tests, Game Days. Eine bewusste Zonen-Evakuierungsübung, die 300 fehlgeschlagene Requests kostet, ist gut angelegtes Budget, und ein Budget zu haben ist das, was die Übung genehmigungsfähig macht.
  • Hardware und Plattform. Instance Retirements, Zonen-Ereignisse. Kleiner, als man erwartet, wenn die Architektur Multi-AZ ist.

Führe ein Ledger. Notiere nach jedem Incident und jeder riskanten Änderung, wie viel Budget es gekostet hat und was die Ursache war. Drei Monate dieses Ledgers sagen dir besser als jede Roadmap-Diskussion, wohin Reliability-Engineering-Zeit fließen sollte.

DatumEreignisFehlgeschlagene RequestsAnteil am Budget
3. AugDeploy mit falscher Connection-Pool-Einstellung, nach 9 Minuten zurückgerollt3.10031 %
11. AugLatenz beim Zahlungsanbieter, Timeouts im Checkout2.20022 %
14. AugGeplanter RDS-Failover-Test3503,5 %
Gesamtes FensterHintergrundfehler, keine einzelne Ursache7507,5 %

In diesem Beispiel hat ein Deploy mehr gekostet als ein Drittanbieter-Ausfall und ein geplanter Test zusammen. Der Investment Case schreibt sich von selbst: Canary-Analyse und automatisches Rollback vor allem anderen.

Die Policy ist das Produkt

Ein Budget ohne Konsequenz ist ein Dashboard. Was es wirksam macht, ist eine kurze schriftliche Policy, vorab von Engineering- und Produktleitung vereinbart, die festlegt, was sich ändert, wenn das Budget knapp wird. Das Google SRE Workbook veröffentlicht eine Beispiel-Policy, deren Struktur sich zu kopieren lohnt. Eine brauchbare erste Version passt auf eine halbe Seite:

  • Budget über 50 Prozent: normaler Release-Prozess. Riskante Änderungen und Experimente sind erwünscht.
  • Budget unter 50 Prozent: Änderungen brauchen eine Canary-Stufe und ein getestetes Rollback. Keine Experimente in Produktion.
  • Budget aufgebraucht: Feature-Releases stoppen, bis der Service wieder innerhalb des SLO liegt. Nur Reliability-Fixes, Sicherheitspatches und Änderungen, die das Budget wiederherstellen, gehen raus. Die Priorität des Teams sind die obersten Punkte aus den jüngsten Postmortems.
  • Ein einzelner Incident verbraucht mehr als 20 Prozent des Budgets: Ein Postmortem ist Pflicht, mit mindestens einem hoch priorisierten Action Item.
  • Uneinigkeit: Eine namentlich benannte Führungskraft entscheidet. Der Eskalationspfad steht fest, bevor er gebraucht wird.

Zwei Eigenschaften sorgen dafür, dass das hält. Sie ist symmetrisch: Dasselbe Dokument, das Releases einfriert, wenn das Budget weg ist, sagt Operations, mit dem Blockieren aufzuhören, wenn es gesund ist. Und sie ist vorab vereinbart: Der Product Owner hat sie in einer ruhigen Woche unterschrieben, sodass ihr Einsatz in einer schlechten Woche Ausführung ist, nicht Konfrontation. Wenn die Führung keine Policy unterschreibt, die Feature-Arbeit stoppen kann, hast du noch kein SLO. Du hast eine Metrik.

Lass CloudWatch das Ledger führen

Der SLI oben wurde von Hand mit get-metric-data berechnet. Für das laufende Budget hat CloudWatch ein managed SLO-Feature innerhalb von Application Signals. Du definierst den Indikator, das Attainment-Ziel und das Intervall, und es verfolgt Zielerreichung und verbleibendes Error Budget fortlaufend. Drei Entscheidungen in seinem Modell bilden diesen Beitrag direkt ab:

  • Period-based oder request-based. Ein period-based SLO teilt das Intervall in Perioden (zum Beispiel eine Minute), bewertet jede als gut oder schlecht und meldet gute Perioden gegen alle Perioden. Ein request-based SLO zählt gute Requests gegen alle Requests. Das sind die oben beschriebenen zeit- und eventbasierten Budgets.
  • Rollierendes oder Kalender-Intervall. Beide werden unterstützt, mit dem bereits beschriebenen Trade-off.
  • Worauf der SLI aufbaut. Services, die mit Application Signals instrumentiert sind, bekommen Standardmetriken für Latenz und Verfügbarkeit, wobei 5xx-Antworten als Faults zählen und 4xx-Antworten als erfolgreich gelten. Bist du nicht instrumentiert, lässt sich ein SLO auf jede CloudWatch-Metrik oder jeden Metric-Math-Ausdruck setzen, der eine einzelne Zeitreihe ergibt, und dazu gehört der Load-Balancer-Ausdruck oben.

Die Console zeigt das Ergebnis als zwei Zahlen: Zielerreichung gegen das Ziel und verbleibendes Budget. Bei einem request-based SLO kann das verbleibende Budget während des Intervalls steigen wie fallen, denn es hängt vom bisherigen Verhältnis guter zu allen Requests ab, und eine ruhige Woche mit sauberem Traffic verdünnt einen früheren Incident.

Failure Modes und worauf zu achten ist

Prozentwerte mitteln. Ein Tag mit 100 Requests bei 90 Prozent und ein Tag mit einer Million Requests bei 99,99 Prozent ergeben im Schnitt nicht 95. Der 30-Tage-SLI ist alle guten Requests geteilt durch alle gültigen Requests. Summiere Zähler und Nenner, dann teile.

Ein Nenner mit Löchern. RequestCount zählt nur Requests, für die der Load Balancer ein Target wählen konnte, der Ausdruck oben überzeichnet den Schaden bei einem Totalausfall also leicht. Das ist die sichere Richtung, in die man falsch liegen kann. Der SLI sieht außerdem keine Requests, die den Load Balancer nie erreicht haben: ein DNS-Fehler, ein WAF-Block, ein Client in einem kaputten Netz.

Das SLO, dem niemand zugestimmt hat. Ein Ziel, das das Plattform-Team allein gewählt hat, hat keine Autorität, wenn es mit einem Launch-Termin kollidiert. Die Zahl muss demjenigen gehören, dem die Roadmap gehört.

Zu viele SLOs. Beginne mit ein oder zwei pro nutzerseitigem Service: Verfügbarkeit und Latenz auf dem Request-Pfad, der das Geld verdient. Zwanzig SLOs ergeben zwanzig Budgets, von denen immer eines aufgebraucht ist, und die Policy wird zu Rauschen.

Das Ziel setzen, bevor du die Daten gesehen hast. Lass die Abfrage zuerst über die letzten 30 Tage laufen. Ein SLO, das gewählt wurde, bevor du den SLI gesehen hast, ist ein Wunsch. Eines, das knapp unter der gemessenen Historie gesetzt und dann bewusst verschärft wird, ist ein Ziel, das du verteidigen kannst.

Es am Monatsende erfahren. Ein Budget, das in einem Monatsbericht abgelesen wird, kann nur die Vergangenheit erklären. Zu handeln, solange noch Budget da ist, braucht einen Alert auf die Verbrauchsrate, und den Service weniger verbrauchen zu lassen, braucht Änderungen in seinem Code. Beides ist Teil 3.

Lies das als Nächstes

Für Consulting zu AWS, Cloud-Architektur, SRE-Praxis, CI/CD-Pipelines, Linux und mehr, starte auf ercanermis.com.

Referenzen