ReliabilitySLISLOSLAavailabilitydurability

Availability, SLOs and Error Budgets

An SLI is a measurement, an SLO is the target you set for it, an SLA is the contract with penalties; 99.9% availability is 8h 46m of downtime a year and 43 minutes a month, serial dependencies multiply their unavailability, and the error budget — the downtime you are allowed and have not yet spent — is the number that decides whether the next release ships.

▶ InteractiveInterview questionDebug it
Progress
What problem does this solve?

"Reliable" is not a requirement; without a measured indicator, a numeric target and a policy for what happens when the target is missed, reliability work is argued about instead of decided, and every outage is a surprise instead of a budget item.

SLI, SLO, SLA — and what "available" means

A Service Level Indicator is a measurement: the fraction of HTTP requests in the last 30 days that returned a non-5xx status within 500 ms. A Service Level Objective is the internal target for that SLI: 99.9%. A Service Level Agreement is a contract with a customer, with a looser number and financial consequences: 99.5%, with service credits below it. The SLO is stricter than the SLA so that you notice and act before the penalty clause does. The three terms are confused constantly; the fix is to remember that only the SLI is a *fact*, and the other two are *decisions* about it.

The properties themselves are distinct. Availability is the fraction of time — or, better, of requests — during which the service does what it should. Durability is the probability that stored data is not lost: S3 promises eleven nines of durability and four nines of availability, which is exactly right — a temporarily unreachable object is fine, a lost one is not. Reliability is the broad term: the service does the right thing, correctly, consistently. A search that returns instantly but wrong is available and unreliable. Define the SLI so that the failure your users actually care about counts — a login that returns 200 in 4 s is not "up" to the person waiting.

The nines, in minutes

Availability is almost always quoted as a percentage, and percentages hide the number that matters: how long you are allowed to be down. Each extra nine divides the allowance by ten. From 99.9% to 99.99% is the step from "one bad afternoon a year" to "52 minutes a year, in total, including every deploy that goes wrong" — and that step typically costs more than all the previous ones combined, because at four nines a human cannot be in the loop for recovery: 52 minutes is roughly one page, one diagnosis, one rollback. Five nines means nobody is ever in the loop; every failure must be detected and mitigated automatically in seconds.

Permitted downtime per period (365-day year, 30-day month)
AvailabilityPer yearPer monthPer dayWhat it implies operationally
99%3d 15h 36m7h 12m14m 24sBusiness hours on-call; a weekend outage fits
99.5%1d 19h 48m3h 36m7m 12sTypical SLA for a paid SaaS
99.9%8h 45m 36s (≈ 8h 46m)43m 12s1m 26sOn-call with pager; deploys are the main risk
99.95%4h 22m 48s21m 36s43sMulti-AZ; automated failover expected
99.99%52m 34s4m 19s8.6sNo human in the recovery loop; automatic rollback and failover
99.999%5m 15s26s0.86sMulti-region active-active; seconds-scale detection; almost never justified for one service

How downtime composes

Availabilities are probabilities, and they compose like probabilities. A request that must pass through a load balancer, a service, and a database in series succeeds only if all three do: 0.9999 × 0.999 × 0.999 ≈ 0.998, or 99.8% — worse than the weakest component, which is why a service cannot promise more nines than the dependency it cannot avoid. Ten dependencies at 99.9% each, all in series, give 0.999^10 ≈ 0.990: a 99% system built from 99.9% parts. This is the hidden cost of a synchronous call chain in Microservices and the reason Request/Response vs Event-Driven matters for availability, not just for latency.

Redundancy composes the other way. Two independent instances in parallel, either of which can serve the request, fail only if both do: 1 − (0.01 × 0.01) = 0.9999, so two 99% servers behind a load balancer give 99.99% — *if* their failures are independent, which shared power, a shared deploy, or a shared bad config make untrue. The pattern that actually delivers nines is therefore: remove serial dependencies from the critical path (cache, degrade, queue), and add independent parallel capacity to what remains.

Serial dependencies multiply; parallel redundancy divides
serial: 99.9% ceilingClientLB pair 99.99%Instance A 99.9%Instance B 99.9%Payment API 99.9%Primary DB 99.95%
ClientGateway / LBServiceWorkerDatabaseCacheQueue / LogObject storageCDNExternal system
The arithmetic for the diagram above
instances in parallel:   1 − (0.001 × 0.001)       = 0.999999
critical path in series: 0.9999 × 0.999999 × 0.9995 × 0.999
                       ≈ 0.9984                             → 99.84%, ≈ 14 h/yr
