Backend / Observability / 12_slo_sli_sla.md

SLO, SLI, SLA, and Error Budgets

Updated 6 interview angles 8 min read source
On this page8
  1. The four terms
  2. The mechanism: budget, burn rate, and two windows
  3. Latency SLOs
  4. Where it breaks in production
  5. The dashboard the SLO implies
  6. The trade not taken: paging on causes
  7. Related
  8. Interview angle

SLO, SLI, SLA, and Error Budgets

Article.

The Google SRE framework for turning “is the service healthy?” into a number that decides engineering work. The interview question under it: how do you turn reliability into a budget, and alert on that budget without paging on every blip or sleeping through a slow leak? The answer is burn-rate alerting over two windows, and the reason for the two windows is worth being able to show.

The four terms

Term What it is Audience
SLI a measured ratio: good events / all events engineering
SLO the target for an SLI over a window: 99.9% over 28 days engineering + product
SLA a contract with consequences: refunds, penalties legal, customers
Error budget (1 - SLO) × events: the failure you may spend engineering + product

The SLO is tighter than the SLA, so an internal incident spends budget before it breaches a contract. Promise 99.9% externally, run to 99.95% internally.

A good SLI

It is a ratio of user-visible outcomes, measured where the user experiences them:

  • Availability: successful requests / all requests.
  • Latency: requests faster than 300 ms / all requests.
  • Correctness: orders processed correctly / all orders.
  • Freshness: writes visible to readers within a minute / all writes.

CPU, memory, queue depth and pod counts are not SLIs. They are causes, useful on a dashboard, but no user experiences 85% CPU.

The nines

SLO Downtime per year Per 28-day window
99% 3.65 days 6.7 hours
99.5% 1.83 days 3.4 hours
99.9% 8.76 hours 40 minutes
99.95% 4.38 hours 20 minutes
99.99% 52 minutes 4 minutes
99.999% 5 minutes 24 seconds

At 99.999% the whole month’s budget is shorter than acknowledging a page. Start from what the service actually achieved over the last 90 days, and tighten only where users would notice the difference.

The mechanism: budget, burn rate, and two windows

The error budget is a quantity: at 99.9% over 28 days, 0.1% of requests, or about 40 minutes of total failure. Burn rate is how fast you are spending it, relative to spending it evenly:

text
burn_rate = observed_error_rate / (1 - SLO)

burn 1    -> the budget lasts exactly the window (28 days)
burn 14.4 -> 2% of a 30-day budget gone in one hour

An alert on burn rate pages on budget consumption, not on any particular error rate. Each rule uses two windows that must both exceed the threshold:

  • the long window (1 hour) says the problem is significant: enough budget spent to matter;
  • the short window (5 minutes) says it is still happening, so the alert stops soon after recovery.

The standard rule set from the SRE Workbook:

Windows Burn rate Action
1 h and 5 min ≥ 14.4 page
6 h and 30 min ≥ 6 page
3 d and 6 h ≥ 1 ticket

Three incidents, minute by minute

A simulation against a 99.9% SLO, comparing a static threshold (“error rate above 1% for 5 minutes”), a 1-hour burn rule alone, and the two-window rule:

text
A. 3-minute blip at 20% errors (starts 01:00): 1.5% of the 28-day budget spent
  static >1% for 5 min     never fires
  burn 1 h only            never fires
  burn 1 h + 5 min         never fires
B. 10-minute outage at 100% (01:00-01:10): 24.8% of the 28-day budget spent
  static >1% for 5 min     fires at 01:04, last firing at 01:09
  burn 1 h only            fires at 01:00, last firing at 02:08
  burn 1 h + 5 min         fires at 01:00, last firing at 01:13
C. 0.5% errors for 3 days: 53.6% of the 28-day budget spent
  static >1% for 5 min     never fires
  burn 1 h only            never fires
  burn 1 h + 5 min         never fires
  burn 3 d + 6 h (ticket)  fires at 14:24, last firing at 2d 23:59

Read it as three arguments:

  • A is a rolled-back deploy that cost 1.5% of the budget. Nothing pages, which is correct: nobody should be woken for it.
  • B is why the short window exists. The 1-hour rule alone keeps firing until 02:08, almost an hour after recovery, because the outage stays inside its window. With the 5-minute window it clears at 01:13.
  • C is why static thresholds fail. A 0.5% error rate never crosses “1%”, yet it spends more than half the month’s budget in three days. Only the slow-burn ticket sees it, 14 hours in.

