lumo

Module 13 · Lesson 3 of 15Free

SLOs and error budgets: defining reliability targets

Level
Intermediate
Topic
Observability, incidents and safe deployments
Reading time
18 min

When you finish this page you can

  1. Define a reliability target using an explicit population, good outcome, measurement point and window.
  2. Calculate an error budget and distinguish request-based targets from time-based targets.
  3. Explain how missing measurements, retries and traffic mix can distort reliability reports.
  4. Use budget consumption to choose between feature work and reliability improvements.
  1. RED and USE methods: choosing what to measure18 min

Video lesson · coming soon

reports 99.95% successful API requests during a festival sale. Yet checkout is failing for one customer in ten. Product-page traffic is hiding the failures that stop people buying.

Should the team continue releasing features, or stop and repair checkout? This lesson answers one question: how do you turn customer expectations into a measurable reliability target and a rule for acting on failures?

The scenario uses Kartly’s many-services stage. All targets and measurements below are illustrative, not production statistics.

Count the outcome customers need

A site-wide success percentage treats every request as equally important. That is convenient to calculate, but it answers the wrong question here.

Suppose successful catalog reads dominate Kartly’s traffic. Adding more catalog traffic improves the reported percentage without fixing a single checkout.

Check yourselfAnswer in your head first, then reveal
Kartly adds a million successful product-page requests. Checkout behavior stays unchanged. Has checkout become more reliable?Show answerHide answer
No. The site-wide percentage improves because its denominator grew. A checkout target must count checkout outcomes separately.

Diagram not drawn yet: slo-checkout-population.svg

Catalog requests and checkout requests enter separate counting groups. Checkout requests split into good responses and bad responses. Only checkout good and bad counts enter the checkout reliability calculation; catalog requests do not.

Choose the population before calculating its success percentage. Unrelated traffic must not hide checkout failures.

A service level indicator, or , is the measurement. For this lesson, it is the fraction of eligible checkout requests with a good outcome.

A service level objective, or , sets the target for that measurement over a defined window. Expressing an SLI as good events divided by total events makes its relationship to an explicit.1

You already selected useful service signals in RED and USE methods. Now you must decide which signal represents an experience worth protecting.

Start with one customer task, not every metric on the dashboard. CPU helps explain failures; it does not tell you whether someone could place an order.

The next difficulty is deciding what “good” actually means.

Define good before choosing a percentage

Kartly’s first proposal is “checkout returns 200.” That rule would count a fast response containing an application error as success.

Instead, the team defines a good response as an expected checkout result delivered within two seconds. An expected result includes a confirmed order or an explicit business rejection, such as insufficient stock.

A payment is not an expected rejection. The customer still does not know whether the purchase worked.

This boundary also has limits. It measures the checkout API, not the whole phone experience. A slow screen or a failed connection before Kartly’s edge remains outside this measurement.

Server-side observations can miss requests that never reach the server. Client measurements and external probes expose different parts of that gap.1

Where should Kartly measure checkout reliability first?

Count only inside the checkout service.

The counter is easy to add, but an application instance cannot count requests rejected before they reach it. A healthy-looking application can sit behind a failing gateway.

Measure the entire task on the customer’s device.

The measurement includes more of the customer experience, but a failed phone may also fail to report its result. Reporting coverage becomes another system to operate.

Why this choice

Kartly chooses the edge for its initial API objective because it sees failures across the internal . The edge receives a bounded outcome classification from checkout; it does not infer business success from a status code alone.

The team also runs an external checkout probe as a separate warning signal. It does not mix synthetic probe requests into the customer-request denominator.

The choice changes when client reporting is dependable enough to support a journey-level objective. Until then, the dashboard must say “checkout API,” not “customers can always buy.”

Write the measurement contract before implementing the counters:

Field Kartly’s rule for this lesson
Population Authenticated, valid checkout submissions accepted at the edge
Good outcome Expected checkout result delivered within two seconds
Bad outcome Unexpected error, dependency failure, timeout or response after the deadline
Exclusions Malformed requests, unauthenticated requests and identified test traffic
Measurement point Kartly’s edge, with a checkout outcome classification
Window Trailing 30 days, recomputed hourly
Initial target At least 99.9% good

Eligibility must not depend on whether the service succeeded. Otherwise, a failure could remove itself from the denominator.

An eligible request rejected during overload counts as bad. Planned maintenance also counts under this contract: customers still cannot buy.

This contract makes the percentage meaningful. It does not yet explain whether the proposed target is worth its cost.

A target creates a failure allowance

For a good-event ratio, the error budget is the failure allowance implied by the target. It is not a separate reliability target.1

Kartly proposes 99.9% good checkout API outcomes. That leaves 0.1% for outcomes outside the contract.

For one illustrative trailing window:

Calculate the allowance

30,000,000 requests × 0.001 = 30,000 bad requests

