Skip to content

SLO, SLI, SLA#

The SLO SLI SLA error budget framework is how SRE teams turn "is the site up" into a number you can argue about. SLI is the measurement, SLO is the target, SLA is the contract with consequences, and the error budget is the slack between perfect and the SLO that engineering is allowed to spend on risk.

flowchart LR
  SLI[SLI<br/>Service Level Indicator<br/>e.g. 99.95% of requests<br/>respond in less than 300ms]
  SLO[SLO<br/>Service Level Objective<br/>target: 99.9% over 28 days]
  SLA[SLA<br/>Service Level Agreement<br/>refund if below 99.5%]
  EB[Error Budget<br/>0.1% = 43 min / month]

  SLI --> SLO --> EB
  SLO --> SLA

  classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
  classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
  classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
  class SLI obs;
  class SLO,EB service;
  class SLA external;

A 99.9% SLO over a 30-day window equals an error budget of about 43 minutes of downtime per month. If you have burned 10 minutes already on a bad deploy, you have 33 left. If you have burned all 43, the policy says: freeze risky changes and shift the team to reliability work until the budget refills.

The point is not the numbers, it is the conversation. SLOs make reliability a shared currency between product (wants features) and SRE (wants stability). They turn vague debates into a budget that runs out.

Problem statement

Your CTO wants "five nines of availability" for the checkout service. Your team is shipping features and breaking things weekly. Define a sensible reliability target, an indicator to measure it, an alerting policy that does not page on every blip, and a policy for what happens when you exceed the budget.

Definitions in plain English#

SLI: Service Level Indicator. A measurement, expressed as a ratio of good events to total events. Examples: successful_requests / total_requests, requests_under_300ms / total_requests, bytes_correctly_served / bytes_attempted.

SLO: Service Level Objective. The target value for an SLI over a window. Example: "99.9% of HTTP requests succeed over a rolling 28-day window."

SLA: Service Level Agreement. A business contract with paying customers tied to an SLO, with financial penalties (refunds, credits) if breached. SLAs are typically set a few notches looser than internal SLOs so engineering has slack.

Error budget. 1 - SLO over the window. A 99.9% SLO buys you 0.1% of "allowed unreliability."

flowchart LR
  USER[User journey]
  SLI[SLI: good / total]
  SLO[SLO: target ratio over window]
  EB[Error budget = 1 - SLO]
  ALERT[Burn-rate alert]
  POLICY[Policy:<br/>freeze on burn]
  SLA[SLA<br/>customer-facing]

  USER --> SLI --> SLO --> EB --> ALERT --> POLICY
  SLO --> SLA

  classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
  classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
  classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
  classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
  class USER client;
  class SLI,ALERT obs;
  class SLO,EB,POLICY service;
  class SLA external;

Choosing a good SLI#

A good SLI is user-centric, proportional, and cheap to compute. The standard Google template is:

The proportion of <event> that were <good>, measured at <observer>.

Examples:

  • Availability: proportion of HTTP requests that did not return 5xx, measured at the load balancer.
  • Latency: proportion of requests served under 300 ms, measured at the load balancer.
  • Quality: proportion of recommendations served from the personalised model versus the static fallback.
  • Freshness: proportion of cached pages newer than 60 s.
  • Correctness: proportion of pipeline runs where output row count matches input row count.

Avoid: CPU%, memory%, queue depth. These are causes, not symptoms. Users do not care about your CPU.

Translating availability to time#

Quick lookup table for a 30-day window:

SLO Allowed downtime / 30 days Allowed / week Allowed / day
99% 7h 18m 1h 41m 14m 24s
99.5% 3h 39m 50m 7m 12s
99.9% 43m 49s 10m 4s 1m 26s
99.95% 21m 54s 5m 2s 43s
99.99% 4m 22s 1m 8s
99.999% 26s 6s 0.8s

Five nines is roughly 26 seconds per month. Almost no team ships 26 seconds of allowed downtime per month while also shipping features. Pick the loosest SLO your users will tolerate.

Error budget policy#

The whole point of an SLO is the policy that triggers when the budget is exhausted.

flowchart TB
  D[Deploy]
  M[Measure SLI]
  B{Budget remaining?}
  S[Ship features]
  F[Feature freeze<br/>reliability work only]
  L[Loosen SLO?<br/>only with PM agreement]

  D --> M --> B
  B -- yes --> S --> D
  B -- no --> F
  F --> M
  F -. quarterly review .-> L

  classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
  classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
  class D,M,S,F,L service;
  class B obs;

A typical policy:

  1. Budget above 50%: ship freely, take risks.
  2. Budget 10 to 50%: ship, but with extra review for risky changes.
  3. Budget below 10%: only safe changes (config-only, dependency bumps).
  4. Budget exhausted: feature freeze until next window or until reliability work refills it.

Burn-rate alerting#

Page on how fast you are burning the budget, not on raw error count. A 0.1% error rate during a freak hour might be fine; the same rate sustained burns the month in days.

Multi-window, multi-burn-rate alerts (Google SRE Workbook ch. 5):

Burn rate Long window Short window Action
14.4x 1 hour 5 minutes Page now (2% of budget in 1h)
6x 6 hours 30 minutes Page (5% in 6h)
3x 24 hours 2 hours Ticket (10% in 24h)
1x 3 days 6 hours Trend, no page

The dual window prevents short flapping from paging while still catching real burns fast.

Code: computing budget remaining#

from datetime import timedelta

def budget_remaining(slo: float, good: int, total: int) -> float:
    """Return fraction of error budget left in [0..1]."""
    if total == 0:
        return 1.0
    failure_ratio = 1 - (good / total)
    allowed_failure_ratio = 1 - slo
    used = failure_ratio / allowed_failure_ratio
    return max(0.0, 1.0 - used)

