Choosing indicators users can feel, budget-driven release decisions, and alerting on symptoms instead of causes so the pager means something.
Module O-2 — SLIs, SLOs, and Error Budgets
What this module covers: Why 100% is the wrong target, and why without a stated one every argument about reliability versus features is a contest of opinions. SLI, SLO and SLA as three different things, with the SLA deliberately looser than the SLO. Choosing indicators users can feel, using the good-events-over-valid-events formulation — including latency expressed as a proportion rather than a percentile, which composes where a percentile does not. Where to measure, and why the load balancer beats the server. Setting a target from measurement rather than aspiration, and the dependency ceiling that caps what you can promise. The error budget as permission to take risk rather than an allowance for failure, and why an unused budget is also a signal. Then the technical heart: multi-window burn-rate alerting, which fixes both failure modes of threshold alerts — noisy blips and slow burns that never cross the line. Symptom-based paging. SLOs for pipelines, queues and non-request systems, which most treatments skip. And the composition argument that turns graceful degradation into an SLO strategy.
100% Is the Wrong Target, and No Target Is Worse
Two claims that sound contradictory and are not.
A 100% reliability target is wrong. It is unachievable — the user's own network, device, DNS resolver and ISP are less reliable than any number you can engineer — and the marginal cost of each additional nine is roughly an order of magnitude, with no ceiling. A team pursuing 100% will spend without limit on improvements no user can perceive, and will still miss.
Having no target is worse. Without one, every conversation about whether to ship a feature or harden a system is a contest between an engineer who feels it is fragile and a product manager who feels the feature matters. Nobody can be shown to be right, so the outcome is decided by whoever is more insistent, and it changes every quarter.
An SLO converts that argument into arithmetic. It states, in advance and by agreement, how unreliable the service is permitted to be — and therefore how much risk you may take, and when you must stop taking it.
Analogy: a train operator's punctuality target. "Every train on time" is not a plan; a single leaf-fall or a passenger illness breaks it, so the target is meaningless and nobody manages against it. "94% of trains within five minutes, measured monthly" is manageable: it tells you which delays matter, it gives you a stock of permissible lateness to spend on engineering works, and when you have spent it you stop scheduling engineering works. Notice the shape — the target is not the aspiration, it is the number that decides what you are allowed to do this month.
SLI, SLO, SLA
| What it is | Consequence of breach | |
|---|---|---|
| SLI | a measurement of behaviour, as a ratio | none — it is a number |
| SLO | an internal target for the SLI over a window | an engineering decision |
| SLA | a contract with a customer | money (credits, penalties) |
Two rules follow. The SLA must be looser than the SLO, with real margin — if you promise customers 99.9% and target 99.9% internally, then any miss is a contractual event, so you have no room to learn. Target 99.95% internally and promise 99.9%.
And the SLO drives behaviour; the SLA drives contracts. Breaching an SLO triggers a change in how the team works. Breaching an SLA triggers finance and legal. Conflating them makes reliability a compliance activity, which is the fastest route to teams gaming the measurement.
Choosing SLIs: Good Events Over Valid Events
An SLI must reflect what a user experiences. CPU < 80% is not an SLI; it is a cause. Nobody has ever filed a complaint about CPU.
The formulation that makes SLIs tractable:
SLI = good events / valid events → a ratio in [0, 1], comparable and composable
Two definitional decisions carry real weight:
"Good" must be specific. Not "the request succeeded" but "returned a non-5xx status within 300 ms." Bundling latency into the definition of good is what makes a single SLI meaningful.
"Valid" is where honesty is tested. Excluding requests that are not your fault is legitimate — a 400 from a malformed client request is not a reliability failure. Excluding things because they are inconvenient is self-deception, and the recognisable examples are: excluding 429s from your own limiter (you are rate limiting because you are overloaded, so those are failures), excluding traffic from a region you would rather not count, and excluding a customer whose usage pattern is unflattering. The rule: decide the exclusions before the incident, write them down, and never redefine them retroactively to save an SLO.
Five categories, and the latency formulation that composes
| Category | SLI | Example |
|---|---|---|
| Availability | successful / valid requests | 99.95% of checkout requests return non-5xx |
| Latency | proportion served within a threshold | 99% of feed loads complete within 300 ms |
| Quality | proportion served non-degraded | 99.5% of pages served with full personalisation |
| Freshness | proportion of data younger than X | 99% of warehouse rows within 15 minutes of source |
| Correctness | proportion processed correctly | 99.999% of ledger entries reconcile |
The latency row deserves emphasis. State latency as a proportion within a threshold, not as a percentile target. "99% of requests under 300 ms" and "p99 < 300 ms" sound identical and behave differently:
- A proportion is a ratio of good to valid, so it aggregates across instances, regions and time windows by simple addition — whereas percentiles cannot be averaged at all (Module O-1).
- A proportion converts directly into an error budget: 1% of requests may exceed 300 ms.
- Multiple thresholds compose ("99% under 300 ms and 99.9% under 2 s"), which captures both typical experience and the intolerable tail.
The quality row is the one most teams do not have, and it is the direct consequence of Module A-7: once you build graceful degradation, your error rate stops reflecting whether the product works. A quality SLI on the degraded-serve rate is what makes a three-week-old open breaker visible.
Where to measure
| Point | Sees | Misses |
|---|---|---|
| Client (RUM) | the truth, including their network and rendering | hard to instrument, sampled, noisy |
| Load balancer | queueing, TLS, retries, all instances | the client's own network |
| Server handler | your code's time | queueing, load-balancer time, connection setup |
| Synthetic probes | availability from chosen locations | real traffic mix and real user conditions |
The load balancer is the right default — it is cheap, complete on your side of the wire, and includes the queueing that a server-side handler timer excludes. Supplement with real-user monitoring for the honest number and synthetic probes originating per region, because a global average hides a dead region (Module A-9).
And keep the number of SLOs small. A handful per service, on the critical user journeys — sign in, search, checkout, feed load. An SLO per endpoint is unmanageable, un-negotiable, and produces alert volume nobody can act on.
Setting the Target: Measure First, and Respect the Ceiling
Do not pick a number by aspiration. Measure the current level, ask whether users are complaining, and set the target at or slightly above what you already deliver if they are not. Then examine the cost:
| SLO | Permitted badness per 30 days | Reality |
|---|---|---|
| 99% | 7.2 hours | noticeable; fine for internal tools |
| 99.9% | 43 minutes | the common default for most products |
| 99.95% | 22 minutes | requires deliberate engineering |
| 99.99% | 4.3 minutes | multi-region, automated failover, no manual steps in the recovery path |
| 99.999% | 26 seconds | almost nobody needs this; a deploy costs you a chunk of it |
Two things to weigh. Each nine costs roughly ten times the previous one, so the question is never "would more reliability be nice" but "is this nine worth ten times the last one to the people paying." And beyond about 99.99%, the user cannot perceive the difference, because their own connection is less reliable than your service — you are improving a number nobody experiences.
Sign in to keep reading
The rest of this module is free — sign in with Google to unlock it and track your progress.
Sign in & RegisterDiscussion
0Join the discussion