This is a request allowance, not a number of minutes.

Measure actual consumption

24,000 bad ÷ 30,000 allowed = 80% consumed

The observed good-event ratio is 99.92%, which meets the proposed target.

Calculate the remaining margin

30,000 allowed − 24,000 observed = 6,000 bad requests remaining

The team has limited room for another incident within this measured window.

A request-based budget changes as the window’s total traffic changes. It is not a fixed allocation issued at the start of a month.2

Moving from 99.9% to 99.99% would reduce this window’s allowance to 3,000 bad requests. Kartly’s observed failures would exceed it substantially.

That tighter target might justify expensive improvements. It does not create them.

Should Kartly adopt 99.9% or immediately require 99.99%?

Require 99.99% immediately.

The allowance becomes ten times smaller. Unless engineering work reduces failures, the service begins outside its target and normal releases may remain blocked.

Why this choice

For this scenario, product accepts 99.9% as an initial API target, not as proof that every customer is satisfied. The team will compare failures with support reports, failed purchases and affected customer groups.

Current performance tests feasibility; it does not decide what customers deserve. If this target permits unacceptable harm, Kartly needs a funded reliability plan and a tighter objective.

Conversely, if extra reliability would not improve the product enough to justify its cost, a stricter percentage is not automatically better.

Keep correctness requirements separate. A duplicate charge is not an acceptable purchase from a general failure allowance. Investigate it even when the API SLO is met.

The budget guides risk-taking. It does not authorize every kind of failure.

Requests are not minutes

“99.9% means about 43 minutes of downtime a month” is only appropriate for a matching time-based definition and month length.

For an illustrative 30-day time-based objective, the arithmetic is:

Calculate a time allowance

30 days × 24 hours/day × 60 minutes/hour × 0.001 = 43.2 minutes

This calculation budgets time. Kartly’s chosen objective budgets requests instead.

A quiet-hour outage and a sale-hour outage can last equally long but affect different numbers of purchases.

A request-based SLO counts good requests divided by total requests. A period-based SLO counts good periods divided by total periods, using a rule that decides whether each period was good.2

Neither is universally correct. A continuously available connection may need a time-oriented measure. Kartly chooses requests because each failed checkout submission represents a purchase interrupted.

Do not accidentally create a third calculation by averaging minute-level success percentages.

Suppose one minute contains 100 requests, all good. Another contains 9,900 requests, with 99 bad.

The combined result is 9,901 good requests out of 10,000: 99.01%. Averaging the minute percentages gives 99.5%, because it gives the quiet minute equal weight.

Sum good counts and total counts across instances and time. Divide only after aggregation.

The same rule applies across services. A healthy catalog must not outweigh broken checkout merely because it serves more requests.

Even correctly weighted counts need a trustworthy collection path.

Make the measurement reproducible

Kartly implements the contract with fixed-size time buckets. Each bucket stores eligible and good counts for a specific checkout-contract version.

The collection path builds on logs, metrics and traces; this lesson only specifies what the SLO calculation needs.

  1. The edge decides eligibility when accepting a checkout request.
  2. It starts a timer and waits for a classified result.
  3. At completion or timeout, it records exactly one terminal observation.
  4. The aggregation process sums the window’s eligible and good counts.
  5. The evaluator calculates the ratio, allowance and remaining budget.

A late response must not create a second observation after a timeout. For this design, an edge-local completion guard lets only the first terminal event record the request.

The calculation is compact enough to inspect directly:

json
{
  "contract_version": 1,
  "window_days": 30,
  "target_good_fraction": 0.999,
  "eligible_requests": 30000000,
  "good_requests": 29976000,
  "bad_requests": 24000,
  "allowed_bad_requests": 30000,
  "remaining_bad_requests": 6000
}

These are illustrative evaluated values, not a vendor configuration format.

For , a bucket at the exact deadline can count observations within that threshold. An interpolated is unnecessary for this calculation.3

Kartly’s good count must also require an expected outcome. A fast internal error remains bad. Separate latency and success totals cannot tell you how many requests satisfied both conditions.

Measurement failure Misleading result Kartly’s response
One edge instance stops reporting Failures may disappear Show incomplete coverage and investigate collection
Timeout and late reply both record One request becomes two Enforce the single terminal observation
A new region is absent from queries The report omits its customers Compare expected regions with reporting regions
No eligible traffic arrives The ratio is undefined Show “no traffic,” not automatic success

Kartly does not pause checkout because its reporting system fails. It pauses automated release approval and restores measurement coverage.

A percentage without coverage information can encourage the wrong release decision.

A rolling window keeps moving

Kartly’s always covers the previous 30 days. Every evaluation adds recent buckets and removes buckets that have become too old.

This means a budget can recover when old failures leave the window. It can also change when traffic rises or falls.

Diagram not drawn yet: slo-rolling-window-ledger.svg