weakest serial link: the payment API at 99.9% — no amount of instance redundancy raises the ceiling above it

Error budgets as a release policy

An SLO of 99.9% over 30 days means you are *allowed* 43 minutes of failure. That allowance is the error budget, and treating it as a budget changes behaviour. While budget remains, the team ships: feature releases, risky migrations, chaos experiments — all are spending from a balance that exists to be spent. When the budget is exhausted, releases stop except for reliability fixes, until the 30-day window rolls enough failure out. The policy replaces the argument between "ship faster" and "be more careful" with a number both sides agreed to in advance.

Alerting follows from the budget too. Alert on burn rate: the multiple of the sustainable rate at which the budget is being consumed. At 99.9%, a burn rate of 14.4 over one hour means 2% of the monthly budget has gone in that hour — page someone. A burn rate of 1 over three days means the budget will be exactly spent by month end — open a ticket. Symptom-based alerting on the SLI ("users are seeing errors") replaces cause-based alerting ("CPU is at 90%"), because a cause without a symptom is not an incident and a symptom without a known cause still is.

  • Budget for 99.9% / 30 days: 43m 12s. Two bad deploys at 15 minutes each and one 20-minute database failover and the month is over.
  • Multi-window burn-rate alerts (1 h and 6 h, 6 h and 3 d) catch both fast outages and slow degradation without paging on noise.
  • The SLO must be achievable with the current architecture; a 99.99% SLO on a single-AZ deployment is a wish, and the budget will simply always be spent.

Measure from the user’s side

A server that reports 100% success while DNS is broken, the CDN is misconfigured, or the load balancer is routing to a dead pool is honestly reporting that every request *it received* succeeded. The SLI that matters is measured as close to the user as possible: synthetic probes from outside your network that exercise the real path (DNS → TLS → LB → app → DB) every minute from several regions; client-side telemetry that reports request outcomes from the browser or mobile app, including the ones that never reached you; and load-balancer logs as the server-side measurement of record, because they see the request before any service does. A request the user sent and you never saw is still a failed request from the SLI’s point of view.

Define the SLI over requests, not time: "99.9% of requests succeed" is more honest than "up 99.9% of the time", because a system that is up but returning errors for one region or one endpoint is partially down, and time-based availability rounds that to zero. The exercise in Logs, Metrics and Traces shows what the histograms behind a latency SLI look like.

Key points

  • SLI is the measurement, SLO the internal target, SLA the external contract; make the SLO stricter than the SLA so you act before the penalty.
  • 99% = 3d 15h 36m a year; 99.9% = 8h 46m; 99.99% = 52m 34s; 99.999% = 5m 15s. Each nine divides the allowance by ten and roughly multiplies the cost.
  • Serial dependencies multiply their availabilities; ten 99.9% dependencies in series are a 99% system. Parallel independent redundancy multiplies the failure probabilities instead.
  • The error budget is the unspent downtime; while it lasts you ship, when it is gone you fix. Alert on burn rate, on symptoms, not on causes.
  • Measure from the user’s side — probes, client telemetry, LB logs — and over requests, not time.

What 99.9% actually means

