Stage 6 · Operate
SLOs & Error Budgets
Defining SLIs
Latency, availability, quality, and throughput — choosing the right indicators for your services.
What Are SLIs?
Service Level Indicators are quantitative measures of service behavior from the user's perspective. They answer one question: how well is the service performing for actual users? SLIs are not infrastructure metrics — they are user-centric measurements.
A well-chosen SLI captures something your users care about. Response time for a web page, error rate for an API, or data freshness for a streaming pipeline. If users would notice a degradation in the SLI, it is the right indicator.
Not all metrics are SLIs. CPU utilization, memory usage, and disk I/O are infrastructure metrics. They help with debugging but do not directly measure user experience. An SLI must map to a user-visible behavior.
Latency SLI
Latency measures how long it takes to serve a successful request. It is the most common SLI for web services. The key is to measure at the user-facing endpoint and only for successful responses — errors should be counted separately under availability.
# Record successful requests with their duration
- record: sli:http_request_duration_seconds:success
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{
code!~"5..",
handler="/api/users"
}[5m])) by (le)
)Always use percentiles, not averages. The 99th percentile captures tail latency — the experience of your unluckiest 1% of users. Averaging hides slow requests behind a sea of fast ones.
Availability SLI
Availability measures the proportion of requests that succeed. A request is successful if it returns the expected response within the latency SLI threshold. Availability is not uptime — a service can be up but returning errors.
# Availability = successful requests / total requests
- record: sli:http_availability:ratio
expr: |
sum(rate(http_request_duration_seconds_count{
code!~"5..",
handler="/api/users"
}[5m]))
/
sum(rate(http_request_duration_seconds_count{
handler="/api/users"
}[5m]))A 404 from a user typo is not a service failure. Define availability as non-5xx responses. Only count server-side errors — 5xx codes, timeouts, and connection resets — as availability violations.
Quality SLI
Quality measures correctness of responses. Does the search result actually match the query? Does the recommendation engine return relevant suggestions? Quality SLIs require domain-specific definitions.
# Quality = queries returning non-empty results
- record: sli:search_quality:ratio
expr: |
sum(rate(search_queries_total{
results_count>0
}[5m]))
/
sum(rate(search_queries_total[5m]))Throughput SLI
Throughput measures the rate at which the service successfully processes requests. It is critical for batch processing, data pipelines, and streaming systems where volume matters more than individual request latency.
# Events processed per second
- record: sli:pipeline_throughput:rate
expr: |
sum(rate(events_processed_total[5m]))Choosing the Right SLIs
- Identify user journeys — what paths do users take through your service?
- Select 2-3 SLIs per service — latency, availability, and quality cover most cases.
- Measure from the user's perspective — instrument at the edge, not inside the service.
- Keep SLIs simple — if an SLI is too complex to understand, it is too complex to act on.
- Align SLIs with business value — the SLI should reflect something the business cares about.
If you are unsure where to begin, start with latency (p99) and availability (non-5xx rate). These two SLIs capture most user-facing issues and are straightforward to implement.
SLIs in Prometheus
The standard pattern for SLI implementation in Prometheus is a recording rule that produces a ratio. The numerator is good events, the denominator is total events. This ratio feeds directly into SLO calculations.
groups:
- name: sli_recording_rules
interval: 30s
rules:
# Latency SLI - p99 for successful requests
- record: sli:http_latency_seconds:p99
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{
code!~"5.."
}[5m])) by (le)
)
# Availability SLI - ratio of non-5xx requests
- record: sli:http_availability:ratio
expr: |
sum(rate(http_request_duration_seconds_count{
code!~"5.."
}[5m]))
/
clamp_min(sum(rate(http_request_duration_seconds_count[5m])), 1)
# Quality SLI - success rate for downstream calls
- record: sli:downstream_success:ratio
expr: |
sum(rate(downstream_call_total{
code="200"
}[5m]))
/
clamp_min(sum(rate(downstream_call_total[5m])), 1)When there is zero traffic, the denominator is zero. clamp_min(total, 1) prevents a division-by-zero error that would produce NaN. During zero traffic, the SLI defaults to 1.0 (no violations), which is correct — no traffic means no user impact.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.