As a Prometheus rule

yaml
# Prometheus: the fast-burn page, 99.9% SLO
- alert: CheckoutErrorBudgetFastBurn
  expr: |
    (sum(rate(http_requests_total{job="checkout",code=~"5.."}[1h]))
      / sum(rate(http_requests_total{job="checkout"}[1h]))) > 14.4 * 0.001
    and
    (sum(rate(http_requests_total{job="checkout",code=~"5.."}[5m]))
      / sum(rate(http_requests_total{job="checkout"}[5m]))) > 14.4 * 0.001
  labels: { severity: page }

Sloth or Pyrra generate the full rule set from a short SLO definition, which beats hand-writing four rules per SLO per service.

Latency SLOs

Latency is continuous, so it becomes a ratio of good events:

text
good_events  = requests completing in < 300 ms
total_events = all requests
SLO: 99% of requests in < 300 ms over 28 days

Count it from histogram buckets (le="0.3" over the total), not from a stored p99: percentiles cannot be averaged across instances or time, and a “p99 of p99s” is not the p99 of anything. For a multi-step user flow, put the SLO on the step the user waits for.

Where it breaks in production

  • The SLI is measured in the wrong place. The app reports 99.99% success while the load balancer returns 502s for requests that never reached it, and clients time out on others. Measure at the edge (load balancer, gateway) or from the client, not only inside the process.
  • Low traffic makes burn rates noisy. At 100 requests an hour one failure is a 1% error rate, a burn of 10 against 99.9%. Require a minimum event count in the rule, add synthetic traffic, or use longer windows for small services.
  • Static thresholds kept alongside. Two alerts for the same problem page twice, and the static one still sleeps through scenario C. Migrate fully.
  • No consequence for a spent budget. If an exhausted budget does not slow feature work, the SLO is a dashboard, not a policy. Agree the response (feature freeze, reliability work first) with product before the first breach.
  • Too many SLOs. Two to four per service. Twenty means none of them decides anything.

The dashboard the SLO implies

An alert says something broke; the dashboard has to answer what to look at, in what order. Build three:

Dashboard Answers Audience
Service health are users affected on call, first 30 s
Saturation what is running out on call, next 5 min
Deep dive why whoever investigates

The service-health board fits one screen: SLO burn rate first, then the RED metrics (rate, errors, duration), then the two or three saturation signals most likely to be the cause. Draw the SLO threshold on every graph, show p50 next to p99, and annotate deploys. Link the runbook from the dashboard and the dashboard from the alert (Incident response, runbooks and postmortems).

The trade not taken: paging on causes

The traditional pager watches causes: CPU above 80%, queue depth above 1,000, a pod restarting. Each is easy to set up and each pages without a user being affected, so the team learns to ignore pages, which is how the one that matters gets missed. Causes also miss failures nobody thought to threshold, such as a bad config that returns wrong answers at normal CPU.

Paging on symptoms (budget burn on user-visible SLIs) pages when users are affected and only then. The causes stay on the saturation dashboard, where they explain an incident instead of being one.

Interview angle 6

  • “SLI, SLO, SLA?” - the SLI is the measured ratio, the SLO the internal target over a window, the SLA the external contract. The SLO is tighter, so incidents spend budget before they breach a contract.
  • “What is a burn-rate alert?” - an alert on how fast the error budget is being spent: observed error rate over 1 - SLO. Burn 14.4 sustained for an hour spends 2% of a 30-day budget.
    • Follow-up: why two windows? The long window proves the burn is significant; the short one makes the alert clear soon after recovery. In a simulated 10-minute outage the 1-hour rule alone kept firing until 02:08, the two-window rule cleared at 01:13.
  • “What does a static ‘errors above 1%’ alert miss?” - slow leaks. A steady 0.5% never crosses it, yet spent 53.6% of a month’s budget in three days in the simulation; only the 3-day burn ticket caught it.
    • Follow-up: and a 3-minute spike to 20%? It cost 1.5% of the budget and no rule paged, which is the right outcome.
  • “How would you set the latency SLI?” - as a ratio of requests under a threshold, counted from histogram buckets, never by averaging stored percentiles.
  • “Why not page on high CPU?” - it pages without users affected and misses failures with normal CPU. Page on symptoms, keep causes on dashboards.
  • “Why is 99.999% expensive?” - 24 seconds a month. One slow deploy spends it, so it needs redundancy everywhere and automated rollback, at a cost that grows with each nine.