def burn_rate(slo: float, good: int, total: int) -> float:
    """Burn rate: 1.0 == on track to burn exactly the budget."""
    if total == 0:
        return 0.0
    failure_ratio = 1 - (good / total)
    allowed = 1 - slo
    return failure_ratio / allowed if allowed else 0.0

# 99.9% SLO, last hour: 9990 good of 10000
print(budget_remaining(0.999, 9990, 10000))  # 0.0  -> burned all hourly budget
print(burn_rate(0.999, 9990, 10000))         # 1.0  -> burning exactly at rate

SLA vs SLO: keep them separated#

  • SLA is what you promise externally; lawyers care about it; refunds tied to it.
  • SLO is what you operate to internally; set tighter than SLA.
  • Rule of thumb: SLO is at least one nine tighter than SLA. If SLA is 99.5%, SLO is 99.9%. This buffer absorbs measurement error and prevents you from waking up the lawyers every time a router blips.

Gotchas#

  • Aggregating SLIs hides outages. A 99.9% global SLI can mask one region being totally down. Split by region, by endpoint, by tenant.
  • Bad SLI denominators. If you count health-check probes in "total requests", you can paper over real user failures.
  • Static thresholds drift. A "less than 300 ms" SLI that was fine when you had 1M users is meaningless at 100M with new use cases. Review quarterly.
  • No policy = no SLO. A target with no consequence on breach is a vanity metric. Get product + engineering buy-in on what happens when it goes red.
  • Five-nines theater. Most internal services do not need 99.99%. Your dependency chain compounds: 4 services at 99.99% each = 99.96% combined.
  • Ignoring user journeys. A 99.9% availability per microservice can still produce 95% checkout success. Define SLOs on the user-visible flow.

Quick reference#

Definitions#

  • SLI: a ratio, good events over total. User-centric, not infra.
  • SLO: target value for an SLI over a window (28 or 30 days typical).
  • SLA: external contract with refunds on breach; set looser than SLO.
  • Error budget: 1 - SLO. Slack the team gets to spend on risk.

Nines to time (30-day window)#

SLO Allowed downtime
99% 7h 18m
99.5% 3h 39m
99.9% 43m
99.95% 22m
99.99% 4m 22s
99.999% 26s

SLI template#

Proportion of <event> that were <good>, measured at <observer>.

Canonical examples: - HTTP availability: 2xx-3xx-4xx / all responses, measured at the LB. - Latency: requests under threshold / total. - Freshness: cached entries less than X seconds old / total served. - Correctness: rows out matches rows in.

Burn-rate alerts (multi-window)#

Burn rate Long win Short win Severity
14.4x 1h 5m Page now
6x 6h 30m Page
3x 24h 2h Ticket
1x 3d 6h Trend only

Burn = (1 - SLI) / (1 - SLO). 1.0 means on pace to burn exactly the budget.

Error-budget policy ladder#

  • 100 to 50% left: ship freely.
  • 50 to 10%: extra review on risky changes.
  • 10 to 0%: safe changes only.
  • 0%: feature freeze, reliability work only.

Common mistakes#

  • SLI on CPU/memory instead of user-visible signals.
  • Counting health checks in the SLI denominator.
  • One global SLO hiding per-region or per-tenant outages.
  • SLA tighter than SLO (no buffer).
  • No policy on burn -> the SLO is decoration.
  • Chaining 4 services at 99.99% and promising 99.99% end-to-end.

Interview probes#

  • Q: "Difference between SLO and SLA?" A: SLO internal target, SLA external contract with penalty.
  • Q: "What is an error budget for?" A: Negotiating between velocity and reliability; ties to a freeze policy.
  • Q: "Why burn-rate alerts over threshold alerts?" A: They catch sustained problems early and ignore flaps.
  • Q: "Why not always aim for five nines?" A: Cost compounds; dependency chain dilutes; users do not need it.

Refs#

  • Beyer, Jones, Petoff, Murphy, Site Reliability Engineering (Google, 2016) - ch. 4 SLOs.
  • Beyer et al., The Site Reliability Workbook (2018) - ch. 5 alerting on SLOs.
  • Liz Fong-Jones and Seth Vargo, Implementing SLOs (Google Cloud blog, 2020).
  • Alex Hidalgo, Implementing Service Level Objectives (O'Reilly, 2020).

FAQ#

What is the difference between SLI, SLO, and SLA?#

An SLI is the measurement, like the percent of requests under 300 ms. An SLO is the target you commit to internally. An SLA is the external contract with refunds or penalties if breached.

What is an error budget?#

The acceptable amount of unreliability between perfect and the SLO. If your SLO is 99.9 percent, you have 0.1 percent of unreliability to spend on risky changes or incidents per window.

How do I pick good SLIs?#

Choose user-visible signals like request success rate or latency p95 on critical paths. Avoid internal metrics that do not directly reflect user happiness, like CPU utilization.

What is burn rate alerting?#

An alerting strategy that fires when the error budget is being consumed faster than the rate that would exhaust it over the SLO window, catching outages early without paging on tiny blips.

Should every service have an SLA?#

No. Internal services usually only need SLOs. SLAs are for external customers where contractual commitments and credits make sense and require careful margin between SLA and SLO.

  • Observability: metrics, logs, and traces are the raw signals from which SLIs are computed.
  • Chaos Engineering: proves that SLOs hold under realistic failure injection rather than just on a calm day.
  • Capacity Planning: forecast headroom needed so the SLO does not silently degrade as load grows.