Skip to content
Navigation

Type at least two characters. Search covers page titles, headings, tags and database names.

↑ ↓ to navigateEnter to openEsc to close0 pages
Monitoringintermediate

SLO and SLA

Defining service level objectives for a database, and using error budgets to decide when to stop shipping.

2 min readIntermediateUpdated Edit this page
  • SLI — a service level indicator: a measured quantity, such as the fraction of queries completing under 100 ms.
  • SLO — a service level objective: an internal target for that indicator.
  • SLA — a service level agreement: a contractual commitment with consequences, usually set well below the SLO so there is margin.

Indicators worth using

SLIDefinition
AvailabilitySuccessful connections and queries / total attempts
LatencyFraction of queries completing within a threshold
FreshnessFraction of reads served with staleness under a bound
DurabilityData loss events per period; and confirmed restorability
CorrectnessFailed integrity checks per period

Freshness deserves particular attention for databases with replicas — it is the SLI that captures what replica reads actually promise, and it is rarely defined.

Writing one

An SLO must be specific enough to be measured without argument:

99.9% of read queries against the orders service complete in under 50 ms,
measured at the application's database client, over a rolling 30-day window.

Every clause matters: which queries, what threshold, where measured, over what window. "The database is 99.9% available" is not measurable, because nobody has said what available means.

Error budgets

A 99.9% objective over 30 days permits about 43 minutes of failure. That is the error budget, and it is a decision-making tool:

  • Budget remaining — ship features, take calculated risks, run the migration.
  • Budget exhausted — stop feature work and spend the effort on reliability until it recovers.
# Fraction of the 30-day budget consumed, for a 99.9% objective.
(
  1 - (
    sum(rate(db_queries_success_total[30d]))
    / sum(rate(db_queries_total[30d]))
  )
) / (1 - 0.999)

The value of the budget is that it converts "should we do the risky migration this week" from an argument into a number.

Burn-rate alerting

Alert on how fast the budget is being consumed, not on individual failures:

# Fast burn: at this rate the 30-day budget is gone in about two days.
- alert: ErrorBudgetFastBurn
  expr: |
    (1 - (sum(rate(db_queries_success_total[1h])) / sum(rate(db_queries_total[1h])))) > 14.4 * 0.001
  for: 5m
  labels: { severity: page }
 
# Slow burn: sustained, lower-rate consumption. A ticket, not a page.
- alert: ErrorBudgetSlowBurn
  expr: |
    (1 - (sum(rate(db_queries_success_total[6h])) / sum(rate(db_queries_total[6h])))) > 6 * 0.001
  for: 30m
  labels: { severity: ticket }

This is how you get one page for a real degradation instead of dozens for individual errors.

SLA versus SLO

Set the SLA below the SLO — for example an SLO of 99.9% and an SLA of 99.5%. The gap is the room to detect and fix a degradation before it becomes a contractual matter. Committing externally to the same number you target internally leaves no margin for the ordinary.