What 99.9% actually means
Pick a target and read the downtime it permits. Then compose components in series and in parallel, and spend an error budget.
Availability target
targetper yearper quarterper monthper weekper day
90%36d 12h 36m9d 3h 9m2d 23h 60m16h 48m2h 24m
99%3d 15h 40m21h 55m7h 12m1h 41m14m 24s
99.9%8h 46m2h 11m43m 12s10m 5s1m 26s
99.99%52m 36s13m 9s4m 19s1m 0s8.6s
99.999%5m 16s1m 19s25.9s6.0s0.9s
In series — availabilities multiply
LB 99.990 × app 99.950 × DB 99.900 = 99.840%
→ 14h 1m per year, worse than the weakest part
In parallel — 1 − (1 − a)ⁿ
1 − (1 − 0.9900)^2 = 99.9900%
→ 52m 36s per year — only if failures are independent
Error budget over 30 days
budget
43m 12s
burned
20m 0s
remaining
23m 12s
release policy
budget healthy: release normally
SLI  service level indicator  — the measurement: fraction of requests under 300 ms with a 2xx/3xx status, measured at the edge
SLO  service level objective  — the internal target on an SLI: 99.9% of requests over 30 days
SLA  service level agreement  — the contract with consequences: 99.9% or a 10% credit; always looser than the SLO
error budget = 1 − SLO, in minutes (or failed requests) per period; spend it on releases, lose it to incidents
The user experiences the product of every serial dependency: 99.99 × 99.95 × 99.90 is 99.840%, 14h 1m of downtime a year, and no component alone looks that bad. Redundancy helps only in parallel and only when failures are independent — two replicas on the same rack, same deploy, same bad config share their outages. Measure the SLI where the user is, not where the server is: a healthy `/health` endpoint behind a broken load balancer is 100% up and 0% useful.

How data moves through it

One request or event, hop by hop.

  1. 1Client → Synthetic probe / RUM: every user request (and every probe) records outcome and latency at the client or the LB.
  2. 2LB → Metrics pipeline: access logs streamed to a metrics store; success ratio and latency histograms computed per endpoint.
  3. 3Metrics → SLO evaluator: SLI over the 30-day window compared with the target; remaining error budget computed in minutes.
  4. 4SLO evaluator → Alerting: burn-rate rules on short and long windows; page on fast burn, ticket on slow burn.
  5. 5Error budget → Release pipeline: a policy gate that blocks feature deploys while the budget is negative.

When to use — and when not

Use it when
  • Any service with users who notice when it is down, as soon as there is a second engineer and a deploy cadence to argue about.
  • When choosing between architectures: the nines the product actually needs decide whether multi-AZ, multi-region or a single box is the right answer.
  • When negotiating an SLA: derive it from a measured SLI and an SLO you already meet, never the reverse.
Avoid it when
  • Setting an SLO you have no way to measure: an SLO without an SLI is a slogan.
  • Applying one availability number to every endpoint; checkout and the admin report deserve different SLOs and different on-call responses.
  • Chasing an extra nine that no customer asked for; the cost curve is exponential and the last nine is usually the one that reshapes the architecture.

Tradeoffs

Complexity
low → high
Ops cost
low → high
Latency
low → high
Consistency
weak → strong
Scalability
poor → strong

The concepts are cheap; each additional nine is roughly an order of magnitude more infrastructure, automation and on-call, which is why the target must be measured against need.

How it fails

  • Server-side 100% while users see failures: the SLI is measured behind the load balancer, so DNS, CDN and LB outages are invisible.
  • SLA stricter than what the architecture can deliver: a 99.99% contract on a single-AZ deployment pays credits every quarter.
  • Time-based availability hiding partial outages: one region erroring for an hour rounds to "up".
  • Alerts on causes not symptoms: paging on CPU at 90% while the real outage is a wrong config that no metric on the box reveals.
  • Error budget with no enforcement: the number is tracked, the releases continue, and the SLO becomes a dashboard nobody trusts.

How it scales

  • More services in the critical path lower availability multiplicatively; every new synchronous hop must justify its nines. Move consequences off the path with queues; see Request/Response vs Event-Driven.
  • From one instance to N behind an LB is the cheapest availability gain (parallel composition); from single-AZ to multi-AZ is the next; multi-region active-active is the last and by far the most expensive.
  • SLI pipelines must handle the request volume: compute availability from LB logs or sampled client telemetry, not by querying the production database.

How it interacts with databases, queues, caches, APIs and external systems

  • Load balancer and CDN: the server-side source of truth for request outcomes; their logs are the SLI, not the application’s self-report.
  • Databases: the durability SLO belongs to backups and replication (RPO/RTO), the availability SLO to failover time; see Replication and Read Scaling.
  • Queues: work moved off the synchronous path stops counting against the request SLI and gains its own freshness SLO (oldest message age).
  • External providers: their SLA is the ceiling of any path that calls them synchronously; wrap them with the patterns in Reliability Patterns or take them off the path.
  • Observability stack: histograms for latency SLIs, structured logs for post-hoc SLI recomputation, traces for finding which hop spent the budget; see Distributed Tracing.