Two consecutive evaluations show a trailing 30-day window moving forward. An old bucket with failures leaves on the left, a new bucket enters on the right, and both eligible and bad counts are recalculated. Remaining budget equals 0.001 times eligible requests minus bad requests.

A rolling budget is recalculated from the current window. It does not reset at a calendar boundary.

For comparison, a calendar-month window gives a familiar reporting boundary. But an incident near the boundary can disappear from the new month’s report immediately.

Kartly chooses a rolling window for release decisions to avoid that abrupt reset. Calendar reports can still serve business reporting.

A recovered budget does not prove that the underlying bug was fixed. The team tracks corrective work separately from the arithmetic.

Retries introduce another boundary. Kartly counts each eligible HTTP attempt, including retries using the same .

One failed attempt followed by one successful retry produces a 50% good-event ratio for those attempts. A customer-task measurement might record eventual success instead.

Neither result is mathematically wrong. They answer different questions. Kartly retains the attempt-based API objective and avoids calling it a unique-customer success rate.

The remaining question is what the team does when failures consume the allowance quickly.

Turn consumption into engineering action

Kartly agrees on a written policy before the next incident. An error-budget policy connects measured performance to explicit actions and ownership.1

For this scenario:

Condition Action Owner
Budget remains and recent behavior is stable Continue ordinary releases with existing safeguards Service owner
Failure rate rises sharply Investigate and pause rollout expansion On-call engineer
Budget reaches zero or below Pause discretionary feature releases; prioritize reliability work Service owner and product lead
A recovery or urgent security change is needed Permit it with explicit risk review Incident lead
Measurements are incomplete Hold automated approvals; restore trustworthy reporting Observability owner

A freeze that blocks the repair would defeat its purpose.

Consider the window with 6,000 bad requests remaining. An incident adds 15,000 bad requests. Assume other window counts stay unchanged except for those incident requests.

The budget becomes negative, even after accounting for the small allowance added by those new requests. Kartly has breached its target.

The team should not wait for that point to notice trouble.

compares the observed bad-event fraction with the fraction allowed by the target. A value above one means failures are occurring faster than the target permits proportionally.2

For this lesson’s target, an observed bad-event fraction of 2% gives a burn rate of 20.

That number does not predict an exact exhaustion time. Request volume changes, and old observations leave the rolling window.

It does tell you that the recent failure fraction is far above the sustainable fraction. Alerting: signals worth paging for develops the windows and thresholds needed to act on that signal.

Where this shows up

Kartly now has a reliability target; next it needs alerts that warn about threatened budgets without paging for every fluctuation.

Common mistakes

  • Choosing the percentage first. Define eligible and good events before discussing how many failures are acceptable.
  • Treating the budget as permission to ignore customers. Concentrated harm can demand action even when the overall target is met.
  • Changing exclusions after an incident. Version the contract prospectively instead of making the failed requests disappear.
  • Reporting only the aggregate. Inspect important regions and client versions, using the same definitions, to find concentrated failures.
  • Treating an SLO as a correctness guarantee. A high good-event ratio does not prove that orders or charges are correct.

These mistakes usually produce reassuring numbers rather than useful decisions.

Check your understanding

Check yourselfAnswer in your head first, then reveal
Kartly records an eligible checkout timeout. The payment dependency caused it. Should the request leave the denominator?Show answerHide answer
No. The customer experienced a checkout failure regardless of which dependency caused it. Removing it would make the objective measure ownership rather than the promised API outcome.
Check yourselfAnswer in your head first, then reveal
A window contains two million eligible requests. The target is 99.9%, and 1,500 requests are bad. How much budget remains?Show answerHide answer
The allowance is 2,000 bad requests, leaving 500. Not 2,000: the observed failures have already consumed part of the allowance.
Check yourselfAnswer in your head first, then reveal
An edge instance stops reporting during an incident. The measured good-event ratio improves. Can Kartly resume automated releases?Show answerHide answer
Not from that percentage alone. Missing observations may have removed failures, so Kartly must restore coverage before using the report for automated approval.
Check yourselfAnswer in your head first, then reveal
Old failures leave the rolling window and the budget becomes positive. Does that prove the incident’s cause has been repaired?Show answerHide answer
No. The arithmetic changed because the window moved. The team still needs evidence that corrective work addressed the cause.

Summary

  1. Turn customer expectations into an explicit good-event ratio, a target, a window and an agreed action policy.
  2. Define eligibility, expected outcomes, deadlines and measurement coverage before choosing the percentage.
  3. Error budget equals the allowed bad fraction times eligible events; subtract observed bad events to find the remaining margin.
  4. Request-based budgets are not downtime allowances. Aggregate counts before dividing, and recalculate rolling windows as they move.
  5. Use budget consumption to control release risk, without blocking recovery work or ignoring correctness failures.

Report a mistake

Tell us what’s wrong in this lesson and we’ll fix it.