Skip to content

    System Design

    Availability, Reliability, Durability and SLOs: Three Promises, Measured

    Tell availability, reliability and durability apart, compute downtime and error budgets, and turn each promise into an SLI, an SLO and an alert you can defend.

    By Published 14 min read

    Share

    Standard lessonbeginnerBackend System Design

    Before this: Latency vs Throughput

    What you'll learn: By the end of this lesson you will be able to say precisely how availability, reliability and durability differ and show a failure that breaks only one of them, compute availability from time or from requests, multiply availabilities along a request path and see when redundancy does and does not help, explain what a durable commit waits for, and turn a requirement into an SLI, an SLO, an error budget and a burn-rate alert, keeping an SLA looser than both.

    A bank branch makes three separate promises. The doors are open when you arrive (availability). The teller reads your balance correctly every time (reliability). Your money is still in the vault next year, even after a fire in the branch (durability). A branch can fail one and keep the others: open with a teller who miscounts, closed for a holiday with the vault intact, or open and friendly while the vault's records quietly burn.

    Software makes the same three promises, and teams mix them up, which leads to the wrong fix. The requirements and ShopStream brief lessons give the first definitions. This lesson goes deeper: how each promise is measured, what limits it, and how a target becomes an alert.

    Verified with PostgreSQL 18 documentation, the Google SRE book and workbook, the AWS Well-Architected reliability pillar, the Amazon S3 user guide and SLA, and the Azure Well-Architected reliability pillar, read on 2026-11-08.

    The core idea

    Availability asks "can I use it now?", reliability asks "does it do the right thing, consistently?", and durability asks "will what I saved still be there later?" They fail separately, are measured separately and cost different things to fix. A target for each is written as an SLO, and a contract built on top of it is an SLA.

    Three illustrations run through the lesson: a minimal example (downtime and error-budget arithmetic by hand), a realistic example (ShopStream's checkout path, capped by its hard dependencies) and a failure example (a mistaken delete that replication copies to every replica).

    Three promises, three kinds of failure

    Promise Question Fails when Typical fix
    Availability Can users use it now? Servers are down, overloaded or unreachable Redundancy, failover, load shedding
    Reliability Does it behave correctly, consistently? A bug charges a card twice Testing, safe deploys, fast recovery
    Durability Does saved data survive? A zone is lost, a write was acknowledged before it was flushed, the wrong rows are deleted Replication, flush before acknowledging, backups

    The Azure Well-Architected reliability pillar says a reliable workload must "continue to consistently provide its intended functionality", and also be resilient, recoverable and available. Availability is one part of that picture. Durability is the data side of it and gets its own number, because restarting a server cannot bring back lost data.

    flowchart TD accTitle: Which promise broke accDescr: A decision flow. If users cannot get any response, availability broke. If they get a response that is wrong, reliability broke. If data they saved earlier is missing or changed, durability broke. S["Something is wrong"] --> Q1{"Do requests get a response?"} Q1 -->|"no, or errors"| A["Availability: restore service"] Q1 -->|"yes"| Q2{"Is the answer right?"} Q2 -->|"no"| R["Reliability: fix behaviour, roll back"] Q2 -->|"yes"| Q3{"Is earlier saved data intact?"} Q3 -->|"no"| D["Durability: restore from replica or backup"] Q3 -->|"yes"| OK["Look at latency or capacity instead"]

    Figure 1. Triage by promise. How to read this: ask the three questions in order. The first "no" tells you which recovery path to start; restarting a server restores availability and does nothing for a lost table.

    Availability: from time to requests

    The AWS reliability pillar defines availability as the percentage of time a workload is available for use: available time divided by total time over a stated period. Its table of design goals gives the yearly allowance: 99.9% is 8 hours 45 minutes, 99.99% is 52 minutes, 99.999% is 5 minutes.

    Minimal example. A 30-day month has 30 x 24 x 60 = 43,200 minutes. A 99.9% target allows 0.1% of that, 43.2 minutes of full outage. A target is a budget you spend.

    Time-based availability breaks down for a system that is partly up almost all the time. The Google SRE book notes that for globally distributed services "a time-based metric for availability is usually not meaningful" and defines availability as the request success rate: successful requests over total requests in a window. The AWS pillar gives the same request-based form, measured over one-minute or five-minute periods, and counts a period with no requests as 100% available, so quiet windows can flatter a number.

    Dependencies multiply, redundancy divides

    The AWS pillar says that when a system has hard dependencies, where a failure of the dependency directly becomes a failure of the caller, its availability is the product of theirs: three components at 99.99% give about 99.97%. For independent redundant components it is 100% minus the product of the failure rates: two components at 99.9% give 99.9999%. The word "independent" carries the weight. Two copies that run the same release or share one misconfigured setting fail together, and the formula overstates what you get. Azure's reliability guidance lists release processes, bugs and routine operations among the factors that limit an availability target.

    ShopStream checkout path: three hard dependencies in seriesShopper to App tier (checkout); App tier to Database (order); App tier to Payments (charge)ALL THREE MUST WORK: ABOUT 99.7%ShopperShopperApp tier: assume 99.9%App tierassume 99.9%Database: assume 99.9%Databaseassume 99.9%Payments: assume 99.9%Paymentsassume 99.9%checkoutordercharge

    Figure 2. Series dependencies set a ceiling. How to read this: the zone is the chain 0.999 x 0.999 x 0.999 = 0.997003. Every box is needed for a checkout to succeed, so the chain can never beat its weakest link and in fact does worse than any single box. The payment provider is the one dependency ShopStream does not operate.

    Reliability: correct, and quick to recover

    Reliability adds correctness over time. A system can answer every request and still be unreliable if some answers are wrong, such as a double charge. Two classic quantities link failure to availability: the mean time between failures (MTBF) and the mean time to recover (MTTR). The AWS pillar estimates availability as MTBF / (MTBF + MTTR) and gives a worked case: an MTBF of 150 days and an MTTR of one hour gives about 99.97%.

    Recovery speed matters as much as failure rate: halving MTTR in that example gives 99.986%, the same as failing half as often.

    Durability: what "saved" means

    The SRE book describes durability as the likelihood that data will be retained over a long period of time. It is about data surviving, not about the service being up. A database can be down for an hour and lose nothing, or be up all day while losing writes, which is worse.

    Durability has layers, and a commit's acknowledgement is only as strong as the layer it waited for. PostgreSQL's documentation says committed data should be in a nonvolatile area safe from power loss, operating system failure and hardware failure, and warns that write-back disk caches are volatile and lose their contents in a power failure (many solid-state drives have them). PostgreSQL asks the operating system to force writes to disk, but the manual says the administrator must make sure the storage honours that.

    Replication adds a second layer. With synchronous_commit at its default of on and a synchronous standby configured, a commit waits until the standby has received the commit record and flushed it to durable storage, so the transaction is lost only if the primary and every synchronous standby lose their storage. With off, success is reported before the flush; the manual puts the maximum delay at three times wal_writer_delay and says a crash may lose recent "committed" transactions without corrupting the database. Turning fsync off is different: it can cause unrecoverable corruption after a crash.

    sequenceDiagram accTitle: What a durable commit waits for accDescr: A client commits a transaction. The primary writes and flushes its log, sends it to a synchronous standby, and the standby flushes it and replies. Only then does the primary acknowledge the client. With synchronous_commit off the primary acknowledges before the flush. participant C as Client participant P as Primary participant S as Standby C->>P: COMMIT alt synchronous_commit = on, one synchronous standby P->>P: flush log to durable storage P->>S: send commit record S->>S: flush to durable storage S-->>P: received and flushed P-->>C: success else synchronous_commit = off P-->>C: success, flush happens later end

    Figure 3. Each acknowledgement is a promise. How to read this: the later the success arrives, the more failures the data survives, and the longer the client waits. The first branch pays a standby round trip for each commit; the second pays nothing and accepts a short window of possible loss.

    Durability targets are design goals

    Amazon S3's user guide says S3 Standard stores objects redundantly across multiple devices in at least three Availability Zones and is "designed to provide 99.999999999% durability and 99.99% availability of objects over a given year". Read that as a design goal, not a guarantee. Eleven nines is a yearly loss probability of 10^-11 per object; for 10,000,000 objects the expected loss is 0.0001 objects a year, about one in 10,000 years (the author's arithmetic, not a figure from the page).

    Failure example. A maintenance script runs a DELETE with the wrong condition. The change reaches the primary's log, the standby replays it, and both copies agree the rows are gone: redundancy, and even synchronous commit, made the mistake durable. Eleven nines of device durability do not help either. Recovery needs history: PostgreSQL's continuous archiving can restore a database to its state at any time since a base backup (the manual's example is recovering to just before a table was dropped), and the S3 page names versioning as protection from "unintended user actions and application failures". Durability needs redundancy against hardware loss and history against human error.

    SLIs, SLOs and SLAs

    The SRE book's terms are worth using exactly:

    • An SLI is a carefully defined quantitative measure of some aspect of the service, for example the fraction of well-formed requests that succeed.
    • An SLO is a target value or range for an SLI.
    • An SLA is a contract with users that includes consequences of meeting or missing the SLOs. The book's test: if there is no explicit consequence, you are almost certainly looking at an SLO.

    Its advice on targets: do not pick one from current performance, which can lock you into heroics; keep SLIs simple and SLOs few; start loose and tighten; and keep an internal SLO tighter than the one you advertise.

    The error budget is the unreliability the SLO permits. For 99.9% over 30 days it is 43.2 minutes, or in requests, 0.1% of valid requests.

    Burn rate and alerts

    Alerting on "error rate above the SLO for ten minutes" is noisy: the SRE workbook shows a 0.1% error rate for 10 minutes would alert while consuming only 0.02% of the monthly budget. It prefers burn rate, how fast the service consumes the budget relative to the SLO: a constant 0.1% error rate against a 99.9% SLO over 30 days uses exactly all the budget, a burn rate of 1. For a 99.9% SLO it recommends pages at burn rate 14.4 over one hour (2% of budget, with a 5-minute short window), and 6 over six hours (5%), and a ticket at burn rate 1 over three days (10%).

    flowchart LR accTitle: From a user journey to an alert accDescr: A critical user journey gets an SLI, which is compared with an SLO target over a window. The remaining error budget and its burn rate drive alerts and release decisions. A looser SLA sits on top. J["User journey
    checkout"] --> I["SLI
    good checkouts / valid checkouts"] I --> O["SLO
    99.9% over 30 days"] O --> B["Error budget
    0.1%, and its burn rate"] B --> AL["Alerts and release decisions"] O -.->|"set looser, with consequences"| SLA["SLA
    the contract"]

    Figure 4. A promise is a chain, not a number. How to read this: each box depends on the one before. An SLO without an SLI cannot be measured, and a target with no budget behind it changes no decision.

    Providers keep a gap between goal and contract. S3's user guide states a design goal of 99.99% availability, while the S3 SLA gives service credits only when monthly uptime falls below 99.9% (10% for S3 Standard down to 99.0%). Azure's guidance says SLOs and SLAs should be controlled independently.

    Trade-offs

    Choice Gain Cost Wrong when
    Synchronous standby (synchronous_commit = on) Acknowledged writes survive loss of the primary A round trip on each commit; commits may wait if the standby is down Latency budget is tight and the data is low value
    Tighter SLO (more nines) Fewer user-visible failures More cost, testing and slower change (AWS) The user cost of downtime is small

    Google's SRE book says 100% is probably never the right reliability target and that cost is often the key factor; AWS also says higher goals cost more, so identify the real need first.

    In practice: ShopStream sets a checkout availability target

    This is the realistic example. It is an educational scenario on the course's running example, ShopStream, and nothing in it describes a real company. Availabilities are illustrative; the order volume (500,000 orders a day) is the course's shared target.

    This is a realistic scenario, not a case history.

    The situation

    ShopStream's checkout path crosses the application tier, the database and an external payment provider. At 500,000 orders a day, a 30-day month holds 15,000,000 checkouts. The business asks for 99.9%: an error budget of 15,000 failed checkouts a month. Can the architecture meet it?

    Starting architecture

    Figure 2 is the starting point: each of the three is assumed 99.9% and is a hard dependency. The product is 0.997003, about 99.7%, an error budget of about 45,000 failed checkouts a month, three times what the business wants (the budget would be gone in ten days).

    Options considered

    Option Chain after the change Cost Risk
    A. Redundant app servers and a database standby App tier and database each about 1 - 0.001^2 = 99.9999% in theory, so 0.999999 x 0.999999 x 0.999 = about 99.8998% Two copies, failover, a standby Assumes independent failures; failover time and a bad release still count
    B. Option A, and make the payment step a soft dependency Checkout accepts the order as "payment pending" if the provider is slow, and settles when it recovers Order states, a retry job, support copy Customers wait for confirmation; needs idempotent charges
    C. Launch SLO of 99.5% The 99.7% ceiling leaves margin None More visible failures than the business hoped

    The decision

    Option A is not enough: it fixes two links, and the payment provider is left as nearly all the remaining error, so the ceiling is still just under 99.9% before any bug or bad deploy. The team chooses B, with C as the launch SLO, tightening once measurements exist. No SLA is offered until the numbers are measured. The SLI is the share of checkout requests that return success or an explicit "payment pending", over 30 days. Settlement and retries belong to Stage 5 and Stage 6.

    Rollout and verification

    Start with the SLI on dashboards and no alert, and compare two weeks of real data with the assumed 99.9% figures. Then add burn-rate alerts: a page at a burn rate of 14.4 over one hour (5-minute short window) and a ticket at 1 over three days. Those are the SRE workbook's example parameters for a 99.9% SLO; reusing the same fractions of budget for the launch SLO is a starting point to tune. Verify the redundancy by stopping one application server and one database primary in staging and watching the SLI; any dip is evidence against the independence assumption.

    The 2 a.m. failure

    The page reads: checkout success dropped to 92% for an hour (illustrative), a burn rate of 16 against the 0.5% budget, so the 14.4 alert fired. The standby and both app servers are healthy, but a release an hour earlier changed how prices are rounded, and every server computes the wrong total on a coupon path. The service is available but unreliable. Checks: deploy markers against the SLI curve, the error type, a sample of failing orders. Mitigation: roll back. Lasting fix: a canary release that watches the SLI before full rollout, and a test for the coupon path. A second app server did not help because both ran the same code, which is the independence caveat in practice.

    Architect's notes

    • Set targets per promise and per critical user journey, not one number for "the site".
    • Multiply before you promise. List every hard dependency on the path and multiply.
    • Turn hard dependencies into soft ones where the product allows: queue the work, show a pending state.
    • Treat durability as two questions: what survives hardware or zone loss, and what survives a mistaken change.
    • Test recovery, not just backups. Azure says flows not tested for recovery should not carry guaranteed SLAs.
    • Keep SLO, SLA and design goal different. Advertise less than you aim for.

    Common mistakes

    • Using "uptime" for everything. A server that answers wrongly is up but unreliable.
    • Counting redundancy as independence. Copies that share a release, a config or a network fail together.
    • Equating replication with backup. Replication copies a mistaken delete to every replica.
    • Acknowledging before flushing data that must not be lost.

    Key takeaways

    • Availability is "can I use it", reliability is "is it right and quick to recover", durability is "is my data still there".
    • Request-based availability tracks users better than time-based, and low-traffic windows need care.
    • Hard dependencies multiply availability; independent redundancy divides unavailability, but only where failures are really independent.
    • A durable commit waits for a flush on the primary and, with synchronous replication, on a standby; each wait costs latency.
    • Durability figures such as eleven nines are design goals and do not cover deletion by mistake: that needs versioning or backups.
    • An SLI measures, an SLO targets, an SLA is a contract with consequences; the error budget and its burn rate turn the target into alerts and release decisions.

    Practice exercises

    Exercise 1 (20 min). For a 99.95% target compute the allowed downtime over a 30-day month and over a year, then the error budget in requests at 1,000,000 requests a day.

    Exercise 2 (30 min). ShopStream's chain gets a search service (99.9%) as a hard dependency. Recompute the series availability, then decide whether search can become a soft dependency and what the user sees when it fails.

    Exercise 3 (45 min). For a 99.9% SLO over 30 days, compute the error rate that gives a burn rate of 14.4, how long until it spends 2% of the budget, and how long until it spends all of it.

    Exercise 4 (45 min). Write three SLIs for a store tablet that shows new orders (availability, latency, and durability or correctness) as ratios of good to valid events, with a window and a proposed SLO each.

    Official documentation

    Ask about this article

    Get answers grounded in this post. AI-generated — based on this article, and may be imperfect.

    Scaled AI Weekly

    Enjoyed this? Get more like it every Monday.

    Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.

    Get new articles by email

    Free. We email a confirmation link first, and you can unsubscribe from any email.

    Join engineers building production AI systems

    Comments